@ttt-productions/query-core 0.14.26 → 0.14.28

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.
Files changed (37) hide show
  1. package/dist/react/firestore/doc-subscription-registry.d.ts.map +1 -1
  2. package/dist/react/firestore/doc-subscription-registry.js +31 -16
  3. package/dist/react/firestore/doc-subscription-registry.js.map +1 -1
  4. package/dist/react/firestore/useBatchFirestoreDocs.d.ts.map +1 -1
  5. package/dist/react/firestore/useBatchFirestoreDocs.js.map +1 -1
  6. package/dist/react/index.d.ts +2 -1
  7. package/dist/react/index.d.ts.map +1 -1
  8. package/dist/react/index.js.map +1 -1
  9. package/dist/react/read-retry-derivation.d.ts +17 -0
  10. package/dist/react/read-retry-derivation.d.ts.map +1 -0
  11. package/dist/react/read-retry-derivation.js +26 -0
  12. package/dist/react/read-retry-derivation.js.map +1 -0
  13. package/dist/react/testing/firestore-test-wrapper.d.ts +14 -0
  14. package/dist/react/testing/firestore-test-wrapper.d.ts.map +1 -0
  15. package/dist/react/testing/firestore-test-wrapper.js +12 -0
  16. package/dist/react/testing/firestore-test-wrapper.js.map +1 -0
  17. package/dist/react/testing/index.d.ts +5 -0
  18. package/dist/react/testing/index.d.ts.map +1 -0
  19. package/dist/react/testing/index.js +5 -0
  20. package/dist/react/testing/index.js.map +1 -0
  21. package/dist/react/testing/mutation-builders.d.ts +18 -0
  22. package/dist/react/testing/mutation-builders.d.ts.map +1 -0
  23. package/dist/react/testing/mutation-builders.js +45 -0
  24. package/dist/react/testing/mutation-builders.js.map +1 -0
  25. package/dist/react/testing/paginated-read-builders.d.ts +20 -0
  26. package/dist/react/testing/paginated-read-builders.d.ts.map +1 -0
  27. package/dist/react/testing/paginated-read-builders.js +30 -0
  28. package/dist/react/testing/paginated-read-builders.js.map +1 -0
  29. package/dist/react/testing/read-builders.d.ts +49 -0
  30. package/dist/react/testing/read-builders.d.ts.map +1 -0
  31. package/dist/react/testing/read-builders.js +95 -0
  32. package/dist/react/testing/read-builders.js.map +1 -0
  33. package/dist/react/use-read-retry-state.d.ts +1 -11
  34. package/dist/react/use-read-retry-state.d.ts.map +1 -1
  35. package/dist/react/use-read-retry-state.js +1 -25
  36. package/dist/react/use-read-retry-state.js.map +1 -1
  37. package/package.json +6 -2
@@ -1 +1 @@
1
- {"version":3,"file":"doc-subscription-registry.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAoBzD,wBAAgB,eAAe,CAC7B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAET;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,KAAK,GAAG,IAAI,CAEd;AAWD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,IAAI,CA0DnE;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAEtE"}
1
+ {"version":3,"file":"doc-subscription-registry.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAqBzD,wBAAgB,eAAe,CAC7B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAET;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,KAAK,GAAG,IAAI,CAEd;AAWD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAwEnE;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAEtE"}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { doc, onSnapshot } from 'firebase/firestore';
3
- import { isPermissionDeniedError } from './resubscribe.js';
3
+ import { RESUBSCRIBE_DELAYS_MS, isPermissionDeniedError } from './resubscribe.js';
4
4
  const registries = new WeakMap();
5
5
  function registryKey(queryKeyPrefix, id) {
6
6
  return `${queryKeyPrefix} ${id}`;
@@ -29,24 +29,37 @@ export function subscribeDoc(params) {
29
29
  unsubscribe: () => { },
30
30
  subscribers: new Set(),
31
31
  error: null,
32
+ retryTimer: null,
32
33
  };
33
34
  const subscribers = created.subscribers;
34
35
  const ref = doc(db, collectionPath, id);
35
- created.unsubscribe = onSnapshot(ref, (snapshot) => {
36
- created.error = null;
37
- queryClient.setQueryData([queryKeyPrefix, id], snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null, { updatedAt: Date.now() });
38
- // Copy before iterating: an onUpdate could (re-entrantly) unsubscribe.
39
- for (const sub of [...subscribers])
40
- sub.onUpdate();
41
- }, (error) => {
42
- created.error = error;
43
- const held = queryClient.getQueryData([queryKeyPrefix, id]);
44
- if (held === undefined || held === null || isPermissionDeniedError(error)) {
45
- queryClient.setQueryData([queryKeyPrefix, id], null, { updatedAt: Date.now() });
46
- }
47
- for (const sub of [...subscribers])
48
- sub.onError?.(error);
49
- });
36
+ let attempt = 0;
37
+ // The SDK ends a listener on its first error, so a denied one is re-opened on the backoff
38
+ // `useFirestoreDoc` uses; its failure shows meanwhile, since a denied id reads as failed.
39
+ const listen = () => {
40
+ created.retryTimer = null;
41
+ created.unsubscribe = onSnapshot(ref, (snapshot) => {
42
+ attempt = 0;
43
+ created.error = null;
44
+ queryClient.setQueryData([queryKeyPrefix, id], snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null, { updatedAt: Date.now() });
45
+ // Copy before iterating: an onUpdate could (re-entrantly) unsubscribe.
46
+ for (const sub of [...subscribers])
47
+ sub.onUpdate();
48
+ }, (error) => {
49
+ created.error = error;
50
+ const held = queryClient.getQueryData([queryKeyPrefix, id]);
51
+ if (held === undefined || held === null || isPermissionDeniedError(error)) {
52
+ queryClient.setQueryData([queryKeyPrefix, id], null, { updatedAt: Date.now() });
53
+ }
54
+ if (isPermissionDeniedError(error) && attempt < RESUBSCRIBE_DELAYS_MS.length) {
55
+ created.retryTimer = setTimeout(listen, RESUBSCRIBE_DELAYS_MS[attempt]);
56
+ attempt += 1;
57
+ }
58
+ for (const sub of [...subscribers])
59
+ sub.onError?.(error);
60
+ });
61
+ };
62
+ listen();
50
63
  entry = created;
51
64
  registry.set(key, entry);
52
65
  }
