mirror of
https://github.com/hanzoai/agency.git
synced 2026-11-02 19:13:28 +00:00
488 lines
18 KiB
Plaintext
488 lines
18 KiB
Plaintext
"use strict";
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
|
|
// src/queryObserver.ts
|
|
var queryObserver_exports = {};
|
|
__export(queryObserver_exports, {
|
|
QueryObserver: () => QueryObserver
|
|
});
|
|
module.exports = __toCommonJS(queryObserver_exports);
|
|
var import_focusManager = require("./focusManager.cjs");
|
|
var import_notifyManager = require("./notifyManager.cjs");
|
|
var import_query = require("./query.cjs");
|
|
var import_subscribable = require("./subscribable.cjs");
|
|
var import_thenable = require("./thenable.cjs");
|
|
var import_utils = require("./utils.cjs");
|
|
var import_timeoutManager = require("./timeoutManager.cjs");
|
|
var QueryObserver = class extends import_subscribable.Subscribable {
|
|
constructor(client, options) {
|
|
super();
|
|
this.options = options;
|
|
this.#client = client;
|
|
this.#selectError = null;
|
|
this.#currentThenable = (0, import_thenable.pendingThenable)();
|
|
this.bindMethods();
|
|
this.setOptions(options);
|
|
}
|
|
#client;
|
|
#currentQuery = void 0;
|
|
#currentQueryInitialState = void 0;
|
|
#currentResult = void 0;
|
|
#currentResultState;
|
|
#currentResultOptions;
|
|
#currentThenable;
|
|
#selectError;
|
|
#selectFn;
|
|
#selectResult;
|
|
// This property keeps track of the last query with defined data.
|
|
// It will be used to pass the previous data and query to the placeholder function between renders.
|
|
#lastQueryWithDefinedData;
|
|
#staleTimeoutId;
|
|
#refetchIntervalId;
|
|
#currentRefetchInterval;
|
|
#trackedProps = /* @__PURE__ */ new Set();
|
|
bindMethods() {
|
|
this.refetch = this.refetch.bind(this);
|
|
}
|
|
onSubscribe() {
|
|
if (this.listeners.size === 1) {
|
|
this.#currentQuery.addObserver(this);
|
|
if (shouldFetchOnMount(this.#currentQuery, this.options)) {
|
|
this.#executeFetch();
|
|
} else {
|
|
this.updateResult();
|
|
}
|
|
this.#updateTimers();
|
|
}
|
|
}
|
|
onUnsubscribe() {
|
|
if (!this.hasListeners()) {
|
|
this.destroy();
|
|
}
|
|
}
|
|
shouldFetchOnReconnect() {
|
|
return shouldFetchOn(
|
|
this.#currentQuery,
|
|
this.options,
|
|
this.options.refetchOnReconnect
|
|
);
|
|
}
|
|
shouldFetchOnWindowFocus() {
|
|
return shouldFetchOn(
|
|
this.#currentQuery,
|
|
this.options,
|
|
this.options.refetchOnWindowFocus
|
|
);
|
|
}
|
|
destroy() {
|
|
this.listeners = /* @__PURE__ */ new Set();
|
|
this.#clearStaleTimeout();
|
|
this.#clearRefetchInterval();
|
|
this.#currentQuery.removeObserver(this);
|
|
}
|
|
setOptions(options) {
|
|
const prevOptions = this.options;
|
|
const prevQuery = this.#currentQuery;
|
|
this.options = this.#client.defaultQueryOptions(options);
|
|
if (this.options.enabled !== void 0 && typeof this.options.enabled !== "boolean" && typeof this.options.enabled !== "function" && typeof (0, import_utils.resolveEnabled)(this.options.enabled, this.#currentQuery) !== "boolean") {
|
|
throw new Error(
|
|
"Expected enabled to be a boolean or a callback that returns a boolean"
|
|
);
|
|
}
|
|
this.#updateQuery();
|
|
this.#currentQuery.setOptions(this.options);
|
|
if (prevOptions._defaulted && !(0, import_utils.shallowEqualObjects)(this.options, prevOptions)) {
|
|
this.#client.getQueryCache().notify({
|
|
type: "observerOptionsUpdated",
|
|
query: this.#currentQuery,
|
|
observer: this
|
|
});
|
|
}
|
|
const mounted = this.hasListeners();
|
|
if (mounted && shouldFetchOptionally(
|
|
this.#currentQuery,
|
|
prevQuery,
|
|
this.options,
|
|
prevOptions
|
|
)) {
|
|
this.#executeFetch();
|
|
}
|
|
this.updateResult();
|
|
if (mounted && (this.#currentQuery !== prevQuery || (0, import_utils.resolveEnabled)(this.options.enabled, this.#currentQuery) !== (0, import_utils.resolveEnabled)(prevOptions.enabled, this.#currentQuery) || (0, import_utils.resolveStaleTime)(this.options.staleTime, this.#currentQuery) !== (0, import_utils.resolveStaleTime)(prevOptions.staleTime, this.#currentQuery))) {
|
|
this.#updateStaleTimeout();
|
|
}
|
|
const nextRefetchInterval = this.#computeRefetchInterval();
|
|
if (mounted && (this.#currentQuery !== prevQuery || (0, import_utils.resolveEnabled)(this.options.enabled, this.#currentQuery) !== (0, import_utils.resolveEnabled)(prevOptions.enabled, this.#currentQuery) || nextRefetchInterval !== this.#currentRefetchInterval)) {
|
|
this.#updateRefetchInterval(nextRefetchInterval);
|
|
}
|
|
}
|
|
getOptimisticResult(options) {
|
|
const query = this.#client.getQueryCache().build(this.#client, options);
|
|
const result = this.createResult(query, options);
|
|
if (shouldAssignObserverCurrentProperties(this, result)) {
|
|
this.#currentResult = result;
|
|
this.#currentResultOptions = this.options;
|
|
this.#currentResultState = this.#currentQuery.state;
|
|
}
|
|
return result;
|
|
}
|
|
getCurrentResult() {
|
|
return this.#currentResult;
|
|
}
|
|
trackResult(result, onPropTracked) {
|
|
return new Proxy(result, {
|
|
get: (target, key) => {
|
|
this.trackProp(key);
|
|
onPropTracked?.(key);
|
|
if (key === "promise") {
|
|
this.trackProp("data");
|
|
if (!this.options.experimental_prefetchInRender && this.#currentThenable.status === "pending") {
|
|
this.#currentThenable.reject(
|
|
new Error(
|
|
"experimental_prefetchInRender feature flag is not enabled"
|
|
)
|
|
);
|
|
}
|
|
}
|
|
return Reflect.get(target, key);
|
|
}
|
|
});
|
|
}
|
|
trackProp(key) {
|
|
this.#trackedProps.add(key);
|
|
}
|
|
getCurrentQuery() {
|
|
return this.#currentQuery;
|
|
}
|
|
refetch({ ...options } = {}) {
|
|
return this.fetch({
|
|
...options
|
|
});
|
|
}
|
|
fetchOptimistic(options) {
|
|
const defaultedOptions = this.#client.defaultQueryOptions(options);
|
|
const query = this.#client.getQueryCache().build(this.#client, defaultedOptions);
|
|
return query.fetch().then(() => this.createResult(query, defaultedOptions));
|
|
}
|
|
fetch(fetchOptions) {
|
|
return this.#executeFetch({
|
|
...fetchOptions,
|
|
cancelRefetch: fetchOptions.cancelRefetch ?? true
|
|
}).then(() => {
|
|
this.updateResult();
|
|
return this.#currentResult;
|
|
});
|
|
}
|
|
#executeFetch(fetchOptions) {
|
|
this.#updateQuery();
|
|
let promise = this.#currentQuery.fetch(
|
|
this.options,
|
|
fetchOptions
|
|
);
|
|
if (!fetchOptions?.throwOnError) {
|
|
promise = promise.catch(import_utils.noop);
|
|
}
|
|
return promise;
|
|
}
|
|
#updateStaleTimeout() {
|
|
this.#clearStaleTimeout();
|
|
const staleTime = (0, import_utils.resolveStaleTime)(
|
|
this.options.staleTime,
|
|
this.#currentQuery
|
|
);
|
|
if (import_utils.isServer || this.#currentResult.isStale || !(0, import_utils.isValidTimeout)(staleTime)) {
|
|
return;
|
|
}
|
|
const time = (0, import_utils.timeUntilStale)(this.#currentResult.dataUpdatedAt, staleTime);
|
|
const timeout = time + 1;
|
|
this.#staleTimeoutId = import_timeoutManager.timeoutManager.setTimeout(() => {
|
|
if (!this.#currentResult.isStale) {
|
|
this.updateResult();
|
|
}
|
|
}, timeout);
|
|
}
|
|
#computeRefetchInterval() {
|
|
return (typeof this.options.refetchInterval === "function" ? this.options.refetchInterval(this.#currentQuery) : this.options.refetchInterval) ?? false;
|
|
}
|
|
#updateRefetchInterval(nextInterval) {
|
|
this.#clearRefetchInterval();
|
|
this.#currentRefetchInterval = nextInterval;
|
|
if (import_utils.isServer || (0, import_utils.resolveEnabled)(this.options.enabled, this.#currentQuery) === false || !(0, import_utils.isValidTimeout)(this.#currentRefetchInterval) || this.#currentRefetchInterval === 0) {
|
|
return;
|
|
}
|
|
this.#refetchIntervalId = import_timeoutManager.timeoutManager.setInterval(() => {
|
|
if (this.options.refetchIntervalInBackground || import_focusManager.focusManager.isFocused()) {
|
|
this.#executeFetch();
|
|
}
|
|
}, this.#currentRefetchInterval);
|
|
}
|
|
#updateTimers() {
|
|
this.#updateStaleTimeout();
|
|
this.#updateRefetchInterval(this.#computeRefetchInterval());
|
|
}
|
|
#clearStaleTimeout() {
|
|
if (this.#staleTimeoutId) {
|
|
import_timeoutManager.timeoutManager.clearTimeout(this.#staleTimeoutId);
|
|
this.#staleTimeoutId = void 0;
|
|
}
|
|
}
|
|
#clearRefetchInterval() {
|
|
if (this.#refetchIntervalId) {
|
|
import_timeoutManager.timeoutManager.clearInterval(this.#refetchIntervalId);
|
|
this.#refetchIntervalId = void 0;
|
|
}
|
|
}
|
|
createResult(query, options) {
|
|
const prevQuery = this.#currentQuery;
|
|
const prevOptions = this.options;
|
|
const prevResult = this.#currentResult;
|
|
const prevResultState = this.#currentResultState;
|
|
const prevResultOptions = this.#currentResultOptions;
|
|
const queryChange = query !== prevQuery;
|
|
const queryInitialState = queryChange ? query.state : this.#currentQueryInitialState;
|
|
const { state } = query;
|
|
let newState = { ...state };
|
|
let isPlaceholderData = false;
|
|
let data;
|
|
if (options._optimisticResults) {
|
|
const mounted = this.hasListeners();
|
|
const fetchOnMount = !mounted && shouldFetchOnMount(query, options);
|
|
const fetchOptionally = mounted && shouldFetchOptionally(query, prevQuery, options, prevOptions);
|
|
if (fetchOnMount || fetchOptionally) {
|
|
newState = {
|
|
...newState,
|
|
...(0, import_query.fetchState)(state.data, query.options)
|
|
};
|
|
}
|
|
if (options._optimisticResults === "isRestoring") {
|
|
newState.fetchStatus = "idle";
|
|
}
|
|
}
|
|
let { error, errorUpdatedAt, status } = newState;
|
|
data = newState.data;
|
|
let skipSelect = false;
|
|
if (options.placeholderData !== void 0 && data === void 0 && status === "pending") {
|
|
let placeholderData;
|
|
if (prevResult?.isPlaceholderData && options.placeholderData === prevResultOptions?.placeholderData) {
|
|
placeholderData = prevResult.data;
|
|
skipSelect = true;
|
|
} else {
|
|
placeholderData = typeof options.placeholderData === "function" ? options.placeholderData(
|
|
this.#lastQueryWithDefinedData?.state.data,
|
|
this.#lastQueryWithDefinedData
|
|
) : options.placeholderData;
|
|
}
|
|
if (placeholderData !== void 0) {
|
|
status = "success";
|
|
data = (0, import_utils.replaceData)(
|
|
prevResult?.data,
|
|
placeholderData,
|
|
options
|
|
);
|
|
isPlaceholderData = true;
|
|
}
|
|
}
|
|
if (options.select && data !== void 0 && !skipSelect) {
|
|
if (prevResult && data === prevResultState?.data && options.select === this.#selectFn) {
|
|
data = this.#selectResult;
|
|
} else {
|
|
try {
|
|
this.#selectFn = options.select;
|
|
data = options.select(data);
|
|
data = (0, import_utils.replaceData)(prevResult?.data, data, options);
|
|
this.#selectResult = data;
|
|
this.#selectError = null;
|
|
} catch (selectError) {
|
|
this.#selectError = selectError;
|
|
}
|
|
}
|
|
}
|
|
if (this.#selectError) {
|
|
error = this.#selectError;
|
|
data = this.#selectResult;
|
|
errorUpdatedAt = Date.now();
|
|
status = "error";
|
|
}
|
|
const isFetching = newState.fetchStatus === "fetching";
|
|
const isPending = status === "pending";
|
|
const isError = status === "error";
|
|
const isLoading = isPending && isFetching;
|
|
const hasData = data !== void 0;
|
|
const result = {
|
|
status,
|
|
fetchStatus: newState.fetchStatus,
|
|
isPending,
|
|
isSuccess: status === "success",
|
|
isError,
|
|
isInitialLoading: isLoading,
|
|
isLoading,
|
|
data,
|
|
dataUpdatedAt: newState.dataUpdatedAt,
|
|
error,
|
|
errorUpdatedAt,
|
|
failureCount: newState.fetchFailureCount,
|
|
failureReason: newState.fetchFailureReason,
|
|
errorUpdateCount: newState.errorUpdateCount,
|
|
isFetched: newState.dataUpdateCount > 0 || newState.errorUpdateCount > 0,
|
|
isFetchedAfterMount: newState.dataUpdateCount > queryInitialState.dataUpdateCount || newState.errorUpdateCount > queryInitialState.errorUpdateCount,
|
|
isFetching,
|
|
isRefetching: isFetching && !isPending,
|
|
isLoadingError: isError && !hasData,
|
|
isPaused: newState.fetchStatus === "paused",
|
|
isPlaceholderData,
|
|
isRefetchError: isError && hasData,
|
|
isStale: isStale(query, options),
|
|
refetch: this.refetch,
|
|
promise: this.#currentThenable,
|
|
isEnabled: (0, import_utils.resolveEnabled)(options.enabled, query) !== false
|
|
};
|
|
const nextResult = result;
|
|
if (this.options.experimental_prefetchInRender) {
|
|
const hasResultData = nextResult.data !== void 0;
|
|
const isErrorWithoutData = nextResult.status === "error" && !hasResultData;
|
|
const finalizeThenableIfPossible = (thenable) => {
|
|
if (isErrorWithoutData) {
|
|
thenable.reject(nextResult.error);
|
|
} else if (hasResultData) {
|
|
thenable.resolve(nextResult.data);
|
|
}
|
|
};
|
|
const recreateThenable = () => {
|
|
const pending = this.#currentThenable = nextResult.promise = (0, import_thenable.pendingThenable)();
|
|
finalizeThenableIfPossible(pending);
|
|
};
|
|
const prevThenable = this.#currentThenable;
|
|
switch (prevThenable.status) {
|
|
case "pending":
|
|
if (query.queryHash === prevQuery.queryHash) {
|
|
finalizeThenableIfPossible(prevThenable);
|
|
}
|
|
break;
|
|
case "fulfilled":
|
|
if (isErrorWithoutData || nextResult.data !== prevThenable.value) {
|
|
recreateThenable();
|
|
}
|
|
break;
|
|
case "rejected":
|
|
if (!isErrorWithoutData || nextResult.error !== prevThenable.reason) {
|
|
recreateThenable();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return nextResult;
|
|
}
|
|
updateResult() {
|
|
const prevResult = this.#currentResult;
|
|
const nextResult = this.createResult(this.#currentQuery, this.options);
|
|
this.#currentResultState = this.#currentQuery.state;
|
|
this.#currentResultOptions = this.options;
|
|
if (this.#currentResultState.data !== void 0) {
|
|
this.#lastQueryWithDefinedData = this.#currentQuery;
|
|
}
|
|
if ((0, import_utils.shallowEqualObjects)(nextResult, prevResult)) {
|
|
return;
|
|
}
|
|
this.#currentResult = nextResult;
|
|
const shouldNotifyListeners = () => {
|
|
if (!prevResult) {
|
|
return true;
|
|
}
|
|
const { notifyOnChangeProps } = this.options;
|
|
const notifyOnChangePropsValue = typeof notifyOnChangeProps === "function" ? notifyOnChangeProps() : notifyOnChangeProps;
|
|
if (notifyOnChangePropsValue === "all" || !notifyOnChangePropsValue && !this.#trackedProps.size) {
|
|
return true;
|
|
}
|
|
const includedProps = new Set(
|
|
notifyOnChangePropsValue ?? this.#trackedProps
|
|
);
|
|
if (this.options.throwOnError) {
|
|
includedProps.add("error");
|
|
}
|
|
return Object.keys(this.#currentResult).some((key) => {
|
|
const typedKey = key;
|
|
const changed = this.#currentResult[typedKey] !== prevResult[typedKey];
|
|
return changed && includedProps.has(typedKey);
|
|
});
|
|
};
|
|
this.#notify({ listeners: shouldNotifyListeners() });
|
|
}
|
|
#updateQuery() {
|
|
const query = this.#client.getQueryCache().build(this.#client, this.options);
|
|
if (query === this.#currentQuery) {
|
|
return;
|
|
}
|
|
const prevQuery = this.#currentQuery;
|
|
this.#currentQuery = query;
|
|
this.#currentQueryInitialState = query.state;
|
|
if (this.hasListeners()) {
|
|
prevQuery?.removeObserver(this);
|
|
query.addObserver(this);
|
|
}
|
|
}
|
|
onQueryUpdate() {
|
|
this.updateResult();
|
|
if (this.hasListeners()) {
|
|
this.#updateTimers();
|
|
}
|
|
}
|
|
#notify(notifyOptions) {
|
|
import_notifyManager.notifyManager.batch(() => {
|
|
if (notifyOptions.listeners) {
|
|
this.listeners.forEach((listener) => {
|
|
listener(this.#currentResult);
|
|
});
|
|
}
|
|
this.#client.getQueryCache().notify({
|
|
query: this.#currentQuery,
|
|
type: "observerResultsUpdated"
|
|
});
|
|
});
|
|
}
|
|
};
|
|
function shouldLoadOnMount(query, options) {
|
|
return (0, import_utils.resolveEnabled)(options.enabled, query) !== false && query.state.data === void 0 && !(query.state.status === "error" && options.retryOnMount === false);
|
|
}
|
|
function shouldFetchOnMount(query, options) {
|
|
return shouldLoadOnMount(query, options) || query.state.data !== void 0 && shouldFetchOn(query, options, options.refetchOnMount);
|
|
}
|
|
function shouldFetchOn(query, options, field) {
|
|
if ((0, import_utils.resolveEnabled)(options.enabled, query) !== false && (0, import_utils.resolveStaleTime)(options.staleTime, query) !== "static") {
|
|
const value = typeof field === "function" ? field(query) : field;
|
|
return value === "always" || value !== false && isStale(query, options);
|
|
}
|
|
return false;
|
|
}
|
|
function shouldFetchOptionally(query, prevQuery, options, prevOptions) {
|
|
return (query !== prevQuery || (0, import_utils.resolveEnabled)(prevOptions.enabled, query) === false) && (!options.suspense || query.state.status !== "error") && isStale(query, options);
|
|
}
|
|
function isStale(query, options) {
|
|
return (0, import_utils.resolveEnabled)(options.enabled, query) !== false && query.isStaleByTime((0, import_utils.resolveStaleTime)(options.staleTime, query));
|
|
}
|
|
function shouldAssignObserverCurrentProperties(observer, optimisticResult) {
|
|
if (!(0, import_utils.shallowEqualObjects)(observer.getCurrentResult(), optimisticResult)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
// Annotate the CommonJS export names for ESM import in node:
|
|
0 && (module.exports = {
|
|
QueryObserver
|
|
});
|
|
//# sourceMappingURL=queryObserver.cjs.map |