@ttt-productions/query-core 0.14.14 → 0.14.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription-status.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/subscription-status.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAuC,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEtF,yHAAyH;AACzH,UAAU,cAAc;IACtB,gGAAgG;IAChG,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,oBAAoB,CAAC;IAClC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,mGAAmG;IACnG,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC;AAM9E;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM;;;;;;oBAc1C,WAAW,GAAG,CAAC,CAAC,IAAI,EAAE,kBAAkB,KAAK,WAAW,CAAC;mBAkBnC,OAAO;EAwBxC;AAED,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAQtE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EACvC,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,EACnC,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,qBAAqB,GAC5B,eAAe,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"subscription-status.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/subscription-status.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAuC,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEtF,yHAAyH;AACzH,UAAU,cAAc;IACtB,gGAAgG;IAChG,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,oBAAoB,CAAC;IAClC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,mGAAmG;IACnG,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC;AAM9E;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM;;;;;;oBAc1C,WAAW,GAAG,CAAC,CAAC,IAAI,EAAE,kBAAkB,KAAK,WAAW,CAAC;mBAkBnC,OAAO;EAwBxC;AAED,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAQtE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EACvC,KAAK,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,EACnC,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,qBAAqB,GAC5B,eAAe,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAwG/C"}
|
|
@@ -132,6 +132,18 @@ export function useSubscribedResult(query, subscribe, enabled, status) {
|
|
|
132
132
|
refetch,
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
|
+
else if (active && query.isPending) {
|
|
136
|
+
// The listener has not delivered its first snapshot. The query underneath is disabled in
|
|
137
|
+
// subscribe mode, so it reports pending but not loading; the read IS loading, exactly like a
|
|
138
|
+
// one-shot read's first fetch — never an answered absence.
|
|
139
|
+
result = {
|
|
140
|
+
...query,
|
|
141
|
+
isLoading: true,
|
|
142
|
+
isFetching: true,
|
|
143
|
+
fetchStatus: 'fetching',
|
|
144
|
+
refetch,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
135
147
|
else {
|
|
136
148
|
result = { ...query, refetch };
|
|
137
149
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscription-status.js","sourceRoot":"","sources":["../../../src/react/firestore/subscription-status.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { QueryObserverResult, RefetchOptions, UseQueryResult } from '@tanstack/react-query';\nimport type { FirestoreSourceState, WithSourceState } from '../../firestore/types.js';\n\n/** A restart a subscribed result's `refetch()` asked for, open until the listener's first snapshot or its next error. */\ninterface PendingRestart {\n /** The listener had failed: its last data is not shown as current while the restart is open. */\n fromError: boolean;\n}\n\ninterface SubscriptionStatus {\n identity: string;\n error: Error | null;\n sourceState: FirestoreSourceState;\n restart: PendingRestart | null;\n /** Bumped by every restart; the listener effect depends on it, so a bump re-opens the listener. */\n restarts: number;\n}\n\ntype StatusPatch = Partial<Omit<SubscriptionStatus, 'identity' | 'restarts'>>;\n\nfunction freshStatus(identity: string): SubscriptionStatus {\n return { identity, error: null, sourceState: 'connecting', restart: null, restarts: 0 };\n}\n\n/**\n * A realtime listener's source state and error, tagged to the subscription identity that\n * produced them. A new identity reads `connecting` with no error from its first render;\n * writes made for a retired identity are dropped once the new identity's listener has\n * started (it calls `reset`).\n *\n * `restart()` clears the error and bumps `restarts`; the listener effect re-opens on the bump,\n * and its first snapshot or next surfaced error ends the restart (`settled` in the patch).\n */\nexport function useSubscriptionStatus(identity: string) {\n const [status, setStatus] = useState<SubscriptionStatus>(() => freshStatus(identity));\n\n const current: SubscriptionStatus = status.identity === identity ? status : freshStatus(identity);\n\n const reset = useCallback(() => {\n setStatus((prev) =>\n prev.identity === identity\n ? { ...prev, error: null, sourceState: 'connecting' }\n : freshStatus(identity),\n );\n }, [identity]);\n\n const update = useCallback(\n (patch: StatusPatch | ((prev: SubscriptionStatus) => StatusPatch)) => {\n setStatus((prev) => {\n if (prev.identity !== identity) return prev;\n const next = typeof patch === 'function' ? patch(prev) : patch;\n return { ...prev, ...next };\n });\n },\n [identity],\n );\n\n // The identity the hook renders now. A `restart` captured under an earlier identity must not\n // touch the current one's status, or every write the current listener makes would be dropped.\n const renderedIdentity = useRef(identity);\n useEffect(() => {\n renderedIdentity.current = identity;\n }, [identity]);\n\n /** Re-opens the listener; false (and nothing changes) when this identity is no longer rendered. */\n const restart = useCallback((): boolean => {\n if (renderedIdentity.current !== identity) return false;\n setStatus((prev) => {\n const base = prev.identity === identity ? prev : freshStatus(identity);\n return {\n ...base,\n error: null,\n sourceState: 'connecting',\n restart: { fromError: base.error !== null || base.restart?.fromError === true },\n restarts: base.restarts + 1,\n };\n });\n return true;\n }, [identity]);\n\n return {\n error: current.error,\n sourceState: current.sourceState,\n pendingRestart: current.restart,\n restarts: current.restarts,\n reset,\n update,\n restart,\n };\n}\n\ntype SubscriptionStatusApi = ReturnType<typeof useSubscriptionStatus>;\n\ninterface RefetchWaiter<TData> {\n resolve: (result: QueryObserverResult<TData, Error>) => void;\n reject: (error: Error) => void;\n throwOnError: boolean;\n}\n\n/**\n * The subscribed hooks' result: the query's own result, with the listener's error and source\n * state merged in. In subscribe mode `refetch()` re-opens the listener (clearing its error, with a\n * fresh resubscribe ladder) and resolves once the re-opened listener delivers its first snapshot or\n * surfaces its next error; until then the result reports fetching. A restart after a failure shows\n * no data until that snapshot: the failed listener's last rows are not presented as current.\n */\nexport function useSubscribedResult<TData>(\n query: UseQueryResult<TData, Error>,\n subscribe: boolean,\n enabled: boolean,\n status: SubscriptionStatusApi,\n): WithSourceState<UseQueryResult<TData, Error>> {\n const { error, sourceState, pendingRestart, restart } = status;\n const waiters = useRef<RefetchWaiter<TData>[]>([]);\n const latest = useRef(query as QueryObserverResult<TData, Error>);\n const mounted = useRef(true);\n const active = subscribe && enabled;\n\n const refetch = useCallback(\n (options?: RefetchOptions): Promise<QueryObserverResult<TData, Error>> => {\n // An unmounted hook, or a refetch captured under an identity the hook has left, re-opens\n // nothing: it settles at once rather than waiting on a listener that will never report.\n if (!active || !mounted.current) return Promise.resolve(latest.current);\n return new Promise((resolve, reject) => {\n if (!restart()) {\n resolve(latest.current);\n return;\n }\n waiters.current.push({ resolve, reject, throwOnError: options?.throwOnError === true });\n });\n },\n [active, restart],\n );\n\n let result: UseQueryResult<TData, Error>;\n if (!subscribe) {\n result = query;\n } else if (error) {\n result = {\n ...query,\n data: undefined,\n error,\n isError: true,\n isLoadingError: true,\n isSuccess: false,\n isPending: false,\n isLoading: false,\n status: 'error',\n refetch,\n } as UseQueryResult<TData, Error>;\n } else if (pendingRestart?.fromError) {\n result = {\n ...query,\n data: undefined,\n error: null,\n isError: false,\n isLoadingError: false,\n isRefetchError: false,\n isSuccess: false,\n isPending: true,\n isLoading: true,\n isFetching: true,\n isRefetching: false,\n status: 'pending',\n fetchStatus: 'fetching',\n refetch,\n } as UseQueryResult<TData, Error>;\n } else if (pendingRestart) {\n result = {\n ...query,\n isFetching: true,\n isLoading: query.isPending,\n isRefetching: !query.isPending,\n fetchStatus: 'fetching',\n refetch,\n } as UseQueryResult<TData, Error>;\n } else {\n result = { ...query, refetch } as UseQueryResult<TData, Error>;\n }\n\n const restartOpen = pendingRestart !== null;\n useEffect(() => {\n latest.current = result as QueryObserverResult<TData, Error>;\n if (restartOpen || waiters.current.length === 0) return;\n const settled = waiters.current;\n waiters.current = [];\n for (const waiter of settled) {\n if (waiter.throwOnError && result.error) waiter.reject(result.error);\n else waiter.resolve(result as QueryObserverResult<TData, Error>);\n }\n });\n\n // A refetch still open when the hook unmounts resolves with the last result instead of hanging.\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n const settled = waiters.current;\n waiters.current = [];\n for (const waiter of settled) waiter.resolve(latest.current);\n };\n }, []);\n\n return { ...result, sourceState } as WithSourceState<UseQueryResult<TData, Error>>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"subscription-status.js","sourceRoot":"","sources":["../../../src/react/firestore/subscription-status.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { QueryObserverResult, RefetchOptions, UseQueryResult } from '@tanstack/react-query';\nimport type { FirestoreSourceState, WithSourceState } from '../../firestore/types.js';\n\n/** A restart a subscribed result's `refetch()` asked for, open until the listener's first snapshot or its next error. */\ninterface PendingRestart {\n /** The listener had failed: its last data is not shown as current while the restart is open. */\n fromError: boolean;\n}\n\ninterface SubscriptionStatus {\n identity: string;\n error: Error | null;\n sourceState: FirestoreSourceState;\n restart: PendingRestart | null;\n /** Bumped by every restart; the listener effect depends on it, so a bump re-opens the listener. */\n restarts: number;\n}\n\ntype StatusPatch = Partial<Omit<SubscriptionStatus, 'identity' | 'restarts'>>;\n\nfunction freshStatus(identity: string): SubscriptionStatus {\n return { identity, error: null, sourceState: 'connecting', restart: null, restarts: 0 };\n}\n\n/**\n * A realtime listener's source state and error, tagged to the subscription identity that\n * produced them. A new identity reads `connecting` with no error from its first render;\n * writes made for a retired identity are dropped once the new identity's listener has\n * started (it calls `reset`).\n *\n * `restart()` clears the error and bumps `restarts`; the listener effect re-opens on the bump,\n * and its first snapshot or next surfaced error ends the restart (`settled` in the patch).\n */\nexport function useSubscriptionStatus(identity: string) {\n const [status, setStatus] = useState<SubscriptionStatus>(() => freshStatus(identity));\n\n const current: SubscriptionStatus = status.identity === identity ? status : freshStatus(identity);\n\n const reset = useCallback(() => {\n setStatus((prev) =>\n prev.identity === identity\n ? { ...prev, error: null, sourceState: 'connecting' }\n : freshStatus(identity),\n );\n }, [identity]);\n\n const update = useCallback(\n (patch: StatusPatch | ((prev: SubscriptionStatus) => StatusPatch)) => {\n setStatus((prev) => {\n if (prev.identity !== identity) return prev;\n const next = typeof patch === 'function' ? patch(prev) : patch;\n return { ...prev, ...next };\n });\n },\n [identity],\n );\n\n // The identity the hook renders now. A `restart` captured under an earlier identity must not\n // touch the current one's status, or every write the current listener makes would be dropped.\n const renderedIdentity = useRef(identity);\n useEffect(() => {\n renderedIdentity.current = identity;\n }, [identity]);\n\n /** Re-opens the listener; false (and nothing changes) when this identity is no longer rendered. */\n const restart = useCallback((): boolean => {\n if (renderedIdentity.current !== identity) return false;\n setStatus((prev) => {\n const base = prev.identity === identity ? prev : freshStatus(identity);\n return {\n ...base,\n error: null,\n sourceState: 'connecting',\n restart: { fromError: base.error !== null || base.restart?.fromError === true },\n restarts: base.restarts + 1,\n };\n });\n return true;\n }, [identity]);\n\n return {\n error: current.error,\n sourceState: current.sourceState,\n pendingRestart: current.restart,\n restarts: current.restarts,\n reset,\n update,\n restart,\n };\n}\n\ntype SubscriptionStatusApi = ReturnType<typeof useSubscriptionStatus>;\n\ninterface RefetchWaiter<TData> {\n resolve: (result: QueryObserverResult<TData, Error>) => void;\n reject: (error: Error) => void;\n throwOnError: boolean;\n}\n\n/**\n * The subscribed hooks' result: the query's own result, with the listener's error and source\n * state merged in. In subscribe mode `refetch()` re-opens the listener (clearing its error, with a\n * fresh resubscribe ladder) and resolves once the re-opened listener delivers its first snapshot or\n * surfaces its next error; until then the result reports fetching. A restart after a failure shows\n * no data until that snapshot: the failed listener's last rows are not presented as current.\n */\nexport function useSubscribedResult<TData>(\n query: UseQueryResult<TData, Error>,\n subscribe: boolean,\n enabled: boolean,\n status: SubscriptionStatusApi,\n): WithSourceState<UseQueryResult<TData, Error>> {\n const { error, sourceState, pendingRestart, restart } = status;\n const waiters = useRef<RefetchWaiter<TData>[]>([]);\n const latest = useRef(query as QueryObserverResult<TData, Error>);\n const mounted = useRef(true);\n const active = subscribe && enabled;\n\n const refetch = useCallback(\n (options?: RefetchOptions): Promise<QueryObserverResult<TData, Error>> => {\n // An unmounted hook, or a refetch captured under an identity the hook has left, re-opens\n // nothing: it settles at once rather than waiting on a listener that will never report.\n if (!active || !mounted.current) return Promise.resolve(latest.current);\n return new Promise((resolve, reject) => {\n if (!restart()) {\n resolve(latest.current);\n return;\n }\n waiters.current.push({ resolve, reject, throwOnError: options?.throwOnError === true });\n });\n },\n [active, restart],\n );\n\n let result: UseQueryResult<TData, Error>;\n if (!subscribe) {\n result = query;\n } else if (error) {\n result = {\n ...query,\n data: undefined,\n error,\n isError: true,\n isLoadingError: true,\n isSuccess: false,\n isPending: false,\n isLoading: false,\n status: 'error',\n refetch,\n } as UseQueryResult<TData, Error>;\n } else if (pendingRestart?.fromError) {\n result = {\n ...query,\n data: undefined,\n error: null,\n isError: false,\n isLoadingError: false,\n isRefetchError: false,\n isSuccess: false,\n isPending: true,\n isLoading: true,\n isFetching: true,\n isRefetching: false,\n status: 'pending',\n fetchStatus: 'fetching',\n refetch,\n } as UseQueryResult<TData, Error>;\n } else if (pendingRestart) {\n result = {\n ...query,\n isFetching: true,\n isLoading: query.isPending,\n isRefetching: !query.isPending,\n fetchStatus: 'fetching',\n refetch,\n } as UseQueryResult<TData, Error>;\n } else if (active && query.isPending) {\n // The listener has not delivered its first snapshot. The query underneath is disabled in\n // subscribe mode, so it reports pending but not loading; the read IS loading, exactly like a\n // one-shot read's first fetch — never an answered absence.\n result = {\n ...query,\n isLoading: true,\n isFetching: true,\n fetchStatus: 'fetching',\n refetch,\n } as UseQueryResult<TData, Error>;\n } else {\n result = { ...query, refetch } as UseQueryResult<TData, Error>;\n }\n\n const restartOpen = pendingRestart !== null;\n useEffect(() => {\n latest.current = result as QueryObserverResult<TData, Error>;\n if (restartOpen || waiters.current.length === 0) return;\n const settled = waiters.current;\n waiters.current = [];\n for (const waiter of settled) {\n if (waiter.throwOnError && result.error) waiter.reject(result.error);\n else waiter.resolve(result as QueryObserverResult<TData, Error>);\n }\n });\n\n // A refetch still open when the hook unmounts resolves with the last result instead of hanging.\n useEffect(() => {\n mounted.current = true;\n return () => {\n mounted.current = false;\n const settled = waiters.current;\n waiters.current = [];\n for (const waiter of settled) waiter.resolve(latest.current);\n };\n }, []);\n\n return { ...result, sourceState } as WithSourceState<UseQueryResult<TData, Error>>;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttt-productions/query-core",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.15",
|
|
4
4
|
"description": "Shared TanStack Query (React Query) client defaults, query key helpers, and Firestore integration hooks for TTT Productions apps",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|