@@ -64,6 +77,8 @@ export function subscribeDoc(params) {
64
77
  return;
65
78
  current.subscribers.delete(subscriber);
66
79
  if (current.subscribers.size === 0) {
80
+ if (current.retryTimer)
81
+ clearTimeout(current.retryTimer);
67
82
  current.unsubscribe();
68
83
  registry.delete(key);
69
84
  if (current.error) {
@@ -1 +1 @@
1
- {"version":3,"file":"doc-subscription-registry.js","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { doc, onSnapshot, type Firestore } from 'firebase/firestore';\nimport type { QueryClient } from '@tanstack/react-query';\nimport { isPermissionDeniedError } from './resubscribe.js';\n\ntype Subscriber = {\n onUpdate: () => void;\n onError?: (error: Error) => void;\n};\n\ntype Entry = {\n unsubscribe: () => void;\n subscribers: Set<Subscriber>;\n error: Error | null;\n};\n\nconst registries = new WeakMap<QueryClient, Map<string, Entry>>();\n\nfunction registryKey(queryKeyPrefix: string, id: string): string {\n return `${queryKeyPrefix} ${id}`;\n}\n\nexport function isListenerOwned(\n queryClient: QueryClient,\n queryKeyPrefix: string,\n id: string,\n): boolean {\n return registries.get(queryClient)?.has(registryKey(queryKeyPrefix, id)) ?? false;\n}\n\nexport function listenerErrorOf(\n queryClient: QueryClient,\n queryKeyPrefix: string,\n id: string,\n): Error | null {\n return registries.get(queryClient)?.get(registryKey(queryKeyPrefix, id))?.error ?? null;\n}\n\nfunction getRegistry(queryClient: QueryClient): Map<string, Entry> {\n let registry = registries.get(queryClient);\n if (!registry) {\n registry = new Map();\n registries.set(queryClient, registry);\n }\n return registry;\n}\n\nexport interface SubscribeDocParams {\n queryClient: QueryClient;\n db: Firestore;\n collectionPath: string;\n queryKeyPrefix: string;\n id: string;\n onUpdate: () => void;\n onError?: (error: Error) => void;\n}\n\nexport function subscribeDoc(params: SubscribeDocParams): () => void {\n const { queryClient, db, collectionPath, queryKeyPrefix, id, onUpdate, onError } = params;\n const registry = getRegistry(queryClient);\n const key = registryKey(queryKeyPrefix, id);\n\n let entry = registry.get(key);\n if (!entry) {\n const created: Entry = {\n unsubscribe: () => {},\n subscribers: new Set<Subscriber>(),\n error: null,\n };\n const subscribers = created.subscribers;\n const ref = doc(db, collectionPath, id);\n created.unsubscribe = onSnapshot(\n ref,\n (snapshot) => {\n created.error = null;\n queryClient.setQueryData(\n [queryKeyPrefix, id],\n snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null,\n { updatedAt: Date.now() },\n );\n // Copy before iterating: an onUpdate could (re-entrantly) unsubscribe.\n for (const sub of [...subscribers]) sub.onUpdate();\n },\n (error) => {\n created.error = error;\n const held = queryClient.getQueryData([queryKeyPrefix, id]);\n if (held === undefined || held === null || isPermissionDeniedError(error)) {\n queryClient.setQueryData([queryKeyPrefix, id], null, { updatedAt: Date.now() });\n }\n for (const sub of [...subscribers]) sub.onError?.(error);\n },\n );\n entry = created;\n registry.set(key, entry);\n }\n\n const subscriber: Subscriber = { onUpdate, onError };\n entry.subscribers.add(subscriber);\n if (entry.error) onError?.(entry.error);\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = registry.get(key);\n if (!current) return;\n current.subscribers.delete(subscriber);\n if (current.subscribers.size === 0) {\n current.unsubscribe();\n registry.delete(key);\n if (current.error) {\n void queryClient.invalidateQueries({ queryKey: [queryKeyPrefix, id], exact: true });\n }\n }\n };\n}\n\nexport function __activeListenerCount(queryClient: QueryClient): number {\n return registries.get(queryClient)?.size ?? 0;\n}\n"]}
1
+ {"version":3,"file":"doc-subscription-registry.js","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { doc, onSnapshot, type Firestore } from 'firebase/firestore';\nimport type { QueryClient } from '@tanstack/react-query';\nimport { RESUBSCRIBE_DELAYS_MS, isPermissionDeniedError } from './resubscribe.js';\n\ntype Subscriber = {\n onUpdate: () => void;\n onError?: (error: Error) => void;\n};\n\ntype Entry = {\n unsubscribe: () => void;\n subscribers: Set<Subscriber>;\n error: Error | null;\n retryTimer: ReturnType<typeof setTimeout> | null;\n};\n\nconst registries = new WeakMap<QueryClient, Map<string, Entry>>();\n\nfunction registryKey(queryKeyPrefix: string, id: string): string {\n return `${queryKeyPrefix} ${id}`;\n}\n\nexport function isListenerOwned(\n queryClient: QueryClient,\n queryKeyPrefix: string,\n id: string,\n): boolean {\n return registries.get(queryClient)?.has(registryKey(queryKeyPrefix, id)) ?? false;\n}\n\nexport function listenerErrorOf(\n queryClient: QueryClient,\n queryKeyPrefix: string,\n id: string,\n): Error | null {\n return registries.get(queryClient)?.get(registryKey(queryKeyPrefix, id))?.error ?? null;\n}\n\nfunction getRegistry(queryClient: QueryClient): Map<string, Entry> {\n let registry = registries.get(queryClient);\n if (!registry) {\n registry = new Map();\n registries.set(queryClient, registry);\n }\n return registry;\n}\n\nexport interface SubscribeDocParams {\n queryClient: QueryClient;\n db: Firestore;\n collectionPath: string;\n queryKeyPrefix: string;\n id: string;\n onUpdate: () => void;\n onError?: (error: Error) => void;\n}\n\nexport function subscribeDoc(params: SubscribeDocParams): () => void {\n const { queryClient, db, collectionPath, queryKeyPrefix, id, onUpdate, onError } = params;\n const registry = getRegistry(queryClient);\n const key = registryKey(queryKeyPrefix, id);\n\n let entry = registry.get(key);\n if (!entry) {\n const created: Entry = {\n unsubscribe: () => {},\n subscribers: new Set<Subscriber>(),\n error: null,\n retryTimer: null,\n };\n const subscribers = created.subscribers;\n const ref = doc(db, collectionPath, id);\n let attempt = 0;\n // The SDK ends a listener on its first error, so a denied one is re-opened on the backoff\n // `useFirestoreDoc` uses; its failure shows meanwhile, since a denied id reads as failed.\n const listen = () => {\n created.retryTimer = null;\n created.unsubscribe = onSnapshot(\n ref,\n (snapshot) => {\n attempt = 0;\n created.error = null;\n queryClient.setQueryData(\n [queryKeyPrefix, id],\n snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null,\n { updatedAt: Date.now() },\n );\n // Copy before iterating: an onUpdate could (re-entrantly) unsubscribe.\n for (const sub of [...subscribers]) sub.onUpdate();\n },\n (error) => {\n created.error = error;\n const held = queryClient.getQueryData([queryKeyPrefix, id]);\n if (held === undefined || held === null || isPermissionDeniedError(error)) {\n queryClient.setQueryData([queryKeyPrefix, id], null, { updatedAt: Date.now() });\n }\n if (isPermissionDeniedError(error) && attempt < RESUBSCRIBE_DELAYS_MS.length) {\n created.retryTimer = setTimeout(listen, RESUBSCRIBE_DELAYS_MS[attempt]);\n attempt += 1;\n }\n for (const sub of [...subscribers]) sub.onError?.(error);\n },\n );\n };\n listen();\n entry = created;\n registry.set(key, entry);\n }\n\n const subscriber: Subscriber = { onUpdate, onError };\n entry.subscribers.add(subscriber);\n if (entry.error) onError?.(entry.error);\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = registry.get(key);\n if (!current) return;\n current.subscribers.delete(subscriber);\n if (current.subscribers.size === 0) {\n if (current.retryTimer) clearTimeout(current.retryTimer);\n current.unsubscribe();\n registry.delete(key);\n if (current.error) {\n void queryClient.invalidateQueries({ queryKey: [queryKeyPrefix, id], exact: true });\n }\n }\n };\n}\n\nexport function __activeListenerCount(queryClient: QueryClient): number {\n return registries.get(queryClient)?.size ?? 0;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"useBatchFirestoreDocs.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAIlE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAIzE,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1D,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAE,SAAS,CAAC;IAEd,cAAc,EAAE,MAAM,CAAC;IAEvB,GAAG,EAAE,MAAM,EAAE,CAAC;IAEd,cAAc,EAAE,MAAM,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,iHAAiH;IACjH,SAAS,CAAC,EAAE,2BAA2B,CAAC;IAExC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAAI;IACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAExB,SAAS,EAAE,OAAO,CAAC;IAEnB,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAEpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtD,kBAAkB,EAAE,OAAO,CAAC;IAE5B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AA2CF,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,YAAY,EAAE,EAC5D,EAAE,EACF,cAAc,EACd,GAAG,EACH,cAAc,EACd,SAA0B,EAC1B,MAAuB,EACvB,OAAc,EACd,SAAiB,EACjB,SAAmB,EACnB,eAA2B,EAC3B,mBAA4C,GAC7C,EAAE,yBAAyB,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAkLzD"}
1
+ {"version":3,"file":"useBatchFirestoreDocs.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAIlE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAKzE,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1D,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAE,SAAS,CAAC;IAEd,cAAc,EAAE,MAAM,CAAC;IAEvB,GAAG,EAAE,MAAM,EAAE,CAAC;IAEd,cAAc,EAAE,MAAM,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,iHAAiH;IACjH,SAAS,CAAC,EAAE,2BAA2B,CAAC;IAExC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAAI;IACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAExB,SAAS,EAAE,OAAO,CAAC;IAEnB,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAEpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtD,kBAAkB,EAAE,OAAO,CAAC;IAE5B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AA2CF,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,YAAY,EAAE,EAC5D,EAAE,EACF,cAAc,EACd,GAAG,EACH,cAAc,EACd,SAA0B,EAC1B,MAAuB,EACvB,OAAc,EACd,SAAiB,EACjB,SAAmB,EACnB,eAA2B,EAC3B,mBAA4C,GAC7C,EAAE,yBAAyB,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAkLzD"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBatchFirestoreDocs.js","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useQueries, useQueryClient } from '@tanstack/react-query';\nimport type { DocumentData, Firestore } from 'firebase/firestore';\nimport { isListenerOwned, listenerErrorOf, subscribeDoc } from './doc-subscription-registry.js';\nimport { getDocLoader } from './batch-doc-loader.js';\nimport { ABSENT_RETRY_DELAYS_MS, trackAbsentDoc } from './absence-scheduler.js';\nimport type { BatchFirestoreDocOutcome } from '../../firestore/types.js';\nimport { useReadRetryStates, type ReadRetrySource } from '../use-read-retry-state.js';\nimport { isPermissionDeniedError } from './resubscribe.js';\n\nexport type BatchFirestoreDocsTransport = 'batch' | 'get';\n\nexport type BatchFirestoreDocsOptions = {\n db: Firestore;\n\n collectionPath: string;\n\n ids: string[];\n\n queryKeyPrefix: string;\n\n staleTime?: number;\n\n gcTime?: number;\n\n enabled?: boolean;\n\n subscribe?: boolean;\n\n /** `'get'` is required where rules gate reads on `resource.data`: there an id-list query is denied wholesale. */\n transport?: BatchFirestoreDocsTransport;\n\n absentStaleTime?: number;\n\n absentRetryDelaysMs?: readonly number[];\n};\n\nexport type BatchFirestoreDocsResult<T> = {\n data: Record<string, T>;\n\n isLoading: boolean;\n\n isError: boolean;\n\n error: Error | null;\n\n outcomes: Record<string, BatchFirestoreDocOutcome<T>>;\n\n failedReadsRunning: boolean;\n\n refetch: () => Promise<void>;\n};\n\nconst LOADING_OUTCOME = { status: 'loading' } as const;\nconst IDLE_SOURCE: ReadRetrySource<Error> = { error: null, isFetching: false, isLoading: false };\nconst ABSENT_OUTCOME = { status: 'absent' } as const;\n\nfunction sameOutcome<T>(a: BatchFirestoreDocOutcome<T>, b: BatchFirestoreDocOutcome<T>): boolean {\n if (a.status !== b.status) return false;\n if (a.status === 'present') {\n const other = b as { data: T; failure?: { error: Error; retrying: boolean } };\n return (\n a.data === other.data &&\n a.failure?.error === other.failure?.error &&\n a.failure?.retrying === other.failure?.retrying\n );\n }\n if (a.status === 'failed') {\n const other = b as { error: Error; retrying: boolean };\n return a.error === other.error && a.retrying === other.retrying;\n }\n return true;\n}\n\nfunction failedOrHeld<T>(\n value: T | null | undefined,\n error: Error,\n retrying: boolean,\n): BatchFirestoreDocOutcome<T> {\n if (value === null || value === undefined || isPermissionDeniedError(error)) {\n return { status: 'failed', error, retrying };\n }\n return { status: 'present', data: value, failure: { error, retrying } };\n}\n\nfunction shallowRecordEqual<T>(a: Record<string, T>, b: Record<string, T>): boolean {\n const aKeys = Object.keys(a);\n if (aKeys.length !== Object.keys(b).length) return false;\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(b, key) || a[key] !== b[key]) return false;\n }\n return true;\n}\n\nexport function useBatchFirestoreDocs<T extends DocumentData>({\n db,\n collectionPath,\n ids,\n queryKeyPrefix,\n staleTime = 30 * 60 * 1000,\n gcTime = 60 * 60 * 1000,\n enabled = true,\n subscribe = false,\n transport = 'batch',\n absentStaleTime = 30 * 1000,\n absentRetryDelaysMs = ABSENT_RETRY_DELAYS_MS,\n}: BatchFirestoreDocsOptions): BatchFirestoreDocsResult<T> {\n const queryClient = useQueryClient();\n\n const idsKey = JSON.stringify(ids);\n\n const uniqueIds = useMemo(() => {\n // idsKey is this hook's own serialization of the ids list.\n const parsed = JSON.parse(idsKey) as string[];\n return Array.from(new Set(parsed.filter(Boolean)));\n }, [idsKey]);\n\n const [subscribeErrors, setSubscribeErrors] = useState<Record<string, Error>>({});\n // Query observers notify on React Query's batched microtask; bumping state here shows a snapshot in the tick it lands.\n const [, setSnapshotVersion] = useState(0);\n\n const results = useQueries({\n queries: uniqueIds.map((id) => ({\n queryKey: [queryKeyPrefix, id],\n queryFn: async ({ signal }: { signal: AbortSignal }): Promise<T | null> => {\n const loader = getDocLoader(queryClient, db, collectionPath);\n const loaded =\n transport === 'get'\n ? await loader.loadOne(id, signal)\n : await loader.loadBatched(id, signal);\n // `onSnapshot` does not re-emit until the document changes, so a read that lands after a listener took the key yields to it.\n if (isListenerOwned(queryClient, queryKeyPrefix, id)) {\n const listenerError = listenerErrorOf(queryClient, queryKeyPrefix, id);\n if (listenerError) throw listenerError;\n const owned = queryClient.getQueryData([queryKeyPrefix, id]);\n if (owned !== undefined) return owned as T | null;\n }\n return loaded as T | null;\n },\n enabled: enabled && !subscribe,\n // Opts back into refetch-on-mount (the package default is off) so a remount re-reads a stale id.\n refetchOnMount: !subscribe,\n staleTime: subscribe\n ? Infinity\n : (query: { state: { data: unknown } }) =>\n query.state.data === null ? absentStaleTime : staleTime,\n gcTime,\n })),\n });\n\n useEffect(() => {\n if (!subscribe || !enabled || uniqueIds.length === 0) return;\n setSubscribeErrors({});\n const unsubscribers = uniqueIds.map((id) =>\n subscribeDoc({\n queryClient,\n db,\n collectionPath,\n queryKeyPrefix,\n id,\n onUpdate: () => {\n setSubscribeErrors((errors) => {\n if (!(id in errors)) return errors;\n const { [id]: _cleared, ...rest } = errors;\n return rest;\n });\n setSnapshotVersion((version) => version + 1);\n },\n onError: (error) =>\n setSubscribeErrors((errors) =>\n errors[id] === error ? errors : { ...errors, [id]: error },\n ),\n }),\n );\n return () => {\n for (const unsubscribe of unsubscribers) unsubscribe();\n };\n }, [uniqueIds, subscribe, enabled, collectionPath, queryKeyPrefix, queryClient, db]);\n\n const absentDelaysKey = absentRetryDelaysMs.join(',');\n const absentDelays = useMemo(\n () => absentDelaysKey.split(',').filter(Boolean).map(Number),\n [absentDelaysKey],\n );\n\n useEffect(() => {\n if (uniqueIds.length === 0) return;\n const releases = uniqueIds.map((id) =>\n trackAbsentDoc({ queryClient, queryKey: [queryKeyPrefix, id], delays: absentDelays }),\n );\n return () => {\n for (const release of releases) release();\n };\n }, [uniqueIds, queryKeyPrefix, queryClient, absentDelays]);\n\n // Only the effect writes these refs, so a concurrent render React discards never leaves them on an uncommitted map.\n const committedDataRef = useRef<Record<string, T>>({});\n const committedOutcomesRef = useRef<Record<string, BatchFirestoreDocOutcome<T>>>({});\n\n // TanStack clears a never-answered read's error as its refetch starts, so the failure is held through the retry.\n const retryStates = useReadRetryStates(\n uniqueIds.map((id, index) => ({\n source: (results[index] ?? IDLE_SOURCE) as ReadRetrySource<Error>,\n queryKey: [queryKeyPrefix, id],\n })),\n );\n\n const nextData: Record<string, T> = {};\n const nextOutcomes: Record<string, BatchFirestoreDocOutcome<T>> = {};\n let anyError: Error | null = null;\n let anyListenerError: Error | null = null;\n let oneShotLoading = false;\n let anyUnresolved = false;\n let failedReadsRunning = false;\n\n for (let index = 0; index < uniqueIds.length; index += 1) {\n const id = uniqueIds[index];\n const result = results[index];\n let outcome: BatchFirestoreDocOutcome<T> = LOADING_OUTCOME;\n const listenerError =\n (subscribe ? subscribeErrors[id] : undefined) ??\n listenerErrorOf(queryClient, queryKeyPrefix, id) ??\n undefined;\n if (\n result &&\n (result.isFetching || result.isPaused) &&\n result.errorUpdatedAt > result.dataUpdatedAt\n ) {\n failedReadsRunning = true;\n }\n const retryState = retryStates[index];\n if (result?.isError) anyError ??= result.error as Error;\n const value = result?.data as T | null | undefined;\n if (retryState && retryState.error !== null) {\n outcome = failedOrHeld(value, retryState.error, retryState.isRetrying);\n } else if (result) {\n if (result.isLoading) oneShotLoading = true;\n if (value === undefined) anyUnresolved = true;\n if (listenerError) {\n anyListenerError ??= listenerError;\n outcome = failedOrHeld(value, listenerError, false);\n } else if (value === null) {\n outcome = ABSENT_OUTCOME;\n } else if (value !== undefined) {\n outcome = { status: 'present', data: value };\n }\n }\n if (outcome.status === 'present') nextData[id] = outcome.data;\n const committed = committedOutcomesRef.current[id];\n nextOutcomes[id] = committed && sameOutcome(committed, outcome) ? committed : outcome;\n }\n\n const data = shallowRecordEqual(committedDataRef.current, nextData)\n ? committedDataRef.current\n : nextData;\n const outcomes = shallowRecordEqual(committedOutcomesRef.current, nextOutcomes)\n ? committedOutcomesRef.current\n : nextOutcomes;\n\n useEffect(() => {\n committedDataRef.current = data;\n committedOutcomesRef.current = outcomes;\n }, [data, outcomes]);\n\n const refetch = useCallback(async () => {\n if (subscribe || !enabled) return;\n await Promise.all(\n uniqueIds.map((id) =>\n queryClient.refetchQueries({ queryKey: [queryKeyPrefix, id], exact: true }),\n ),\n );\n }, [uniqueIds, subscribe, enabled, queryClient, queryKeyPrefix]);\n\n const isLoading = subscribe ? enabled && anyUnresolved : oneShotLoading;\n\n return {\n data,\n isLoading,\n isError: anyError !== null || anyListenerError !== null,\n error: anyError ?? anyListenerError,\n outcomes,\n failedReadsRunning,\n refetch,\n };\n}\n"]}
1
+ {"version":3,"file":"useBatchFirestoreDocs.js","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAChG,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAEhF,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AA6C3D,MAAM,eAAe,GAAG,EAAE,MAAM,EAAE,SAAS,EAAW,CAAC;AACvD,MAAM,WAAW,GAA2B,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACjG,MAAM,cAAc,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAW,CAAC;AAErD,SAAS,WAAW,CAAI,CAA8B,EAAE,CAA8B;IACpF,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACxC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,CAA+D,CAAC;QAC9E,OAAO,CACL,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI;YACrB,CAAC,CAAC,OAAO,EAAE,KAAK,KAAK,KAAK,CAAC,OAAO,EAAE,KAAK;YACzC,CAAC,CAAC,OAAO,EAAE,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,QAAQ,CAChD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,CAAwC,CAAC;QACvD,OAAO,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ,CAAC;IAClE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,YAAY,CACnB,KAA2B,EAC3B,KAAY,EACZ,QAAiB;IAEjB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5E,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC;AAC1E,CAAC;AAED,SAAS,kBAAkB,CAAI,CAAoB,EAAE,CAAoB;IACvE,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7B,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACzD,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IACvF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAyB,EAC5D,EAAE,EACF,cAAc,EACd,GAAG,EACH,cAAc,EACd,SAAS,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAC1B,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EACvB,OAAO,GAAG,IAAI,EACd,SAAS,GAAG,KAAK,EACjB,SAAS,GAAG,OAAO,EACnB,eAAe,GAAG,EAAE,GAAG,IAAI,EAC3B,mBAAmB,GAAG,sBAAsB,GAClB;IAC1B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAEnC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE;QAC7B,2DAA2D;QAC3D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAa,CAAC;QAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAwB,EAAE,CAAC,CAAC;IAClF,uHAAuH;IACvH,MAAM,CAAC,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAE3C,MAAM,OAAO,GAAG,UAAU,CAAC;QACzB,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YAC9B,QAAQ,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC;YAC9B,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAA2B,EAAqB,EAAE;gBACxE,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;gBAC7D,MAAM,MAAM,GACV,SAAS,KAAK,KAAK;oBACjB,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC;oBAClC,CAAC,CAAC,MAAM,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;gBAC3C,6HAA6H;gBAC7H,IAAI,eAAe,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,CAAC;oBACrD,MAAM,aAAa,GAAG,eAAe,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;oBACvE,IAAI,aAAa;wBAAE,MAAM,aAAa,CAAC;oBACvC,MAAM,KAAK,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC;oBAC7D,IAAI,KAAK,KAAK,SAAS;wBAAE,OAAO,KAAiB,CAAC;gBACpD,CAAC;gBACD,OAAO,MAAkB,CAAC;YAC5B,CAAC;YACD,OAAO,EAAE,OAAO,IAAI,CAAC,SAAS;YAC9B,iGAAiG;YACjG,cAAc,EAAE,CAAC,SAAS;YAC1B,SAAS,EAAE,SAAS;gBAClB,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,CAAC,KAAmC,EAAE,EAAE,CACtC,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS;YAC7D,MAAM;SACP,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,IAAI,CAAC,OAAO,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC7D,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACvB,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CACzC,YAAY,CAAC;YACX,WAAW;YACX,EAAE;YACF,cAAc;YACd,cAAc;YACd,EAAE;YACF,QAAQ,EAAE,GAAG,EAAE;gBACb,kBAAkB,CAAC,CAAC,MAAM,EAAE,EAAE;oBAC5B,IAAI,CAAC,CAAC,EAAE,IAAI,MAAM,CAAC;wBAAE,OAAO,MAAM,CAAC;oBACnC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC;oBAC3C,OAAO,IAAI,CAAC;gBACd,CAAC,CAAC,CAAC;gBACH,kBAAkB,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;YAC/C,CAAC;YACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CACjB,kBAAkB,CAAC,CAAC,MAAM,EAAE,EAAE,CAC5B,MAAM,CAAC,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAC3D;SACJ,CAAC,CACH,CAAC;QACF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,WAAW,IAAI,aAAa;gBAAE,WAAW,EAAE,CAAC;QACzD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC;IAErF,MAAM,eAAe,GAAG,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtD,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAC5D,CAAC,eAAe,CAAC,CAClB,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QACnC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CACpC,cAAc,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CACtF,CAAC;QACF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,OAAO,IAAI,QAAQ;gBAAE,OAAO,EAAE,CAAC;QAC5C,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;IAE3D,oHAAoH;IACpH,MAAM,gBAAgB,GAAG,MAAM,CAAoB,EAAE,CAAC,CAAC;IACvD,MAAM,oBAAoB,GAAG,MAAM,CAA8C,EAAE,CAAC,CAAC;IAErF,iHAAiH;IACjH,MAAM,WAAW,GAAG,kBAAkB,CACpC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5B,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,WAAW,CAA2B;QACjE,QAAQ,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC;KAC/B,CAAC,CAAC,CACJ,CAAC;IAEF,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,YAAY,GAAgD,EAAE,CAAC;IACrE,IAAI,QAAQ,GAAiB,IAAI,CAAC;IAClC,IAAI,gBAAgB,GAAiB,IAAI,CAAC;IAC1C,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,kBAAkB,GAAG,KAAK,CAAC;IAE/B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACzD,MAAM,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,OAAO,GAAgC,eAAe,CAAC;QAC3D,MAAM,aAAa,GACjB,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAC7C,eAAe,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,CAAC;YAChD,SAAS,CAAC;QACZ,IACE,MAAM;YACN,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,CAAC;YACtC,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,aAAa,EAC5C,CAAC;YACD,kBAAkB,GAAG,IAAI,CAAC;QAC5B,CAAC;QACD,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,MAAM,EAAE,OAAO;YAAE,QAAQ,KAAK,MAAM,CAAC,KAAc,CAAC;QACxD,MAAM,KAAK,GAAG,MAAM,EAAE,IAA4B,CAAC;QACnD,IAAI,UAAU,IAAI,UAAU,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YAC5C,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;QACzE,CAAC;aAAM,IAAI,MAAM,EAAE,CAAC;YAClB,IAAI,MAAM,CAAC,SAAS;gBAAE,cAAc,GAAG,IAAI,CAAC;YAC5C,IAAI,KAAK,KAAK,SAAS;gBAAE,aAAa,GAAG,IAAI,CAAC;YAC9C,IAAI,aAAa,EAAE,CAAC;gBAClB,gBAAgB,KAAK,aAAa,CAAC;gBACnC,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,CAAC,CAAC;YACtD,CAAC;iBAAM,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBAC1B,OAAO,GAAG,cAAc,CAAC;YAC3B,CAAC;iBAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC/B,OAAO,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YAC/C,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;YAAE,QAAQ,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;QAC9D,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnD,YAAY,CAAC,EAAE,CAAC,GAAG,SAAS,IAAI,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;IACxF,CAAC;IAED,MAAM,IAAI,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC;QACjE,CAAC,CAAC,gBAAgB,CAAC,OAAO;QAC1B,CAAC,CAAC,QAAQ,CAAC;IACb,MAAM,QAAQ,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,OAAO,EAAE,YAAY,CAAC;QAC7E,CAAC,CAAC,oBAAoB,CAAC,OAAO;QAC9B,CAAC,CAAC,YAAY,CAAC;IAEjB,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC;QAChC,oBAAoB,CAAC,OAAO,GAAG,QAAQ,CAAC;IAC1C,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAErB,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACrC,IAAI,SAAS,IAAI,CAAC,OAAO;YAAE,OAAO;QAClC,MAAM,OAAO,CAAC,GAAG,CACf,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CACnB,WAAW,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAC5E,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;IAEjE,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,IAAI,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC;IAExE,OAAO;QACL,IAAI;QACJ,SAAS;QACT,OAAO,EAAE,QAAQ,KAAK,IAAI,IAAI,gBAAgB,KAAK,IAAI;QACvD,KAAK,EAAE,QAAQ,IAAI,gBAAgB;QACnC,QAAQ;QACR,kBAAkB;QAClB,OAAO;KACR,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useQueries, useQueryClient } from '@tanstack/react-query';\nimport type { DocumentData, Firestore } from 'firebase/firestore';\nimport { isListenerOwned, listenerErrorOf, subscribeDoc } from './doc-subscription-registry.js';\nimport { getDocLoader } from './batch-doc-loader.js';\nimport { ABSENT_RETRY_DELAYS_MS, trackAbsentDoc } from './absence-scheduler.js';\nimport type { BatchFirestoreDocOutcome } from '../../firestore/types.js';\nimport { useReadRetryStates } from '../use-read-retry-state.js';\nimport type { ReadRetrySource } from '../read-retry-derivation.js';\nimport { isPermissionDeniedError } from './resubscribe.js';\n\nexport type BatchFirestoreDocsTransport = 'batch' | 'get';\n\nexport type BatchFirestoreDocsOptions = {\n db: Firestore;\n\n collectionPath: string;\n\n ids: string[];\n\n queryKeyPrefix: string;\n\n staleTime?: number;\n\n gcTime?: number;\n\n enabled?: boolean;\n\n subscribe?: boolean;\n\n /** `'get'` is required where rules gate reads on `resource.data`: there an id-list query is denied wholesale. */\n transport?: BatchFirestoreDocsTransport;\n\n absentStaleTime?: number;\n\n absentRetryDelaysMs?: readonly number[];\n};\n\nexport type BatchFirestoreDocsResult<T> = {\n data: Record<string, T>;\n\n isLoading: boolean;\n\n isError: boolean;\n\n error: Error | null;\n\n outcomes: Record<string, BatchFirestoreDocOutcome<T>>;\n\n failedReadsRunning: boolean;\n\n refetch: () => Promise<void>;\n};\n\nconst LOADING_OUTCOME = { status: 'loading' } as const;\nconst IDLE_SOURCE: ReadRetrySource<Error> = { error: null, isFetching: false, isLoading: false };\nconst ABSENT_OUTCOME = { status: 'absent' } as const;\n\nfunction sameOutcome<T>(a: BatchFirestoreDocOutcome<T>, b: BatchFirestoreDocOutcome<T>): boolean {\n if (a.status !== b.status) return false;\n if (a.status === 'present') {\n const other = b as { data: T; failure?: { error: Error; retrying: boolean } };\n return (\n a.data === other.data &&\n a.failure?.error === other.failure?.error &&\n a.failure?.retrying === other.failure?.retrying\n );\n }\n if (a.status === 'failed') {\n const other = b as { error: Error; retrying: boolean };\n return a.error === other.error && a.retrying === other.retrying;\n }\n return true;\n}\n\nfunction failedOrHeld<T>(\n value: T | null | undefined,\n error: Error,\n retrying: boolean,\n): BatchFirestoreDocOutcome<T> {\n if (value === null || value === undefined || isPermissionDeniedError(error)) {\n return { status: 'failed', error, retrying };\n }\n return { status: 'present', data: value, failure: { error, retrying } };\n}\n\nfunction shallowRecordEqual<T>(a: Record<string, T>, b: Record<string, T>): boolean {\n const aKeys = Object.keys(a);\n if (aKeys.length !== Object.keys(b).length) return false;\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(b, key) || a[key] !== b[key]) return false;\n }\n return true;\n}\n\nexport function useBatchFirestoreDocs<T extends DocumentData>({\n db,\n collectionPath,\n ids,\n queryKeyPrefix,\n staleTime = 30 * 60 * 1000,\n gcTime = 60 * 60 * 1000,\n enabled = true,\n subscribe = false,\n transport = 'batch',\n absentStaleTime = 30 * 1000,\n absentRetryDelaysMs = ABSENT_RETRY_DELAYS_MS,\n}: BatchFirestoreDocsOptions): BatchFirestoreDocsResult<T> {\n const queryClient = useQueryClient();\n\n const idsKey = JSON.stringify(ids);\n\n const uniqueIds = useMemo(() => {\n // idsKey is this hook's own serialization of the ids list.\n const parsed = JSON.parse(idsKey) as string[];\n return Array.from(new Set(parsed.filter(Boolean)));\n }, [idsKey]);\n\n const [subscribeErrors, setSubscribeErrors] = useState<Record<string, Error>>({});\n // Query observers notify on React Query's batched microtask; bumping state here shows a snapshot in the tick it lands.\n const [, setSnapshotVersion] = useState(0);\n\n const results = useQueries({\n queries: uniqueIds.map((id) => ({\n queryKey: [queryKeyPrefix, id],\n queryFn: async ({ signal }: { signal: AbortSignal }): Promise<T | null> => {\n const loader = getDocLoader(queryClient, db, collectionPath);\n const loaded =\n transport === 'get'\n ? await loader.loadOne(id, signal)\n : await loader.loadBatched(id, signal);\n // `onSnapshot` does not re-emit until the document changes, so a read that lands after a listener took the key yields to it.\n if (isListenerOwned(queryClient, queryKeyPrefix, id)) {\n const listenerError = listenerErrorOf(queryClient, queryKeyPrefix, id);\n if (listenerError) throw listenerError;\n const owned = queryClient.getQueryData([queryKeyPrefix, id]);\n if (owned !== undefined) return owned as T | null;\n }\n return loaded as T | null;\n },\n enabled: enabled && !subscribe,\n // Opts back into refetch-on-mount (the package default is off) so a remount re-reads a stale id.\n refetchOnMount: !subscribe,\n staleTime: subscribe\n ? Infinity\n : (query: { state: { data: unknown } }) =>\n query.state.data === null ? absentStaleTime : staleTime,\n gcTime,\n })),\n });\n\n useEffect(() => {\n if (!subscribe || !enabled || uniqueIds.length === 0) return;\n setSubscribeErrors({});\n const unsubscribers = uniqueIds.map((id) =>\n subscribeDoc({\n queryClient,\n db,\n collectionPath,\n queryKeyPrefix,\n id,\n onUpdate: () => {\n setSubscribeErrors((errors) => {\n if (!(id in errors)) return errors;\n const { [id]: _cleared, ...rest } = errors;\n return rest;\n });\n setSnapshotVersion((version) => version + 1);\n },\n onError: (error) =>\n setSubscribeErrors((errors) =>\n errors[id] === error ? errors : { ...errors, [id]: error },\n ),\n }),\n );\n return () => {\n for (const unsubscribe of unsubscribers) unsubscribe();\n };\n }, [uniqueIds, subscribe, enabled, collectionPath, queryKeyPrefix, queryClient, db]);\n\n const absentDelaysKey = absentRetryDelaysMs.join(',');\n const absentDelays = useMemo(\n () => absentDelaysKey.split(',').filter(Boolean).map(Number),\n [absentDelaysKey],\n );\n\n useEffect(() => {\n if (uniqueIds.length === 0) return;\n const releases = uniqueIds.map((id) =>\n trackAbsentDoc({ queryClient, queryKey: [queryKeyPrefix, id], delays: absentDelays }),\n );\n return () => {\n for (const release of releases) release();\n };\n }, [uniqueIds, queryKeyPrefix, queryClient, absentDelays]);\n\n // Only the effect writes these refs, so a concurrent render React discards never leaves them on an uncommitted map.\n const committedDataRef = useRef<Record<string, T>>({});\n const committedOutcomesRef = useRef<Record<string, BatchFirestoreDocOutcome<T>>>({});\n\n // TanStack clears a never-answered read's error as its refetch starts, so the failure is held through the retry.\n const retryStates = useReadRetryStates(\n uniqueIds.map((id, index) => ({\n source: (results[index] ?? IDLE_SOURCE) as ReadRetrySource<Error>,\n queryKey: [queryKeyPrefix, id],\n })),\n );\n\n const nextData: Record<string, T> = {};\n const nextOutcomes: Record<string, BatchFirestoreDocOutcome<T>> = {};\n let anyError: Error | null = null;\n let anyListenerError: Error | null = null;\n let oneShotLoading = false;\n let anyUnresolved = false;\n let failedReadsRunning = false;\n\n for (let index = 0; index < uniqueIds.length; index += 1) {\n const id = uniqueIds[index];\n const result = results[index];\n let outcome: BatchFirestoreDocOutcome<T> = LOADING_OUTCOME;\n const listenerError =\n (subscribe ? subscribeErrors[id] : undefined) ??\n listenerErrorOf(queryClient, queryKeyPrefix, id) ??\n undefined;\n if (\n result &&\n (result.isFetching || result.isPaused) &&\n result.errorUpdatedAt > result.dataUpdatedAt\n ) {\n failedReadsRunning = true;\n }\n const retryState = retryStates[index];\n if (result?.isError) anyError ??= result.error as Error;\n const value = result?.data as T | null | undefined;\n if (retryState && retryState.error !== null) {\n outcome = failedOrHeld(value, retryState.error, retryState.isRetrying);\n } else if (result) {\n if (result.isLoading) oneShotLoading = true;\n if (value === undefined) anyUnresolved = true;\n if (listenerError) {\n anyListenerError ??= listenerError;\n outcome = failedOrHeld(value, listenerError, false);\n } else if (value === null) {\n outcome = ABSENT_OUTCOME;\n } else if (value !== undefined) {\n outcome = { status: 'present', data: value };\n }\n }\n if (outcome.status === 'present') nextData[id] = outcome.data;\n const committed = committedOutcomesRef.current[id];\n nextOutcomes[id] = committed && sameOutcome(committed, outcome) ? committed : outcome;\n }\n\n const data = shallowRecordEqual(committedDataRef.current, nextData)\n ? committedDataRef.current\n : nextData;\n const outcomes = shallowRecordEqual(committedOutcomesRef.current, nextOutcomes)\n ? committedOutcomesRef.current\n : nextOutcomes;\n\n useEffect(() => {\n committedDataRef.current = data;\n committedOutcomesRef.current = outcomes;\n }, [data, outcomes]);\n\n const refetch = useCallback(async () => {\n if (subscribe || !enabled) return;\n await Promise.all(\n uniqueIds.map((id) =>\n queryClient.refetchQueries({ queryKey: [queryKeyPrefix, id], exact: true }),\n ),\n );\n }, [uniqueIds, subscribe, enabled, queryClient, queryKeyPrefix]);\n\n const isLoading = subscribe ? enabled && anyUnresolved : oneShotLoading;\n\n return {\n data,\n isLoading,\n isError: anyError !== null || anyListenerError !== null,\n error: anyError ?? anyListenerError,\n outcomes,\n failedReadsRunning,\n refetch,\n };\n}\n"]}
@@ -28,7 +28,8 @@ export type { FirestoreDocOptions, FirestoreCollectionOptions, FirestoreInfinite
28
28
  export { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';
29
29
  export type { FirestoreSearchOptions } from './search/types.js';
30
30
  export { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';
31
- export type { ReadRetryEntry, ReadRetrySource, ReadRetryState } from './use-read-retry-state.js';
31
+ export type { ReadRetryEntry } from './use-read-retry-state.js';
32
+ export type { ReadRetrySource, ReadRetryState } from './read-retry-derivation.js';
32
33
  export { MutationSessionProvider, MutationSessionEndedError, useSessionMutation, } from './session-mutation.js';
33
34
  export type { MutationSession, MutationSessionProviderProps, SessionMutateOptions, SessionMutationFunctionContext, SessionMutationOptions, SessionMutationResult, } from './session-mutation.js';
34
35
  export { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAGtF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAM7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAC;AAClG,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAYjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5F,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGlF,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAU/B,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAWvF,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC","sourcesContent":["'use client';\n\nexport { createQueryClient } from './query-client.js';\nexport type { CreateQueryClientOptions } from './query-client.js';\n\nexport { QueryProvider } from './provider.js';\nexport type { QueryProviderProps } from './provider.js';\n\nexport { FirestoreProvider, useFirestoreDb } from './firestore/context.js';\nexport type { FirestoreProviderProps } from './firestore/context.js';\n\nexport { useFirestoreDoc } from './firestore/use-firestore-doc.js';\nexport { useFirestoreCollection } from './firestore/use-firestore-collection.js';\nexport { useFirestoreInfinite } from './firestore/use-firestore-infinite.js';\nexport { useFirestorePaginated } from './firestore/use-firestore-paginated.js';\nexport type { UseFirestorePaginatedResult } from './firestore/use-firestore-paginated.js';\nexport { useFirestoreCount } from './firestore/use-firestore-count.js';\nexport { useFirestoreLiveInfinite } from './firestore/use-firestore-live-infinite.js';\nexport type { FirestoreLiveInfiniteResult } from './firestore/use-firestore-live-infinite.js';\n\nexport {\n useFirestoreSet,\n useFirestoreUpdate,\n useFirestoreDelete,\n useFirestoreBatch,\n} from './firestore/use-firestore-mutations.js';\n\nexport { useBatchFirestoreDocs } from './firestore/useBatchFirestoreDocs.js';\nexport type {\n BatchFirestoreDocsOptions,\n BatchFirestoreDocsResult,\n BatchFirestoreDocsTransport,\n} from './firestore/useBatchFirestoreDocs.js';\nexport { ABSENT_RETRY_DELAYS_MS } from './firestore/absence-scheduler.js';\n\nexport { useFirestoreSearch } from './search/use-firestore-search.js';\n\nexport {\n invalidateByPrefix,\n removeByPrefix,\n updateQueryData,\n paginatedPageKey,\n mapPaginatedItems,\n prependToFirstPaginatedPage,\n placeRowInPages,\n} from './cache-helpers.js';\nexport type { PagedRows } from './cache-helpers.js';\n\nexport { createDomainEventInvalidator } from './domain-events/create-domain-event-invalidator.js';\nexport {\n exact,\n prefix,\n predicate,\n serializeInvalidation,\n applyInvalidations,\n} from './domain-events/cache-invalidation.js';\nexport type {\n DomainEventInvalidator,\n DomainEventInvalidationRegistry,\n} from './domain-events/create-domain-event-invalidator.js';\nexport type {\n CacheAction,\n CacheInvalidation,\n RefetchType,\n} from './domain-events/cache-invalidation.js';\n\nexport { docWithId } from './firestore/types.js';\nexport type {\n FirestoreDocOptions,\n FirestoreCollectionOptions,\n FirestoreInfiniteOptions,\n FirestorePaginatedOptions,\n FirestoreCountOptions,\n FirestoreLiveInfiniteOptions,\n InfinitePage,\n PaginatedPage,\n MutationOperation,\n} from './firestore/types.js';\nexport { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';\nexport type { FirestoreSearchOptions } from './search/types.js';\n\nexport { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';\nexport type { ReadRetryEntry, ReadRetrySource, ReadRetryState } from './use-read-retry-state.js';\n\nexport {\n MutationSessionProvider,\n MutationSessionEndedError,\n useSessionMutation,\n} from './session-mutation.js';\nexport type {\n MutationSession,\n MutationSessionProviderProps,\n SessionMutateOptions,\n SessionMutationFunctionContext,\n SessionMutationOptions,\n SessionMutationResult,\n} from './session-mutation.js';\n\nexport { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';\nexport type {\n CallableCaptureContext,\n CallableDeclaration,\n CallableErrorRouting,\n CallableMutationOptions,\n CallablePolicy,\n Callables,\n ResumableOutcome,\n} from './callables/create-callables.js';\n\nexport {\n usePendingMutationVariables,\n pendingMutationVariables,\n usePendingMutationTargets,\n hasPendingMutation,\n duplicateSubmissionError,\n useDuplicateGuardedMutation,\n} from './pending-mutations.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAGtF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAM7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAC;AAClG,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAYjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5F,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAIlF,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAU/B,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAWvF,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC","sourcesContent":["'use client';\n\nexport { createQueryClient } from './query-client.js';\nexport type { CreateQueryClientOptions } from './query-client.js';\n\nexport { QueryProvider } from './provider.js';\nexport type { QueryProviderProps } from './provider.js';\n\nexport { FirestoreProvider, useFirestoreDb } from './firestore/context.js';\nexport type { FirestoreProviderProps } from './firestore/context.js';\n\nexport { useFirestoreDoc } from './firestore/use-firestore-doc.js';\nexport { useFirestoreCollection } from './firestore/use-firestore-collection.js';\nexport { useFirestoreInfinite } from './firestore/use-firestore-infinite.js';\nexport { useFirestorePaginated } from './firestore/use-firestore-paginated.js';\nexport type { UseFirestorePaginatedResult } from './firestore/use-firestore-paginated.js';\nexport { useFirestoreCount } from './firestore/use-firestore-count.js';\nexport { useFirestoreLiveInfinite } from './firestore/use-firestore-live-infinite.js';\nexport type { FirestoreLiveInfiniteResult } from './firestore/use-firestore-live-infinite.js';\n\nexport {\n useFirestoreSet,\n useFirestoreUpdate,\n useFirestoreDelete,\n useFirestoreBatch,\n} from './firestore/use-firestore-mutations.js';\n\nexport { useBatchFirestoreDocs } from './firestore/useBatchFirestoreDocs.js';\nexport type {\n BatchFirestoreDocsOptions,\n BatchFirestoreDocsResult,\n BatchFirestoreDocsTransport,\n} from './firestore/useBatchFirestoreDocs.js';\nexport { ABSENT_RETRY_DELAYS_MS } from './firestore/absence-scheduler.js';\n\nexport { useFirestoreSearch } from './search/use-firestore-search.js';\n\nexport {\n invalidateByPrefix,\n removeByPrefix,\n updateQueryData,\n paginatedPageKey,\n mapPaginatedItems,\n prependToFirstPaginatedPage,\n placeRowInPages,\n} from './cache-helpers.js';\nexport type { PagedRows } from './cache-helpers.js';\n\nexport { createDomainEventInvalidator } from './domain-events/create-domain-event-invalidator.js';\nexport {\n exact,\n prefix,\n predicate,\n serializeInvalidation,\n applyInvalidations,\n} from './domain-events/cache-invalidation.js';\nexport type {\n DomainEventInvalidator,\n DomainEventInvalidationRegistry,\n} from './domain-events/create-domain-event-invalidator.js';\nexport type {\n CacheAction,\n CacheInvalidation,\n RefetchType,\n} from './domain-events/cache-invalidation.js';\n\nexport { docWithId } from './firestore/types.js';\nexport type {\n FirestoreDocOptions,\n FirestoreCollectionOptions,\n FirestoreInfiniteOptions,\n FirestorePaginatedOptions,\n FirestoreCountOptions,\n FirestoreLiveInfiniteOptions,\n InfinitePage,\n PaginatedPage,\n MutationOperation,\n} from './firestore/types.js';\nexport { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';\nexport type { FirestoreSearchOptions } from './search/types.js';\n\nexport { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';\nexport type { ReadRetryEntry } from './use-read-retry-state.js';\nexport type { ReadRetrySource, ReadRetryState } from './read-retry-derivation.js';\n\nexport {\n MutationSessionProvider,\n MutationSessionEndedError,\n useSessionMutation,\n} from './session-mutation.js';\nexport type {\n MutationSession,\n MutationSessionProviderProps,\n SessionMutateOptions,\n SessionMutationFunctionContext,\n SessionMutationOptions,\n SessionMutationResult,\n} from './session-mutation.js';\n\nexport { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';\nexport type {\n CallableCaptureContext,\n CallableDeclaration,\n CallableErrorRouting,\n CallableMutationOptions,\n CallablePolicy,\n Callables,\n ResumableOutcome,\n} from './callables/create-callables.js';\n\nexport {\n usePendingMutationVariables,\n pendingMutationVariables,\n usePendingMutationTargets,\n hasPendingMutation,\n duplicateSubmissionError,\n useDuplicateGuardedMutation,\n} from './pending-mutations.js';\n"]}
@@ -0,0 +1,17 @@
1
+ export interface ReadRetrySource<TError = Error> {
2
+ error: TError | null | undefined;
3
+ isFetching: boolean;
4
+ isLoading: boolean;
5
+ isPaused?: boolean;
6
+ }
7
+ export interface ReadRetryState<TError = Error> {
8
+ error: TError | null;
9
+ isRetrying: boolean;
10
+ isLoading: boolean;
11
+ }
12
+ export interface HeldFailure<TError> {
13
+ error: TError;
14
+ }
15
+ export declare function nextHeldFailure<TError>(held: HeldFailure<TError> | undefined, source: ReadRetrySource<TError>): HeldFailure<TError> | undefined;
16
+ export declare function toRetryState<TError>(source: ReadRetrySource<TError>, held: HeldFailure<TError> | undefined): ReadRetryState<TError>;
17
+ //# sourceMappingURL=read-retry-derivation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-retry-derivation.d.ts","sourceRoot":"","sources":["../../src/react/read-retry-derivation.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe,CAAC,MAAM,GAAG,KAAK;IAC7C,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc,CAAC,MAAM,GAAG,KAAK;IAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,WAAW,CAAC,MAAM;IACjC,KAAK,EAAE,MAAM,CAAC;CACf;AAWD,wBAAgB,eAAe,CAAC,MAAM,EACpC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,EACrC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,GAC9B,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,CAMjC;AAED,wBAAgB,YAAY,CAAC,MAAM,EACjC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAC/B,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,GACpC,cAAc,CAAC,MAAM,CAAC,CAOxB"}
@@ -0,0 +1,26 @@
1
+ /** A composite source builds a new error object every render, so a failure is compared by name, message, and `code`. */
2
+ function sameFailure(a, b) {
3
+ if (a === b)
4
+ return true;
5
+ if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null)
6
+ return false;
7
+ const x = a;
8
+ const y = b;
9
+ return x.name === y.name && x.message === y.message && x.code === y.code;
10
+ }
11
+ export function nextHeldFailure(held, source) {
12
+ const live = source.error ?? null;
13
+ if (live !== null)
14
+ return held !== undefined && sameFailure(held.error, live) ? held : { error: live };
15
+ const running = source.isFetching || source.isPaused === true;
16
+ return running ? held : undefined;
17
+ }
18
+ export function toRetryState(source, held) {
19
+ const error = source.error ?? held?.error ?? null;
20
+ return {
21
+ error,
22
+ isRetrying: error !== null && (source.isFetching || source.isPaused === true),
23
+ isLoading: error === null && source.isLoading,
24
+ };
25
+ }
26
+ //# sourceMappingURL=read-retry-derivation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-retry-derivation.js","sourceRoot":"","sources":["../../src/react/read-retry-derivation.ts"],"names":[],"mappings":"AAiBA,wHAAwH;AACxH,SAAS,WAAW,CAAC,CAAU,EAAE,CAAU;IACzC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC7F,MAAM,CAAC,GAAG,CAA0D,CAAC;IACrE,MAAM,CAAC,GAAG,CAA0D,CAAC;IACrE,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,IAAqC,EACrC,MAA+B;IAE/B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC;IAClC,IAAI,IAAI,KAAK,IAAI;QACf,OAAO,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACtF,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;IAC9D,OAAO,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAA+B,EAC/B,IAAqC;IAErC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI,IAAI,CAAC;IAClD,OAAO;QACL,KAAK;QACL,UAAU,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;QAC7E,SAAS,EAAE,KAAK,KAAK,IAAI,IAAI,MAAM,CAAC,SAAS;KAC9C,CAAC;AACJ,CAAC","sourcesContent":["export interface ReadRetrySource<TError = Error> {\n error: TError | null | undefined;\n isFetching: boolean;\n isLoading: boolean;\n isPaused?: boolean;\n}\n\nexport interface ReadRetryState<TError = Error> {\n error: TError | null;\n isRetrying: boolean;\n isLoading: boolean;\n}\n\nexport interface HeldFailure<TError> {\n error: TError;\n}\n\n/** A composite source builds a new error object every render, so a failure is compared by name, message, and `code`. */\nfunction sameFailure(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) return false;\n const x = a as { name?: unknown; message?: unknown; code?: unknown };\n const y = b as { name?: unknown; message?: unknown; code?: unknown };\n return x.name === y.name && x.message === y.message && x.code === y.code;\n}\n\nexport function nextHeldFailure<TError>(\n held: HeldFailure<TError> | undefined,\n source: ReadRetrySource<TError>,\n): HeldFailure<TError> | undefined {\n const live = source.error ?? null;\n if (live !== null)\n return held !== undefined && sameFailure(held.error, live) ? held : { error: live };\n const running = source.isFetching || source.isPaused === true;\n return running ? held : undefined;\n}\n\nexport function toRetryState<TError>(\n source: ReadRetrySource<TError>,\n held: HeldFailure<TError> | undefined,\n): ReadRetryState<TError> {\n const error = source.error ?? held?.error ?? null;\n return {\n error,\n isRetrying: error !== null && (source.isFetching || source.isPaused === true),\n isLoading: error === null && source.isLoading,\n };\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { Firestore } from 'firebase/firestore';
3
+ import { QueryClient } from '@tanstack/react-query';
4
+ export interface FirestoreTestWrapper {
5
+ queryClient: QueryClient;
6
+ Wrapper: (props: {
7
+ children: ReactNode;
8
+ }) => ReactNode;
9
+ }
10
+ export declare function testQueryClient(): QueryClient;
11
+ export declare function firestoreTestWrapper(db: Firestore, { queryClient }?: {
12
+ queryClient?: QueryClient;
13
+ }): FirestoreTestWrapper;
14
+ //# sourceMappingURL=firestore-test-wrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firestore-test-wrapper.d.ts","sourceRoot":"","sources":["../../../src/react/testing/firestore-test-wrapper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAuB,MAAM,uBAAuB,CAAC;AAGzE,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,KAAK,SAAS,CAAC;CACxD;AAED,wBAAgB,eAAe,IAAI,WAAW,CAE7C;AAED,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,SAAS,EACb,EAAE,WAA+B,EAAE,GAAE;IAAE,WAAW,CAAC,EAAE,WAAW,CAAA;CAAO,GACtE,oBAAoB,CAQtB"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
+ import { FirestoreProvider } from '../firestore/context.js';
4
+ export function testQueryClient() {
5
+ return new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: Infinity } } });
6
+ }
7
+ export function firestoreTestWrapper(db, { queryClient = testQueryClient() } = {}) {
8
+ const Wrapper = ({ children }) => (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(FirestoreProvider, { db: db, children: children }) }));
9
+ Wrapper.displayName = 'FirestoreTestWrapper';
10
+ return { queryClient, Wrapper };
11
+ }
12
+ //# sourceMappingURL=firestore-test-wrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firestore-test-wrapper.js","sourceRoot":"","sources":["../../../src/react/testing/firestore-test-wrapper.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAO5D,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,WAAW,CAAC,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,EAAa,EACb,EAAE,WAAW,GAAG,eAAe,EAAE,KAAoC,EAAE;IAEvE,MAAM,OAAO,GAAG,CAAC,EAAE,QAAQ,EAA2B,EAAE,EAAE,CAAC,CACzD,KAAC,mBAAmB,IAAC,MAAM,EAAE,WAAW,YACtC,KAAC,iBAAiB,IAAC,EAAE,EAAE,EAAE,YAAG,QAAQ,GAAqB,GACrC,CACvB,CAAC;IACF,OAAO,CAAC,WAAW,GAAG,sBAAsB,CAAC;IAC7C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC","sourcesContent":["import type { ReactNode } from 'react';\nimport type { Firestore } from 'firebase/firestore';\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport { FirestoreProvider } from '../firestore/context.js';\n\nexport interface FirestoreTestWrapper {\n queryClient: QueryClient;\n Wrapper: (props: { children: ReactNode }) => ReactNode;\n}\n\nexport function testQueryClient(): QueryClient {\n return new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: Infinity } } });\n}\n\nexport function firestoreTestWrapper(\n db: Firestore,\n { queryClient = testQueryClient() }: { queryClient?: QueryClient } = {},\n): FirestoreTestWrapper {\n const Wrapper = ({ children }: { children: ReactNode }) => (\n <QueryClientProvider client={queryClient}>\n <FirestoreProvider db={db}>{children}</FirestoreProvider>\n </QueryClientProvider>\n );\n Wrapper.displayName = 'FirestoreTestWrapper';\n return { queryClient, Wrapper };\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export * from './read-builders.js';
2
+ export * from './paginated-read-builders.js';
3
+ export * from './mutation-builders.js';
4
+ export * from './firestore-test-wrapper.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/testing/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './read-builders.js';
2
+ export * from './paginated-read-builders.js';
3
+ export * from './mutation-builders.js';
4
+ export * from './firestore-test-wrapper.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react/testing/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC","sourcesContent":["export * from './read-builders.js';\nexport * from './paginated-read-builders.js';\nexport * from './mutation-builders.js';\nexport * from './firestore-test-wrapper.js';\n"]}
@@ -0,0 +1,18 @@
1
+ import { type DefaultError, type UseMutationResult } from '@tanstack/react-query';
2
+ import type { SessionMutationFunctionContext, SessionMutationResult } from '../session-mutation.js';
3
+ export interface MutationHandlers<TData, TVariables, TOnMutateResult = unknown, TError = DefaultError> {
4
+ mutate?: UseMutationResult<TData, TError, TVariables, TOnMutateResult>['mutate'];
5
+ mutateAsync?: UseMutationResult<TData, TError, TVariables, TOnMutateResult>['mutateAsync'];
6
+ }
7
+ export interface SessionMutationHandlers<TData, TVariables, TOnMutateResult = unknown, TError = DefaultError> {
8
+ mutate?: SessionMutationResult<TData, TError, TVariables, TOnMutateResult>['mutate'];
9
+ mutateAsync?: SessionMutationResult<TData, TError, TVariables, TOnMutateResult>['mutateAsync'];
10
+ }
11
+ export declare function idleMutation<TData, TVariables, TOnMutateResult = unknown, TError = DefaultError>(handlers?: MutationHandlers<TData, TVariables, TOnMutateResult, TError>): UseMutationResult<TData, TError, TVariables, TOnMutateResult>;
12
+ export declare function pendingMutation<TData, TVariables, TOnMutateResult = unknown, TError = DefaultError>(variables: TVariables, handlers?: MutationHandlers<TData, TVariables, TOnMutateResult, TError>): UseMutationResult<TData, TError, TVariables, TOnMutateResult>;
13
+ export declare function failedMutation<TData, TVariables, TOnMutateResult = unknown, TError = DefaultError>(error: TError, variables: TVariables, handlers?: MutationHandlers<TData, TVariables, TOnMutateResult, TError>): Promise<UseMutationResult<TData, TError, TVariables, TOnMutateResult>>;
14
+ export declare const idleSessionMutation: <TData, TVariables, TOnMutateResult = unknown, TError = DefaultError>(handlers?: SessionMutationHandlers<TData, TVariables, TOnMutateResult, TError>) => SessionMutationResult<TData, TError, TVariables, TOnMutateResult>;
15
+ export declare const pendingSessionMutation: <TData, TVariables, TOnMutateResult = unknown, TError = DefaultError>(variables: TVariables, handlers?: SessionMutationHandlers<TData, TVariables, TOnMutateResult, TError>) => SessionMutationResult<TData, TError, TVariables, TOnMutateResult>;
16
+ export declare const failedSessionMutation: <TData, TVariables, TOnMutateResult = unknown, TError = DefaultError>(error: TError, variables: TVariables, handlers?: SessionMutationHandlers<TData, TVariables, TOnMutateResult, TError>) => Promise<SessionMutationResult<TData, TError, TVariables, TOnMutateResult>>;
17
+ export declare function sessionMutationContext(uid: string | null): SessionMutationFunctionContext;
18
+ //# sourceMappingURL=mutation-builders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation-builders.d.ts","sourceRoot":"","sources":["../../../src/react/testing/mutation-builders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { MutationObserver, QueryClient, } from '@tanstack/react-query';
2
+ const notRunInTest = () => Promise.reject(new Error('this mutation is not run in the test; pass the case its own handler'));
3
+ function observer(mutationFn) {
4
+ return new MutationObserver(new QueryClient(), mutationFn ? { mutationFn } : {});
5
+ }
6
+ function withHandlers(result, handlers) {
7
+ return {
8
+ ...result,
9
+ mutate: handlers.mutate ?? (() => { }),
10
+ mutateAsync: handlers.mutateAsync ?? notRunInTest,
11
+ };
12
+ }
13
+ export function idleMutation(handlers = {}) {
14
+ const idle = observer();
15
+ return withHandlers(idle.getCurrentResult(), handlers);
16
+ }
17
+ export function pendingMutation(variables, handlers = {}) {
18
+ const running = observer(() => new Promise(() => { }));
19
+ void running.mutate(variables);
20
+ return withHandlers(running.getCurrentResult(), handlers);
21
+ }
22
+ export async function failedMutation(error, variables, handlers = {}) {
23
+ const failing = observer(() => Promise.reject(error));
24
+ // The rejection is the failed state this builder returns.
25
+ await failing.mutate(variables).catch(() => undefined);
26
+ return withHandlers(failing.getCurrentResult(), handlers);
27
+ }
28
+ function asSession(result, handlers) {
29
+ return {
30
+ ...result,
31
+ mutate: handlers.mutate ?? (() => { }),
32
+ mutateAsync: handlers.mutateAsync ?? notRunInTest,
33
+ };
34
+ }
35
+ export const idleSessionMutation = (handlers = {}) => asSession(idleMutation(), handlers);
36
+ export const pendingSessionMutation = (variables, handlers = {}) => asSession(pendingMutation(variables), handlers);
37
+ export const failedSessionMutation = async (error, variables, handlers = {}) => asSession(await failedMutation(error, variables), handlers);
38
+ export function sessionMutationContext(uid) {
39
+ return {
40
+ client: new QueryClient(),
41
+ meta: undefined,
42
+ session: { uid, isCurrent: () => true, assertCurrent: () => { } },
43
+ };
44
+ }
45
+ //# sourceMappingURL=mutation-builders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutation-builders.js","sourceRoot":"","sources":["../../../src/react/testing/mutation-builders.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n MutationObserver,\n QueryClient,\n type DefaultError,\n type MutationObserverResult,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport type { SessionMutationFunctionContext, SessionMutationResult } from '../session-mutation.js';\n\nexport interface MutationHandlers<\n TData,\n TVariables,\n TOnMutateResult = unknown,\n TError = DefaultError,\n> {\n mutate?: UseMutationResult<TData, TError, TVariables, TOnMutateResult>['mutate'];\n mutateAsync?: UseMutationResult<TData, TError, TVariables, TOnMutateResult>['mutateAsync'];\n}\n\nexport interface SessionMutationHandlers<\n TData,\n TVariables,\n TOnMutateResult = unknown,\n TError = DefaultError,\n> {\n mutate?: SessionMutationResult<TData, TError, TVariables, TOnMutateResult>['mutate'];\n mutateAsync?: SessionMutationResult<TData, TError, TVariables, TOnMutateResult>['mutateAsync'];\n}\n\nconst notRunInTest = (): Promise<never> =>\n Promise.reject(new Error('this mutation is not run in the test; pass the case its own handler'));\n\nfunction observer<TData, TVariables, TOnMutateResult, TError>(mutationFn?: () => Promise<TData>) {\n return new MutationObserver<TData, TError, TVariables, TOnMutateResult>(\n new QueryClient(),\n mutationFn ? { mutationFn } : {},\n );\n}\n\nfunction withHandlers<TData, TVariables, TOnMutateResult, TError>(\n result: MutationObserverResult<TData, TError, TVariables, TOnMutateResult>,\n handlers: MutationHandlers<TData, TVariables, TOnMutateResult, TError>,\n): UseMutationResult<TData, TError, TVariables, TOnMutateResult> {\n return {\n ...result,\n mutate: handlers.mutate ?? (() => {}),\n mutateAsync: handlers.mutateAsync ?? notRunInTest,\n };\n}\n\nexport function idleMutation<TData, TVariables, TOnMutateResult = unknown, TError = DefaultError>(\n handlers: MutationHandlers<TData, TVariables, TOnMutateResult, TError> = {},\n): UseMutationResult<TData, TError, TVariables, TOnMutateResult> {\n const idle = observer<TData, TVariables, TOnMutateResult, TError>();\n return withHandlers(idle.getCurrentResult(), handlers);\n}\n\nexport function pendingMutation<\n TData,\n TVariables,\n TOnMutateResult = unknown,\n TError = DefaultError,\n>(\n variables: TVariables,\n handlers: MutationHandlers<TData, TVariables, TOnMutateResult, TError> = {},\n): UseMutationResult<TData, TError, TVariables, TOnMutateResult> {\n const running = observer<TData, TVariables, TOnMutateResult, TError>(\n () => new Promise<TData>(() => {}),\n );\n void running.mutate(variables);\n return withHandlers(running.getCurrentResult(), handlers);\n}\n\nexport async function failedMutation<\n TData,\n TVariables,\n TOnMutateResult = unknown,\n TError = DefaultError,\n>(\n error: TError,\n variables: TVariables,\n handlers: MutationHandlers<TData, TVariables, TOnMutateResult, TError> = {},\n): Promise<UseMutationResult<TData, TError, TVariables, TOnMutateResult>> {\n const failing = observer<TData, TVariables, TOnMutateResult, TError>(() => Promise.reject(error));\n // The rejection is the failed state this builder returns.\n await failing.mutate(variables).catch(() => undefined);\n return withHandlers(failing.getCurrentResult(), handlers);\n}\n\nfunction asSession<TData, TVariables, TOnMutateResult, TError>(\n result: UseMutationResult<TData, TError, TVariables, TOnMutateResult>,\n handlers: SessionMutationHandlers<TData, TVariables, TOnMutateResult, TError>,\n): SessionMutationResult<TData, TError, TVariables, TOnMutateResult> {\n return {\n ...result,\n mutate: handlers.mutate ?? (() => {}),\n mutateAsync: handlers.mutateAsync ?? notRunInTest,\n };\n}\n\nexport const idleSessionMutation = <\n TData,\n TVariables,\n TOnMutateResult = unknown,\n TError = DefaultError,\n>(\n handlers: SessionMutationHandlers<TData, TVariables, TOnMutateResult, TError> = {},\n): SessionMutationResult<TData, TError, TVariables, TOnMutateResult> =>\n asSession(idleMutation<TData, TVariables, TOnMutateResult, TError>(), handlers);\n\nexport const pendingSessionMutation = <\n TData,\n TVariables,\n TOnMutateResult = unknown,\n TError = DefaultError,\n>(\n variables: TVariables,\n handlers: SessionMutationHandlers<TData, TVariables, TOnMutateResult, TError> = {},\n): SessionMutationResult<TData, TError, TVariables, TOnMutateResult> =>\n asSession(pendingMutation<TData, TVariables, TOnMutateResult, TError>(variables), handlers);\n\nexport const failedSessionMutation = async <\n TData,\n TVariables,\n TOnMutateResult = unknown,\n TError = DefaultError,\n>(\n error: TError,\n variables: TVariables,\n handlers: SessionMutationHandlers<TData, TVariables, TOnMutateResult, TError> = {},\n): Promise<SessionMutationResult<TData, TError, TVariables, TOnMutateResult>> =>\n asSession(\n await failedMutation<TData, TVariables, TOnMutateResult, TError>(error, variables),\n handlers,\n );\n\nexport function sessionMutationContext(uid: string | null): SessionMutationFunctionContext {\n return {\n client: new QueryClient(),\n meta: undefined,\n session: { uid, isCurrent: () => true, assertCurrent: () => {} },\n };\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import type { UseFirestorePaginatedResult } from '../firestore/use-firestore-paginated.js';
2
+ import type { WithId } from '../../firestore/types.js';
3
+ import type { ReadRetryState } from '../read-retry-derivation.js';
4
+ export type BuiltPaginatedRead<T> = UseFirestorePaginatedResult<T> & {
5
+ retryState: ReadRetryState<Error>;
6
+ };
7
+ export interface PaginatedReadSpec {
8
+ page?: number;
9
+ pageSize?: number;
10
+ hasNextPage?: boolean;
11
+ setPage?: (page: number) => void;
12
+ }
13
+ export declare const answeredPaginatedRead: <T>(items: WithId<T>[], spec?: PaginatedReadSpec) => BuiltPaginatedRead<T>;
14
+ export declare const loadingPaginatedRead: <T>(spec?: PaginatedReadSpec) => BuiltPaginatedRead<T>;
15
+ export declare const failedPaginatedRead: <T>(error: Error, spec?: PaginatedReadSpec) => BuiltPaginatedRead<T>;
16
+ export declare const retryingPaginatedRead: <T>(error: Error, spec?: PaginatedReadSpec) => BuiltPaginatedRead<T>;
17
+ export declare const answeredThenFailedPaginatedRead: <T>(items: WithId<T>[], error: Error, spec?: PaginatedReadSpec) => BuiltPaginatedRead<T>;
18
+ export declare const fetchingPaginatedRead: <T>(items: WithId<T>[], spec?: PaginatedReadSpec) => BuiltPaginatedRead<T>;
19
+ export declare const retryingAnsweredPaginatedRead: <T>(items: WithId<T>[], error: Error, spec?: PaginatedReadSpec) => BuiltPaginatedRead<T>;
20
+ //# sourceMappingURL=paginated-read-builders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginated-read-builders.d.ts","sourceRoot":"","sources":["../../../src/react/testing/paginated-read-builders.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAYlE,MAAM,MAAM,kBAAkB,CAAC,CAAC,IAAI,2BAA2B,CAAC,CAAC,CAAC,GAAG;IACnE,UAAU,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AA4BD,eAAO,MAAM,qBAAqB,GAAI,CAAC,EACrC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,EAClB,OAAM,iBAAsB,KAC3B,kBAAkB,CAAC,CAAC,CAA4E,CAAC;AAEpG,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAE,OAAM,iBAAsB,KAAG,kBAAkB,CAAC,CAAC,CACjC,CAAC;AAE3D,eAAO,MAAM,mBAAmB,GAAI,CAAC,EACnC,OAAO,KAAK,EACZ,OAAM,iBAAsB,KAC3B,kBAAkB,CAAC,CAAC,CAAiE,CAAC;AAEzF,eAAO,MAAM,qBAAqB,GAAI,CAAC,EACrC,OAAO,KAAK,EACZ,OAAM,iBAAsB,KAC3B,kBAAkB,CAAC,CAAC,CAAmE,CAAC;AAE3F,eAAO,MAAM,+BAA+B,GAAI,CAAC,EAC/C,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,EAClB,OAAO,KAAK,EACZ,OAAM,iBAAsB,KAC3B,kBAAkB,CAAC,CAAC,CACmE,CAAC;AAE3F,eAAO,MAAM,qBAAqB,GAAI,CAAC,EACrC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,EAClB,OAAM,iBAAsB,KAC3B,kBAAkB,CAAC,CAAC,CAA4E,CAAC;AAEpG,eAAO,MAAM,6BAA6B,GAAI,CAAC,EAC7C,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,EAClB,OAAO,KAAK,EACZ,OAAM,iBAAsB,KAC3B,kBAAkB,CAAC,CAAC,CACiE,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { answeredRead, answeredThenFailedRead, failedRead, fetchingRead, loadingRead, retryingAnsweredRead, retryingRead, } from './read-builders.js';
2
+ const pageOf = (items, hasMore) => ({
3
+ items,
4
+ cursor: null,
5
+ hasMore,
6
+ after: null,
7
+ });
8
+ function paginated(read, spec) {
9
+ const page = spec.page ?? 1;
10
+ const setPage = spec.setPage ?? (() => { });
11
+ return {
12
+ ...read,
13
+ data: read.data?.items,
14
+ page,
15
+ pageSize: spec.pageSize ?? 10,
16
+ hasNextPage: spec.hasNextPage ?? false,
17
+ hasPrevPage: page > 1,
18
+ setPage,
19
+ nextPage: () => setPage(page + 1),
20
+ prevPage: () => setPage(page - 1),
21
+ };
22
+ }
23
+ export const answeredPaginatedRead = (items, spec = {}) => paginated(answeredRead(pageOf(items, spec.hasNextPage ?? false)), spec);
24
+ export const loadingPaginatedRead = (spec = {}) => paginated(loadingRead(), spec);
25
+ export const failedPaginatedRead = (error, spec = {}) => paginated(failedRead(error), spec);
26
+ export const retryingPaginatedRead = (error, spec = {}) => paginated(retryingRead(error), spec);
27
+ export const answeredThenFailedPaginatedRead = (items, error, spec = {}) => paginated(answeredThenFailedRead(pageOf(items, spec.hasNextPage ?? false), error), spec);
28
+ export const fetchingPaginatedRead = (items, spec = {}) => paginated(fetchingRead(pageOf(items, spec.hasNextPage ?? false)), spec);
29
+ export const retryingAnsweredPaginatedRead = (items, error, spec = {}) => paginated(retryingAnsweredRead(pageOf(items, spec.hasNextPage ?? false), error), spec);
30
+ //# sourceMappingURL=paginated-read-builders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginated-read-builders.js","sourceRoot":"","sources":["../../../src/react/testing/paginated-read-builders.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,YAAY,GAEb,MAAM,oBAAoB,CAAC;AAa5B,MAAM,MAAM,GAAG,CAAI,KAAkB,EAAE,OAAgB,EAA4B,EAAE,CAAC,CAAC;IACrF,KAAK;IACL,MAAM,EAAE,IAAI;IACZ,OAAO;IACP,KAAK,EAAE,IAAI;CACZ,CAAC,CAAC;AAEH,SAAS,SAAS,CAChB,IAAyC,EACzC,IAAuB;IAEvB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC3C,OAAO;QACL,GAAG,IAAI;QACP,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK;QACtB,IAAI;QACJ,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;QAC7B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,KAAK;QACtC,WAAW,EAAE,IAAI,GAAG,CAAC;QACrB,OAAO;QACP,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;QACjC,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;KAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,KAAkB,EAClB,OAA0B,EAAE,EACL,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAEpG,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAI,OAA0B,EAAE,EAAyB,EAAE,CAC7F,SAAS,CAAC,WAAW,EAA4B,EAAE,IAAI,CAAC,CAAC;AAE3D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,KAAY,EACZ,OAA0B,EAAE,EACL,EAAE,CAAC,SAAS,CAAC,UAAU,CAA2B,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AAEzF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,KAAY,EACZ,OAA0B,EAAE,EACL,EAAE,CAAC,SAAS,CAAC,YAAY,CAA2B,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AAE3F,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,KAAkB,EAClB,KAAY,EACZ,OAA0B,EAAE,EACL,EAAE,CACzB,SAAS,CAAC,sBAAsB,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AAE3F,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,KAAkB,EAClB,OAA0B,EAAE,EACL,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAEpG,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,KAAkB,EAClB,KAAY,EACZ,OAA0B,EAAE,EACL,EAAE,CACzB,SAAS,CAAC,oBAAoB,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,KAAK,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC","sourcesContent":["import type { PaginatedPage } from '../firestore/types.js';\nimport type { UseFirestorePaginatedResult } from '../firestore/use-firestore-paginated.js';\nimport type { WithId } from '../../firestore/types.js';\nimport type { ReadRetryState } from '../read-retry-derivation.js';\nimport {\n answeredRead,\n answeredThenFailedRead,\n failedRead,\n fetchingRead,\n loadingRead,\n retryingAnsweredRead,\n retryingRead,\n type BuiltRead,\n} from './read-builders.js';\n\nexport type BuiltPaginatedRead<T> = UseFirestorePaginatedResult<T> & {\n retryState: ReadRetryState<Error>;\n};\n\nexport interface PaginatedReadSpec {\n page?: number;\n pageSize?: number;\n hasNextPage?: boolean;\n setPage?: (page: number) => void;\n}\n\nconst pageOf = <T>(items: WithId<T>[], hasMore: boolean): PaginatedPage<WithId<T>> => ({\n items,\n cursor: null,\n hasMore,\n after: null,\n});\n\nfunction paginated<T>(\n read: BuiltRead<PaginatedPage<WithId<T>>>,\n spec: PaginatedReadSpec,\n): BuiltPaginatedRead<T> {\n const page = spec.page ?? 1;\n const setPage = spec.setPage ?? (() => {});\n return {\n ...read,\n data: read.data?.items,\n page,\n pageSize: spec.pageSize ?? 10,\n hasNextPage: spec.hasNextPage ?? false,\n hasPrevPage: page > 1,\n setPage,\n nextPage: () => setPage(page + 1),\n prevPage: () => setPage(page - 1),\n };\n}\n\nexport const answeredPaginatedRead = <T>(\n items: WithId<T>[],\n spec: PaginatedReadSpec = {},\n): BuiltPaginatedRead<T> => paginated(answeredRead(pageOf(items, spec.hasNextPage ?? false)), spec);\n\nexport const loadingPaginatedRead = <T>(spec: PaginatedReadSpec = {}): BuiltPaginatedRead<T> =>\n paginated(loadingRead<PaginatedPage<WithId<T>>>(), spec);\n\nexport const failedPaginatedRead = <T>(\n error: Error,\n spec: PaginatedReadSpec = {},\n): BuiltPaginatedRead<T> => paginated(failedRead<PaginatedPage<WithId<T>>>(error), spec);\n\nexport const retryingPaginatedRead = <T>(\n error: Error,\n spec: PaginatedReadSpec = {},\n): BuiltPaginatedRead<T> => paginated(retryingRead<PaginatedPage<WithId<T>>>(error), spec);\n\nexport const answeredThenFailedPaginatedRead = <T>(\n items: WithId<T>[],\n error: Error,\n spec: PaginatedReadSpec = {},\n): BuiltPaginatedRead<T> =>\n paginated(answeredThenFailedRead(pageOf(items, spec.hasNextPage ?? false), error), spec);\n\nexport const fetchingPaginatedRead = <T>(\n items: WithId<T>[],\n spec: PaginatedReadSpec = {},\n): BuiltPaginatedRead<T> => paginated(fetchingRead(pageOf(items, spec.hasNextPage ?? false)), spec);\n\nexport const retryingAnsweredPaginatedRead = <T>(\n items: WithId<T>[],\n error: Error,\n spec: PaginatedReadSpec = {},\n): BuiltPaginatedRead<T> =>\n paginated(retryingAnsweredRead(pageOf(items, spec.hasNextPage ?? false), error), spec);\n"]}
@@ -0,0 +1,49 @@
1
+ import { type InfiniteData, type InfiniteQueryObserverResult, type QueryObserverResult } from '@tanstack/react-query';
2
+ import { type ReadRetryState } from '../read-retry-derivation.js';
3
+ export type BuiltRead<T> = QueryObserverResult<T, Error> & {
4
+ retryState: ReadRetryState<Error>;
5
+ };
6
+ export type BuiltInfiniteRead<TData> = InfiniteQueryObserverResult<TData, Error> & {
7
+ retryState: ReadRetryState<Error>;
8
+ };
9
+ export declare const answeredRead: <T>(data: T) => BuiltRead<T>;
10
+ export declare const idleRead: <T>() => BuiltRead<T>;
11
+ export declare const loadingRead: <T>() => BuiltRead<T>;
12
+ export declare const failedRead: <T>(error: Error) => BuiltRead<T>;
13
+ export declare const retryingRead: <T>(error: Error) => BuiltRead<T>;
14
+ export declare const fetchingRead: <T>(data: T) => BuiltRead<T>;
15
+ export declare const answeredThenFailedRead: <T>(data: T, error: Error) => BuiltRead<T>;
16
+ export declare const retryingAnsweredRead: <T>(data: T, error: Error) => BuiltRead<T>;
17
+ export interface InfiniteReadSpec<TPage, TParam, TData = InfiniteData<TPage, TParam>> {
18
+ pages?: TPage[];
19
+ pageParams?: TParam[];
20
+ initialPageParam: TParam;
21
+ getNextPageParam: (lastPage: TPage, allPages: TPage[]) => TParam | undefined | null;
22
+ select?: (data: InfiniteData<TPage, TParam>) => TData;
23
+ }
24
+ export declare const infiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: InfiniteReadSpec<TPage, TParam, TData> & {
25
+ pages: TPage[];
26
+ }) => BuiltInfiniteRead<TData>;
27
+ export declare const idleInfiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, "pages">) => BuiltInfiniteRead<TData>;
28
+ export declare const loadingInfiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, "pages">) => BuiltInfiniteRead<TData>;
29
+ export declare const failedInfiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, "pages">, error: Error) => BuiltInfiniteRead<TData>;
30
+ export declare const retryingInfiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, "pages">, error: Error) => BuiltInfiniteRead<TData>;
31
+ export declare const fetchingInfiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: InfiniteReadSpec<TPage, TParam, TData> & {
32
+ pages: TPage[];
33
+ }) => BuiltInfiniteRead<TData>;
34
+ export declare const answeredThenFailedInfiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: InfiniteReadSpec<TPage, TParam, TData> & {
35
+ pages: TPage[];
36
+ }, error: Error) => BuiltInfiniteRead<TData>;
37
+ export declare const retryingAnsweredInfiniteRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: InfiniteReadSpec<TPage, TParam, TData> & {
38
+ pages: TPage[];
39
+ }, error: Error) => BuiltInfiniteRead<TData>;
40
+ export declare const fetchingNextPageRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: InfiniteReadSpec<TPage, TParam, TData> & {
41
+ pages: TPage[];
42
+ }) => BuiltInfiniteRead<TData>;
43
+ export declare const nextPageFailedRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: InfiniteReadSpec<TPage, TParam, TData> & {
44
+ pages: TPage[];
45
+ }, error: Error) => BuiltInfiniteRead<TData>;
46
+ export declare const retryingNextPageRead: <TPage, TParam, TData = InfiniteData<TPage, TParam>>(spec: InfiniteReadSpec<TPage, TParam, TData> & {
47
+ pages: TPage[];
48
+ }, error: Error) => BuiltInfiniteRead<TData>;
49
+ //# sourceMappingURL=read-builders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-builders.d.ts","sourceRoot":"","sources":["../../../src/react/testing/read-builders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ import { InfiniteQueryObserver, QueryClient, QueryObserver, } from '@tanstack/react-query';
2
+ import { nextHeldFailure, toRetryState } from '../read-retry-derivation.js';
3
+ const KEY = ['built-read'];
4
+ const notFetchedInTest = () => Promise.reject(new Error('this read is not fetched in the test; pass the case its own refetch'));
5
+ function retryStateOf(result, held) {
6
+ const source = {
7
+ error: result.error,
8
+ isFetching: result.isFetching,
9
+ isLoading: result.isLoading,
10
+ };
11
+ return toRetryState(source, nextHeldFailure(held ? { error: held } : undefined, source));
12
+ }
13
+ function observed(state, held = null) {
14
+ const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
15
+ client.getQueryCache().build(client, { queryKey: KEY }).setState(state);
16
+ const result = new QueryObserver(client, {
17
+ queryKey: KEY,
18
+ queryFn: notFetchedInTest,
19
+ enabled: false,
20
+ }).getCurrentResult();
21
+ return { ...result, retryState: retryStateOf(result, held) };
22
+ }
23
+ const answered = (data) => ({
24
+ data,
25
+ dataUpdatedAt: 1,
26
+ status: 'success',
27
+ });
28
+ const failure = (error) => ({
29
+ error,
30
+ errorUpdatedAt: 2,
31
+ errorUpdateCount: 1,
32
+ fetchFailureCount: 1,
33
+ fetchFailureReason: error,
34
+ status: 'error',
35
+ });
36
+ export const answeredRead = (data) => observed(answered(data));
37
+ export const idleRead = () => observed({});
38
+ export const loadingRead = () => observed({ fetchStatus: 'fetching' });
39
+ export const failedRead = (error) => observed(failure(error));
40
+ export const retryingRead = (error) => observed({ status: 'pending', fetchStatus: 'fetching', error: null }, error);
41
+ export const fetchingRead = (data) => observed({ ...answered(data), fetchStatus: 'fetching' });
42
+ export const answeredThenFailedRead = (data, error) => observed({ ...answered(data), ...failure(error) });
43
+ export const retryingAnsweredRead = (data, error) => observed({ ...answered(data), ...failure(error), fetchStatus: 'fetching' });
44
+ function pageParamsOf(spec, pages) {
45
+ const params = [spec.initialPageParam];
46
+ for (let i = 1; i < pages.length; i++) {
47
+ const next = spec.getNextPageParam(pages[i - 1], pages.slice(0, i));
48
+ if (next === undefined || next === null)
49
+ throw new Error(`page ${i} has no page param: getNextPageParam ends the list before it`);
50
+ params.push(next);
51
+ }
52
+ return params;
53
+ }
54
+ function observedInfinite(spec, state, held = null) {
55
+ const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
56
+ const pages = spec.pages;
57
+ client
58
+ .getQueryCache()
59
+ .build(client, { queryKey: KEY })
60
+ .setState({
61
+ ...(pages
62
+ ? {
63
+ data: {
64
+ pages,
65
+ pageParams: spec.pageParams ?? pageParamsOf(spec, pages),
66
+ },
67
+ dataUpdatedAt: 1,
68
+ status: 'success',
69
+ }
70
+ : {}),
71
+ ...state,
72
+ });
73
+ const result = new InfiniteQueryObserver(client, {
74
+ queryKey: KEY,
75
+ queryFn: notFetchedInTest,
76
+ initialPageParam: spec.initialPageParam,
77
+ getNextPageParam: spec.getNextPageParam,
78
+ ...(spec.select ? { select: spec.select } : {}),
79
+ enabled: false,
80
+ }).getCurrentResult();
81
+ return { ...result, retryState: retryStateOf(result, held) };
82
+ }
83
+ const FORWARD = { fetchMore: { direction: 'forward' } };
84
+ export const infiniteRead = (spec) => observedInfinite(spec, {});
85
+ export const idleInfiniteRead = (spec) => observedInfinite(spec, {});
86
+ export const loadingInfiniteRead = (spec) => observedInfinite(spec, { fetchStatus: 'fetching' });
87
+ export const failedInfiniteRead = (spec, error) => observedInfinite(spec, failure(error));
88
+ export const retryingInfiniteRead = (spec, error) => observedInfinite(spec, { status: 'pending', fetchStatus: 'fetching', error: null }, error);
89
+ export const fetchingInfiniteRead = (spec) => observedInfinite(spec, { fetchStatus: 'fetching' });
90
+ export const answeredThenFailedInfiniteRead = (spec, error) => observedInfinite(spec, failure(error));
91
+ export const retryingAnsweredInfiniteRead = (spec, error) => observedInfinite(spec, { ...failure(error), fetchStatus: 'fetching' });
92
+ export const fetchingNextPageRead = (spec) => observedInfinite(spec, { fetchStatus: 'fetching', fetchMeta: FORWARD });
93
+ export const nextPageFailedRead = (spec, error) => observedInfinite(spec, { ...failure(error), fetchMeta: FORWARD });
94
+ export const retryingNextPageRead = (spec, error) => observedInfinite(spec, { ...failure(error), fetchStatus: 'fetching', fetchMeta: FORWARD });
95
+ //# sourceMappingURL=read-builders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read-builders.js","sourceRoot":"","sources":["../../../src/react/testing/read-builders.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n InfiniteQueryObserver,\n QueryClient,\n QueryObserver,\n type InfiniteData,\n type InfiniteQueryObserverResult,\n type QueryKey,\n type QueryObserverResult,\n type QueryState,\n} from '@tanstack/react-query';\nimport { nextHeldFailure, toRetryState, type ReadRetryState } from '../read-retry-derivation.js';\n\nexport type BuiltRead<T> = QueryObserverResult<T, Error> & { retryState: ReadRetryState<Error> };\n\nexport type BuiltInfiniteRead<TData> = InfiniteQueryObserverResult<TData, Error> & {\n retryState: ReadRetryState<Error>;\n};\n\nconst KEY: QueryKey = ['built-read'];\n\nconst notFetchedInTest = (): Promise<never> =>\n Promise.reject(new Error('this read is not fetched in the test; pass the case its own refetch'));\n\nfunction retryStateOf(\n result: { error: Error | null; isFetching: boolean; isLoading: boolean },\n held: Error | null,\n): ReadRetryState<Error> {\n const source = {\n error: result.error,\n isFetching: result.isFetching,\n isLoading: result.isLoading,\n };\n return toRetryState(source, nextHeldFailure(held ? { error: held } : undefined, source));\n}\n\nfunction observed<T>(\n state: Partial<QueryState<T, Error>>,\n held: Error | null = null,\n): BuiltRead<T> {\n const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });\n client.getQueryCache().build<T, Error>(client, { queryKey: KEY }).setState(state);\n const result = new QueryObserver<T, Error>(client, {\n queryKey: KEY,\n queryFn: notFetchedInTest,\n enabled: false,\n }).getCurrentResult();\n return { ...result, retryState: retryStateOf(result, held) };\n}\n\nconst answered = <T>(data: T): Partial<QueryState<T, Error>> => ({\n data,\n dataUpdatedAt: 1,\n status: 'success',\n});\n\nconst failure = (error: Error): Partial<QueryState<never, Error>> => ({\n error,\n errorUpdatedAt: 2,\n errorUpdateCount: 1,\n fetchFailureCount: 1,\n fetchFailureReason: error,\n status: 'error',\n});\n\nexport const answeredRead = <T>(data: T): BuiltRead<T> => observed<T>(answered(data));\n\nexport const idleRead = <T>(): BuiltRead<T> => observed<T>({});\n\nexport const loadingRead = <T>(): BuiltRead<T> => observed<T>({ fetchStatus: 'fetching' });\n\nexport const failedRead = <T>(error: Error): BuiltRead<T> => observed<T>(failure(error));\n\nexport const retryingRead = <T>(error: Error): BuiltRead<T> =>\n observed<T>({ status: 'pending', fetchStatus: 'fetching', error: null }, error);\n\nexport const fetchingRead = <T>(data: T): BuiltRead<T> =>\n observed<T>({ ...answered(data), fetchStatus: 'fetching' });\n\nexport const answeredThenFailedRead = <T>(data: T, error: Error): BuiltRead<T> =>\n observed<T>({ ...answered(data), ...failure(error) });\n\nexport const retryingAnsweredRead = <T>(data: T, error: Error): BuiltRead<T> =>\n observed<T>({ ...answered(data), ...failure(error), fetchStatus: 'fetching' });\n\nexport interface InfiniteReadSpec<TPage, TParam, TData = InfiniteData<TPage, TParam>> {\n pages?: TPage[];\n pageParams?: TParam[];\n initialPageParam: TParam;\n getNextPageParam: (lastPage: TPage, allPages: TPage[]) => TParam | undefined | null;\n select?: (data: InfiniteData<TPage, TParam>) => TData;\n}\n\nfunction pageParamsOf<TPage, TParam, TData>(\n spec: InfiniteReadSpec<TPage, TParam, TData>,\n pages: TPage[],\n): TParam[] {\n const params = [spec.initialPageParam];\n for (let i = 1; i < pages.length; i++) {\n const next = spec.getNextPageParam(pages[i - 1], pages.slice(0, i));\n if (next === undefined || next === null)\n throw new Error(`page ${i} has no page param: getNextPageParam ends the list before it`);\n params.push(next);\n }\n return params;\n}\n\nfunction observedInfinite<TPage, TParam, TData>(\n spec: InfiniteReadSpec<TPage, TParam, TData>,\n state: Partial<QueryState<InfiniteData<TPage, TParam>, Error>>,\n held: Error | null = null,\n): BuiltInfiniteRead<TData> {\n const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });\n const pages = spec.pages;\n client\n .getQueryCache()\n .build<InfiniteData<TPage, TParam>, Error>(client, { queryKey: KEY })\n .setState({\n ...(pages\n ? {\n data: {\n pages,\n pageParams: spec.pageParams ?? pageParamsOf(spec, pages),\n },\n dataUpdatedAt: 1,\n status: 'success',\n }\n : {}),\n ...state,\n });\n const result = new InfiniteQueryObserver<TPage, Error, TData, QueryKey, TParam>(client, {\n queryKey: KEY,\n queryFn: notFetchedInTest,\n initialPageParam: spec.initialPageParam,\n getNextPageParam: spec.getNextPageParam,\n ...(spec.select ? { select: spec.select } : {}),\n enabled: false,\n }).getCurrentResult();\n return { ...result, retryState: retryStateOf(result, held) };\n}\n\nconst FORWARD = { fetchMore: { direction: 'forward' } } as const;\n\nexport const infiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: InfiniteReadSpec<TPage, TParam, TData> & { pages: TPage[] },\n): BuiltInfiniteRead<TData> => observedInfinite(spec, {});\n\nexport const idleInfiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, 'pages'>,\n): BuiltInfiniteRead<TData> => observedInfinite(spec, {});\n\nexport const loadingInfiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, 'pages'>,\n): BuiltInfiniteRead<TData> => observedInfinite(spec, { fetchStatus: 'fetching' });\n\nexport const failedInfiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, 'pages'>,\n error: Error,\n): BuiltInfiniteRead<TData> => observedInfinite(spec, failure(error));\n\nexport const retryingInfiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: Omit<InfiniteReadSpec<TPage, TParam, TData>, 'pages'>,\n error: Error,\n): BuiltInfiniteRead<TData> =>\n observedInfinite(spec, { status: 'pending', fetchStatus: 'fetching', error: null }, error);\n\nexport const fetchingInfiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: InfiniteReadSpec<TPage, TParam, TData> & { pages: TPage[] },\n): BuiltInfiniteRead<TData> => observedInfinite(spec, { fetchStatus: 'fetching' });\n\nexport const answeredThenFailedInfiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: InfiniteReadSpec<TPage, TParam, TData> & { pages: TPage[] },\n error: Error,\n): BuiltInfiniteRead<TData> => observedInfinite(spec, failure(error));\n\nexport const retryingAnsweredInfiniteRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: InfiniteReadSpec<TPage, TParam, TData> & { pages: TPage[] },\n error: Error,\n): BuiltInfiniteRead<TData> =>\n observedInfinite(spec, { ...failure(error), fetchStatus: 'fetching' });\n\nexport const fetchingNextPageRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: InfiniteReadSpec<TPage, TParam, TData> & { pages: TPage[] },\n): BuiltInfiniteRead<TData> =>\n observedInfinite(spec, { fetchStatus: 'fetching', fetchMeta: FORWARD });\n\nexport const nextPageFailedRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: InfiniteReadSpec<TPage, TParam, TData> & { pages: TPage[] },\n error: Error,\n): BuiltInfiniteRead<TData> => observedInfinite(spec, { ...failure(error), fetchMeta: FORWARD });\n\nexport const retryingNextPageRead = <TPage, TParam, TData = InfiniteData<TPage, TParam>>(\n spec: InfiniteReadSpec<TPage, TParam, TData> & { pages: TPage[] },\n error: Error,\n): BuiltInfiniteRead<TData> =>\n observedInfinite(spec, { ...failure(error), fetchStatus: 'fetching', fetchMeta: FORWARD });\n"]}
@@ -1,15 +1,5 @@
1
1
  import { type QueryKey } from '@tanstack/react-query';
2
- export interface ReadRetrySource<TError = Error> {
3
- error: TError | null | undefined;
4
- isFetching: boolean;
5
- isLoading: boolean;
6
- isPaused?: boolean;
7
- }
8
- export interface ReadRetryState<TError = Error> {
9
- error: TError | null;
10
- isRetrying: boolean;
11
- isLoading: boolean;
12
- }
2
+ import { type ReadRetrySource, type ReadRetryState } from './read-retry-derivation.js';
13
3
  export interface ReadRetryEntry<TError = Error> {
14
4
  source: ReadRetrySource<TError>;
15
5
  queryKey: QueryKey;
@@ -1 +1 @@
1
- {"version":3,"file":"use-read-retry-state.d.ts","sourceRoot":"","sources":["../../src/react/use-read-retry-state.ts"],"names":[],"mappings":"AAGA,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE/D,MAAM,WAAW,eAAe,CAAC,MAAM,GAAG,KAAK;IAC7C,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc,CAAC,MAAM,GAAG,KAAK;IAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;CACpB;AAeD,MAAM,WAAW,cAAc,CAAC,MAAM,GAAG,KAAK;IAC5C,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAChC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAyBD,wBAAgB,kBAAkB,CAAC,MAAM,GAAG,KAAK,EAC/C,OAAO,EAAE,SAAS,cAAc,CAAC,MAAM,CAAC,EAAE,GACzC,cAAc,CAAC,MAAM,CAAC,EAAE,CAY1B;AAUD,+HAA+H;AAC/H,wBAAgB,iBAAiB,CAAC,MAAM,GAAG,KAAK,EAC9C,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAC/B,QAAQ,EAAE,QAAQ,GACjB,cAAc,CAAC,MAAM,CAAC,CAExB"}
1
+ {"version":3,"file":"use-read-retry-state.d.ts","sourceRoot":"","sources":["../../src/react/use-read-retry-state.ts"],"names":[],"mappings":"AAGA,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,cAAc,CAAC,MAAM,GAAG,KAAK;IAC5C,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAChC,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,GAAG,KAAK,EAC/C,OAAO,EAAE,SAAS,cAAc,CAAC,MAAM,CAAC,EAAE,GACzC,cAAc,CAAC,MAAM,CAAC,EAAE,CAY1B;AAUD,+HAA+H;AAC/H,wBAAgB,iBAAiB,CAAC,MAAM,GAAG,KAAK,EAC9C,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAC/B,QAAQ,EAAE,QAAQ,GACjB,cAAc,CAAC,MAAM,CAAC,CAExB"}
@@ -1,31 +1,7 @@
1
1
  'use client';
2
2
  import { useState } from 'react';
3
3
  import { hashKey } from '@tanstack/react-query';
4
- /** A composite source builds a new error object every render, so a failure is compared by name, message, and `code`. */
5
- function sameFailure(a, b) {
6
- if (a === b)
7
- return true;
8
- if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null)
9
- return false;
10
- const x = a;
11
- const y = b;
12
- return x.name === y.name && x.message === y.message && x.code === y.code;
13
- }
14
- function nextHeldFailure(held, source) {
15
- const live = source.error ?? null;
16
- if (live !== null)
17
- return held !== undefined && sameFailure(held.error, live) ? held : { error: live };
18
- const running = source.isFetching || source.isPaused === true;
19
- return running ? held : undefined;
20
- }
21
- function toRetryState(source, held) {
22
- const error = source.error ?? held?.error ?? null;
23
- return {
24
- error,
25
- isRetrying: error !== null && (source.isFetching || source.isPaused === true),
26
- isLoading: error === null && source.isLoading,
27
- };
28
- }
4
+ import { nextHeldFailure, toRetryState, } from './read-retry-derivation.js';
29
5
  export function useReadRetryStates(entries) {
30
6
  const [held, setHeld] = useState({});
31
7
  const next = {};
@@ -1 +1 @@
1
- {"version":3,"file":"use-read-retry-state.js","sourceRoot":"","sources":["../../src/react/use-read-retry-state.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { hashKey, type QueryKey } from '@tanstack/react-query';\n\nexport interface ReadRetrySource<TError = Error> {\n error: TError | null | undefined;\n isFetching: boolean;\n isLoading: boolean;\n isPaused?: boolean;\n}\n\nexport interface ReadRetryState<TError = Error> {\n error: TError | null;\n isRetrying: boolean;\n isLoading: boolean;\n}\n\ninterface HeldFailure<TError> {\n error: TError;\n}\n\n/** A composite source builds a new error object every render, so a failure is compared by name, message, and `code`. */\nfunction sameFailure(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) return false;\n const x = a as { name?: unknown; message?: unknown; code?: unknown };\n const y = b as { name?: unknown; message?: unknown; code?: unknown };\n return x.name === y.name && x.message === y.message && x.code === y.code;\n}\n\nexport interface ReadRetryEntry<TError = Error> {\n source: ReadRetrySource<TError>;\n queryKey: QueryKey;\n}\n\nfunction nextHeldFailure<TError>(\n held: HeldFailure<TError> | undefined,\n source: ReadRetrySource<TError>,\n): HeldFailure<TError> | undefined {\n const live = source.error ?? null;\n if (live !== null)\n return held !== undefined && sameFailure(held.error, live) ? held : { error: live };\n const running = source.isFetching || source.isPaused === true;\n return running ? held : undefined;\n}\n\nfunction toRetryState<TError>(\n source: ReadRetrySource<TError>,\n held: HeldFailure<TError> | undefined,\n): ReadRetryState<TError> {\n const error = source.error ?? held?.error ?? null;\n return {\n error,\n isRetrying: error !== null && (source.isFetching || source.isPaused === true),\n isLoading: error === null && source.isLoading,\n };\n}\n\nexport function useReadRetryStates<TError = Error>(\n entries: readonly ReadRetryEntry<TError>[],\n): ReadRetryState<TError>[] {\n const [held, setHeld] = useState<Readonly<Record<string, HeldFailure<TError>>>>({});\n\n const next: Record<string, HeldFailure<TError>> = {};\n const states = entries.map(({ source, queryKey }) => {\n const identity = hashKey(queryKey);\n const failure = nextHeldFailure(held[identity], source);\n if (failure !== undefined) next[identity] = failure;\n return toRetryState(source, failure);\n });\n if (!sameHeld(held, next)) setHeld(next);\n return states;\n}\n\nfunction sameHeld<TError>(\n a: Readonly<Record<string, HeldFailure<TError>>>,\n b: Readonly<Record<string, HeldFailure<TError>>>,\n): boolean {\n const keys = Object.keys(a);\n return keys.length === Object.keys(b).length && keys.every((key) => a[key] === b[key]);\n}\n\n/** TanStack clears a never-succeeded query's `error` as its refetch starts, so the failure is held until the retry settles. */\nexport function useReadRetryState<TError = Error>(\n source: ReadRetrySource<TError>,\n queryKey: QueryKey,\n): ReadRetryState<TError> {\n return useReadRetryStates([{ source, queryKey }])[0]!;\n}\n"]}
1
+ {"version":3,"file":"use-read-retry-state.js","sourceRoot":"","sources":["../../src/react/use-read-retry-state.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,OAAO,EAAiB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EACL,eAAe,EACf,YAAY,GAIb,MAAM,4BAA4B,CAAC;AAOpC,MAAM,UAAU,kBAAkB,CAChC,OAA0C;IAE1C,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAgD,EAAE,CAAC,CAAC;IAEpF,MAAM,IAAI,GAAwC,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;QAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,OAAO,KAAK,SAAS;YAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC;QACpD,OAAO,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CACf,CAAgD,EAChD,CAAgD;IAEhD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AACzF,CAAC;AAED,+HAA+H;AAC/H,MAAM,UAAU,iBAAiB,CAC/B,MAA+B,EAC/B,QAAkB;IAElB,OAAO,kBAAkB,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC;AACxD,CAAC","sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { hashKey, type QueryKey } from '@tanstack/react-query';\nimport {\n nextHeldFailure,\n toRetryState,\n type HeldFailure,\n type ReadRetrySource,\n type ReadRetryState,\n} from './read-retry-derivation.js';\n\nexport interface ReadRetryEntry<TError = Error> {\n source: ReadRetrySource<TError>;\n queryKey: QueryKey;\n}\n\nexport function useReadRetryStates<TError = Error>(\n entries: readonly ReadRetryEntry<TError>[],\n): ReadRetryState<TError>[] {\n const [held, setHeld] = useState<Readonly<Record<string, HeldFailure<TError>>>>({});\n\n const next: Record<string, HeldFailure<TError>> = {};\n const states = entries.map(({ source, queryKey }) => {\n const identity = hashKey(queryKey);\n const failure = nextHeldFailure(held[identity], source);\n if (failure !== undefined) next[identity] = failure;\n return toRetryState(source, failure);\n });\n if (!sameHeld(held, next)) setHeld(next);\n return states;\n}\n\nfunction sameHeld<TError>(\n a: Readonly<Record<string, HeldFailure<TError>>>,\n b: Readonly<Record<string, HeldFailure<TError>>>,\n): boolean {\n const keys = Object.keys(a);\n return keys.length === Object.keys(b).length && keys.every((key) => a[key] === b[key]);\n}\n\n/** TanStack clears a never-succeeded query's `error` as its refetch starts, so the failure is held until the retry settles. */\nexport function useReadRetryState<TError = Error>(\n source: ReadRetrySource<TError>,\n queryKey: QueryKey,\n): ReadRetryState<TError> {\n return useReadRetryStates([{ source, queryKey }])[0]!;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/query-core",
3
- "version": "0.14.26",
3
+ "version": "0.14.28",
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",
@@ -28,6 +28,10 @@
28
28
  "types": "./dist/react/index.d.ts",
29
29
  "default": "./dist/react/index.js"
30
30
  },
31
+ "./react/testing": {
32
+ "types": "./dist/react/testing/index.d.ts",
33
+ "default": "./dist/react/testing/index.js"
34
+ },
31
35
  "./types": {
32
36
  "types": "./dist/firestore/types.d.ts",
33
37
  "default": "./dist/firestore/types.js"
@@ -60,7 +64,7 @@
60
64
  }
61
65
  },
62
66
  "dependencies": {
63
- "@ttt-productions/firebase-helpers": "^0.12.17"
67
+ "@ttt-productions/firebase-helpers": "^0.12.20"
64
68
  },
65
69
  "devDependencies": {
66
70
  "@tanstack/react-query": "^5.90.0",