@ttt-productions/query-core 0.14.21 → 0.14.23

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 (153) hide show
  1. package/README.md +6 -6
  2. package/dist/defaults.d.ts +0 -22
  3. package/dist/defaults.d.ts.map +1 -1
  4. package/dist/defaults.js +0 -35
  5. package/dist/defaults.js.map +1 -1
  6. package/dist/firestore/types.d.ts +1 -191
  7. package/dist/firestore/types.d.ts.map +1 -1
  8. package/dist/firestore/types.js +1 -6
  9. package/dist/firestore/types.js.map +1 -1
  10. package/dist/index.d.ts +2 -9
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -8
  13. package/dist/index.js.map +1 -1
  14. package/dist/keys.d.ts +0 -22
  15. package/dist/keys.d.ts.map +1 -1
  16. package/dist/keys.js +0 -4
  17. package/dist/keys.js.map +1 -1
  18. package/dist/react/cache-helpers.d.ts +16 -0
  19. package/dist/react/cache-helpers.d.ts.map +1 -0
  20. package/dist/{cache-helpers.js → react/cache-helpers.js} +0 -28
  21. package/dist/react/cache-helpers.js.map +1 -0
  22. package/dist/react/defaults.d.ts +4 -0
  23. package/dist/react/defaults.d.ts.map +1 -0
  24. package/dist/react/defaults.js +17 -0
  25. package/dist/react/defaults.js.map +1 -0
  26. package/dist/react/domain-events/cache-invalidation.d.ts +33 -0
  27. package/dist/react/domain-events/cache-invalidation.d.ts.map +1 -0
  28. package/dist/react/domain-events/cache-invalidation.js +74 -0
  29. package/dist/react/domain-events/cache-invalidation.js.map +1 -0
  30. package/dist/react/domain-events/create-domain-event-invalidator.d.ts +28 -0
  31. package/dist/react/domain-events/create-domain-event-invalidator.d.ts.map +1 -0
  32. package/dist/{domain-events → react/domain-events}/create-domain-event-invalidator.js +1 -6
  33. package/dist/react/domain-events/create-domain-event-invalidator.js.map +1 -0
  34. package/dist/react/firestore/absence-scheduler.d.ts +0 -28
  35. package/dist/react/firestore/absence-scheduler.d.ts.map +1 -1
  36. package/dist/react/firestore/absence-scheduler.js +1 -39
  37. package/dist/react/firestore/absence-scheduler.js.map +1 -1
  38. package/dist/react/firestore/batch-doc-loader.d.ts +0 -30
  39. package/dist/react/firestore/batch-doc-loader.d.ts.map +1 -1
  40. package/dist/react/firestore/batch-doc-loader.js +0 -34
  41. package/dist/react/firestore/batch-doc-loader.js.map +1 -1
  42. package/dist/react/firestore/context.d.ts +0 -19
  43. package/dist/react/firestore/context.d.ts.map +1 -1
  44. package/dist/react/firestore/context.js +1 -20
  45. package/dist/react/firestore/context.js.map +1 -1
  46. package/dist/react/firestore/doc-subscription-registry.d.ts +0 -23
  47. package/dist/react/firestore/doc-subscription-registry.d.ts.map +1 -1
  48. package/dist/react/firestore/doc-subscription-registry.js +5 -26
  49. package/dist/react/firestore/doc-subscription-registry.js.map +1 -1
  50. package/dist/react/firestore/infinite-helpers.d.ts +9 -0
  51. package/dist/react/firestore/infinite-helpers.d.ts.map +1 -0
  52. package/dist/react/firestore/infinite-helpers.js +11 -0
  53. package/dist/react/firestore/infinite-helpers.js.map +1 -0
  54. package/dist/react/firestore/resubscribe.d.ts +0 -20
  55. package/dist/react/firestore/resubscribe.d.ts.map +1 -1
  56. package/dist/react/firestore/resubscribe.js +0 -20
  57. package/dist/react/firestore/resubscribe.js.map +1 -1
  58. package/dist/react/firestore/subscription-status.d.ts +0 -29
  59. package/dist/react/firestore/subscription-status.d.ts.map +1 -1
  60. package/dist/react/firestore/subscription-status.js +1 -34
  61. package/dist/react/firestore/subscription-status.js.map +1 -1
  62. package/dist/react/firestore/types.d.ts +80 -0
  63. package/dist/react/firestore/types.d.ts.map +1 -0
  64. package/dist/react/firestore/types.js +4 -0
  65. package/dist/react/firestore/types.js.map +1 -0
  66. package/dist/react/firestore/use-firestore-collection.d.ts +2 -21
  67. package/dist/react/firestore/use-firestore-collection.d.ts.map +1 -1
  68. package/dist/react/firestore/use-firestore-collection.js +23 -44
  69. package/dist/react/firestore/use-firestore-collection.js.map +1 -1
  70. package/dist/react/firestore/use-firestore-count.d.ts +1 -16
  71. package/dist/react/firestore/use-firestore-count.d.ts.map +1 -1
  72. package/dist/react/firestore/use-firestore-count.js +0 -15
  73. package/dist/react/firestore/use-firestore-count.js.map +1 -1
  74. package/dist/react/firestore/use-firestore-doc.d.ts +2 -24
  75. package/dist/react/firestore/use-firestore-doc.d.ts.map +1 -1
  76. package/dist/react/firestore/use-firestore-doc.js +21 -42
  77. package/dist/react/firestore/use-firestore-doc.js.map +1 -1
  78. package/dist/react/firestore/use-firestore-infinite.d.ts +1 -30
  79. package/dist/react/firestore/use-firestore-infinite.d.ts.map +1 -1
  80. package/dist/react/firestore/use-firestore-infinite.js +0 -32
  81. package/dist/react/firestore/use-firestore-infinite.js.map +1 -1
  82. package/dist/react/firestore/use-firestore-live-infinite.d.ts +2 -35
  83. package/dist/react/firestore/use-firestore-live-infinite.d.ts.map +1 -1
  84. package/dist/react/firestore/use-firestore-live-infinite.js +10 -36
  85. package/dist/react/firestore/use-firestore-live-infinite.js.map +1 -1
  86. package/dist/react/firestore/use-firestore-mutations.d.ts +2 -1
  87. package/dist/react/firestore/use-firestore-mutations.d.ts.map +1 -1
  88. package/dist/react/firestore/use-firestore-mutations.js +3 -3
  89. package/dist/react/firestore/use-firestore-mutations.js.map +1 -1
  90. package/dist/react/firestore/use-firestore-paginated.d.ts +2 -31
  91. package/dist/react/firestore/use-firestore-paginated.d.ts.map +1 -1
  92. package/dist/react/firestore/use-firestore-paginated.js +8 -36
  93. package/dist/react/firestore/use-firestore-paginated.js.map +1 -1
  94. package/dist/react/firestore/useBatchFirestoreDocs.d.ts +1 -123
  95. package/dist/react/firestore/useBatchFirestoreDocs.d.ts.map +1 -1
  96. package/dist/react/firestore/useBatchFirestoreDocs.js +12 -61
  97. package/dist/react/firestore/useBatchFirestoreDocs.js.map +1 -1
  98. package/dist/react/index.d.ts +13 -4
  99. package/dist/react/index.d.ts.map +1 -1
  100. package/dist/react/index.js +8 -13
  101. package/dist/react/index.js.map +1 -1
  102. package/dist/react/pending-mutations.d.ts +2 -22
  103. package/dist/react/pending-mutations.d.ts.map +1 -1
  104. package/dist/react/pending-mutations.js +7 -38
  105. package/dist/react/pending-mutations.js.map +1 -1
  106. package/dist/react/provider.d.ts +1 -6
  107. package/dist/react/provider.d.ts.map +1 -1
  108. package/dist/react/provider.js +1 -5
  109. package/dist/react/provider.js.map +1 -1
  110. package/dist/{query-client.d.ts → react/query-client.d.ts} +0 -4
  111. package/dist/react/query-client.d.ts.map +1 -0
  112. package/dist/{query-client.js → react/query-client.js} +0 -4
  113. package/dist/react/query-client.js.map +1 -0
  114. package/dist/react/search/types.d.ts +16 -0
  115. package/dist/react/search/types.d.ts.map +1 -0
  116. package/dist/react/search/types.js +2 -0
  117. package/dist/react/search/types.js.map +1 -0
  118. package/dist/react/search/use-firestore-search.d.ts +1 -30
  119. package/dist/react/search/use-firestore-search.d.ts.map +1 -1
  120. package/dist/react/search/use-firestore-search.js +3 -41
  121. package/dist/react/search/use-firestore-search.js.map +1 -1
  122. package/dist/react/use-read-retry-state.d.ts +1 -21
  123. package/dist/react/use-read-retry-state.d.ts.map +1 -1
  124. package/dist/react/use-read-retry-state.js +3 -22
  125. package/dist/react/use-read-retry-state.js.map +1 -1
  126. package/dist/search/rule.d.ts +0 -6
  127. package/dist/search/rule.d.ts.map +1 -1
  128. package/dist/search/rule.js +0 -6
  129. package/dist/search/rule.js.map +1 -1
  130. package/dist/search/types.d.ts +1 -39
  131. package/dist/search/types.d.ts.map +1 -1
  132. package/dist/search/types.js.map +1 -1
  133. package/package.json +2 -2
  134. package/dist/cache-helpers.d.ts +0 -48
  135. package/dist/cache-helpers.d.ts.map +0 -1
  136. package/dist/cache-helpers.js.map +0 -1
  137. package/dist/domain-events/cache-invalidation.d.ts +0 -70
  138. package/dist/domain-events/cache-invalidation.d.ts.map +0 -1
  139. package/dist/domain-events/cache-invalidation.js +0 -123
  140. package/dist/domain-events/cache-invalidation.js.map +0 -1
  141. package/dist/domain-events/create-domain-event-invalidator.d.ts +0 -46
  142. package/dist/domain-events/create-domain-event-invalidator.d.ts.map +0 -1
  143. package/dist/domain-events/create-domain-event-invalidator.js.map +0 -1
  144. package/dist/domain-events/index.d.ts +0 -5
  145. package/dist/domain-events/index.d.ts.map +0 -1
  146. package/dist/domain-events/index.js +0 -3
  147. package/dist/domain-events/index.js.map +0 -1
  148. package/dist/firestore/infinite-helpers.d.ts +0 -20
  149. package/dist/firestore/infinite-helpers.d.ts.map +0 -1
  150. package/dist/firestore/infinite-helpers.js +0 -23
  151. package/dist/firestore/infinite-helpers.js.map +0 -1
  152. package/dist/query-client.d.ts.map +0 -1
  153. package/dist/query-client.js.map +0 -1
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # @ttt-productions/query-core
2
2
 
3
- Shared TanStack Query (React Query) setup for TTT Productions apps.
3
+ Shared TanStack Query (React Query) setup and Firestore read hooks for consuming apps.
4
4
 
5
- - `createTTTQueryClient()` factory with safe defaults
6
- - `keys` query key helpers
7
- - invalidation + cache update helpers
8
- - `TTTQueryProvider` for Next.js/React apps
5
+ - `createQueryClient()` factory with safe defaults and `QueryProvider` (`./react`)
6
+ - `STALE_TIMES` presets and the search rule (root)
7
+ - `keys` query key helpers (`./keys`)
8
+ - the Firestore hooks, invalidation, and cache update helpers (`./react`)
9
9
 
10
- No app business logic. No Firebase.
10
+ No app business logic. See `docs/packages/query-core.md`.
@@ -1,25 +1,3 @@
1
- import type { DefaultOptions, QueryClientConfig } from '@tanstack/react-query';
2
- /**
3
- * Small, conservative defaults intended to work well across apps.
4
- * Apps can override via `createQueryClient({ defaultOptions: ... })`.
5
- */
6
- export declare const defaultQueryOptions: DefaultOptions;
7
- export declare const defaultQueryClientConfig: QueryClientConfig;
8
- /**
9
- * Named `staleTime` presets (milliseconds) for React Query call sites.
10
- *
11
- * Use a preset instead of a magic number so every query self-documents how
12
- * fresh its data must be:
13
- * - `short` (30s) — frequently-changing counts/lists; matches the client default.
14
- * - `medium` (5m) — semi-dynamic data that tolerates a few minutes of staleness.
15
- * - `long` (30m) — rarely-changing data (public profiles, detail docs).
16
- * - `forever` (∞) — immutable for the session, OR data whose freshness is driven
17
- * entirely by explicit cache invalidation (a domain event), never
18
- * by elapsed time. Do NOT use `forever` for data with no
19
- * invalidation path — it will never refetch.
20
- *
21
- * Generic time buckets, not app-specific presets — safe to live in this package.
22
- */
23
1
  export declare const STALE_TIMES: {
24
2
  readonly short: 30000;
25
3
  readonly medium: number;
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,cAcjC,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,iBAEtC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW;;;;;CAKd,CAAC"}
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW;;;;;CAKd,CAAC"}
package/dist/defaults.js CHANGED
@@ -1,38 +1,3 @@
1
- /**
2
- * Small, conservative defaults intended to work well across apps.
3
- * Apps can override via `createQueryClient({ defaultOptions: ... })`.
4
- */
5
- export const defaultQueryOptions = {
6
- queries: {
7
- refetchOnWindowFocus: false,
8
- refetchOnReconnect: true,
9
- refetchOnMount: false,
10
- staleTime: 30_000, // 30s
11
- gcTime: 5 * 60_000, // 5m
12
- retry: (failureCount) => failureCount < 2,
13
- },
14
- mutations: {
15
- retry: 0,
16
- },
17
- };
18
- export const defaultQueryClientConfig = {
19
- defaultOptions: defaultQueryOptions,
20
- };
21
- /**
22
- * Named `staleTime` presets (milliseconds) for React Query call sites.
23
- *
24
- * Use a preset instead of a magic number so every query self-documents how
25
- * fresh its data must be:
26
- * - `short` (30s) — frequently-changing counts/lists; matches the client default.
27
- * - `medium` (5m) — semi-dynamic data that tolerates a few minutes of staleness.
28
- * - `long` (30m) — rarely-changing data (public profiles, detail docs).
29
- * - `forever` (∞) — immutable for the session, OR data whose freshness is driven
30
- * entirely by explicit cache invalidation (a domain event), never
31
- * by elapsed time. Do NOT use `forever` for data with no
32
- * invalidation path — it will never refetch.
33
- *
34
- * Generic time buckets, not app-specific presets — safe to live in this package.
35
- */
36
1
  export const STALE_TIMES = {
37
2
  short: 30_000,
38
3
  medium: 5 * 60_000,
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAmB;IACjD,OAAO,EAAE;QACP,oBAAoB,EAAE,KAAK;QAC3B,kBAAkB,EAAE,IAAI;QACxB,cAAc,EAAE,KAAK;QAErB,SAAS,EAAE,MAAM,EAAE,MAAM;QACzB,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,KAAK;QAEzB,KAAK,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,GAAG,CAAC;KAC1C;IACD,SAAS,EAAE;QACT,KAAK,EAAE,CAAC;KACT;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,cAAc,EAAE,mBAAmB;CACpC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,CAAC,GAAG,MAAM;IAClB,IAAI,EAAE,EAAE,GAAG,MAAM;IACjB,OAAO,EAAE,MAAM,CAAC,iBAAiB;CACzB,CAAC","sourcesContent":["import type { DefaultOptions, QueryClientConfig } from '@tanstack/react-query';\n\n/**\n * Small, conservative defaults intended to work well across apps.\n * Apps can override via `createQueryClient({ defaultOptions: ... })`.\n */\nexport const defaultQueryOptions: DefaultOptions = {\n queries: {\n refetchOnWindowFocus: false,\n refetchOnReconnect: true,\n refetchOnMount: false,\n\n staleTime: 30_000, // 30s\n gcTime: 5 * 60_000, // 5m\n\n retry: (failureCount) => failureCount < 2,\n },\n mutations: {\n retry: 0,\n },\n};\n\nexport const defaultQueryClientConfig: QueryClientConfig = {\n defaultOptions: defaultQueryOptions,\n};\n\n/**\n * Named `staleTime` presets (milliseconds) for React Query call sites.\n *\n * Use a preset instead of a magic number so every query self-documents how\n * fresh its data must be:\n * - `short` (30s) — frequently-changing counts/lists; matches the client default.\n * - `medium` (5m) — semi-dynamic data that tolerates a few minutes of staleness.\n * - `long` (30m) — rarely-changing data (public profiles, detail docs).\n * - `forever` (∞) — immutable for the session, OR data whose freshness is driven\n * entirely by explicit cache invalidation (a domain event), never\n * by elapsed time. Do NOT use `forever` for data with no\n * invalidation path — it will never refetch.\n *\n * Generic time buckets, not app-specific presets — safe to live in this package.\n */\nexport const STALE_TIMES = {\n short: 30_000,\n medium: 5 * 60_000,\n long: 30 * 60_000,\n forever: Number.POSITIVE_INFINITY,\n} as const;\n"]}
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,CAAC,GAAG,MAAM;IAClB,IAAI,EAAE,EAAE,GAAG,MAAM;IACjB,OAAO,EAAE,MAAM,CAAC,iBAAiB;CACzB,CAAC","sourcesContent":["export const STALE_TIMES = {\n short: 30_000,\n medium: 5 * 60_000,\n long: 30 * 60_000,\n forever: Number.POSITIVE_INFINITY,\n} as const;\n"]}
@@ -1,40 +1,11 @@
1
- import type { DocumentData, DocumentSnapshot, QueryDocumentSnapshot, QueryConstraint } from 'firebase/firestore';
2
- /**
3
- * Document with ID included in the data object.
4
- */
5
1
  export type WithId<T> = T & {
6
2
  id: string;
7
3
  };
8
- /**
9
- * Metadata-derived liveness of a realtime subscription. Firestore serves cached
10
- * snapshots offline WITHOUT firing the error callback, so error-only detection
11
- * renders a stale cached empty result as "live". This four-state is derived from
12
- * `snapshot.metadata.fromCache` (server-confirmed vs cache) plus the listener
13
- * error callback:
14
- * - `connecting` — no server-confirmed snapshot yet (initial, or only cache-first data).
15
- * - `live` — at least one server-confirmed snapshot (`fromCache === false`).
16
- * - `offline` — only cached data after having been live (connectivity loss).
17
- * - `error` — the listener error callback fired (e.g. permission loss).
18
- *
19
- * Meaningful only for `subscribe: true`; a non-subscribed hook stays `connecting`.
20
- */
4
+ /** Firestore serves cached snapshots offline without firing the error callback, so liveness is read from `metadata.fromCache`. */
21
5
  export type FirestoreSourceState = 'connecting' | 'live' | 'offline' | 'error';
22
- /** A query-hook result augmented with the metadata-derived subscription source state. */
23
6
  export type WithSourceState<R> = R & {
24
7
  sourceState: FirestoreSourceState;
25
8
  };
26
- /**
27
- * One requested id's answer from `useBatchFirestoreDocs`:
28
- * - `loading` — no answer yet (nothing cached for the id, or the hook is disabled).
29
- * - `present` — the document exists and is readable; `data` is it.
30
- * - `absent` — the read succeeded and the document does not exist.
31
- * - `failed` — the read (or, in subscribe mode, the listener) errored; `error` is the cause.
32
- * A failure is never reported as `absent`, and a document cached before the failure is
33
- * not reported as `present`. What a failure means for a given collection (a rules denial
34
- * that stands for "not there for this reader", say) is the consumer's to decide from `error`.
35
- * - A failed id stays `failed` through a retry of it, with the failure it showed and `retrying`
36
- * true while the retry runs; an answer replaces it, a new failure replaces its `error`.
37
- */
38
9
  export type BatchFirestoreDocOutcome<T> = {
39
10
  status: 'loading';
40
11
  } | {
@@ -47,183 +18,22 @@ export type BatchFirestoreDocOutcome<T> = {
47
18
  error: Error;
48
19
  retrying: boolean;
49
20
  };
50
- /**
51
- * Extract document data with ID from a QueryDocumentSnapshot.
52
- */
53
- export declare function docWithId<T extends DocumentData>(snap: QueryDocumentSnapshot<T>): WithId<T>;
54
- /**
55
- * Base options shared across all Firestore hooks.
56
- */
57
21
  export interface FirestoreBaseOptions {
58
- /** React Query cache key */
59
22
  queryKey: readonly unknown[];
60
- /** Enable/disable the query */
61
23
  enabled?: boolean;
62
- /** Stale time override (ms) */
63
24
  staleTime?: number;
64
- /** Garbage collection time override (ms) */
65
25
  gcTime?: number;
66
26
  }
67
- /**
68
- * Options for single document queries.
69
- */
70
- export interface FirestoreDocOptions<T> extends FirestoreBaseOptions {
71
- /** Full document path (e.g., 'users/abc123') */
72
- docPath: string;
73
- /** Enable realtime updates via onSnapshot (default: false) */
74
- subscribe?: boolean;
75
- /** Transform function applied to document data. Receives data WITH id included. */
76
- select?: (data: DocumentData & {
77
- id: string;
78
- }) => T;
79
- }
80
- /**
81
- * Options for collection queries.
82
- */
83
- export interface FirestoreCollectionOptions<T> extends FirestoreBaseOptions {
84
- /** Collection path (e.g., 'users' or 'entities/abc/members') */
85
- collectionPath: string;
86
- /** Firestore query constraints (where, orderBy, etc.) */
87
- constraints?: QueryConstraint[];
88
- /** Enable realtime updates via onSnapshot (default: false) */
89
- subscribe?: boolean;
90
- /** Transform function applied to each document. Receives data WITH id included. */
91
- select?: (data: DocumentData & {
92
- id: string;
93
- }) => T;
94
- }
95
- /**
96
- * Options for infinite scroll queries.
97
- */
98
- export interface FirestoreInfiniteOptions<T> extends FirestoreBaseOptions {
99
- /** Collection path */
100
- collectionPath: string;
101
- /** Firestore query constraints (where, orderBy - required for pagination) */
102
- constraints?: QueryConstraint[];
103
- /** Number of items per page (default: 20) */
104
- pageSize?: number;
105
- /** Transform function applied to each document. Receives data WITH id included. */
106
- select?: (data: DocumentData & {
107
- id: string;
108
- }) => T;
109
- }
110
- /**
111
- * Options for paginated queries with page numbers.
112
- */
113
- export interface FirestorePaginatedOptions<T> extends FirestoreBaseOptions {
114
- /** Collection path */
115
- collectionPath: string;
116
- /** Firestore query constraints */
117
- constraints?: QueryConstraint[];
118
- /** Number of items per page (default: 10) */
119
- pageSize?: number;
120
- /** Initial page number (default: 1) */
121
- initialPage?: number;
122
- /** Re-read the displayed page every `refetchInterval` ms while it is mounted (omit for none). */
123
- refetchInterval?: number;
124
- /** Transform function applied to each document. Receives data WITH id included. */
125
- select?: (data: DocumentData & {
126
- id: string;
127
- }) => T;
128
- }
129
- /**
130
- * Options for count() aggregation queries.
131
- */
132
- export interface FirestoreCountOptions extends FirestoreBaseOptions {
133
- /** Collection path */
134
- collectionPath: string;
135
- /** Firestore query constraints (where, etc.) applied before counting */
136
- constraints?: QueryConstraint[];
137
- /** Polling interval in ms (omit for no polling) */
138
- refetchInterval?: number;
139
- }
140
- /**
141
- * Options for a live newest-window + cursor-bridged older-pages list
142
- * (e.g. chat messages, live comment threads, live activity feeds). The newest
143
- * page is a realtime onSnapshot window; older pages load on demand via getDocs,
144
- * seeded from the window's oldest document so there is no gap or re-read.
145
- */
146
- export interface FirestoreLiveInfiniteOptions<T = DocumentData & {
147
- id: string;
148
- }> {
149
- /** Collection path (slash-joined for nested paths, e.g. 'chats/t1/messages'). */
150
- collectionPath: string;
151
- /** React Query cache key. The older-pages query is keyed under `[...queryKey, 'older']`. */
152
- queryKey: readonly unknown[];
153
- /** Field both the live window and older pages order by (descending under the hood). */
154
- orderByField: string;
155
- /** Equality/filter constraints. Do NOT pass orderBy/limit/startAfter — the hook adds those. */
156
- constraints?: QueryConstraint[];
157
- /** Items per page / live-window size (default 20, capped at 100). */
158
- pageSize?: number;
159
- /** When false, no listener is opened and no pages are fetched. */
160
- enabled?: boolean;
161
- /** Map each raw doc (id included) to the item shape. Default: identity (WithId). */
162
- select?: (data: DocumentData & {
163
- id: string;
164
- }) => T;
165
- /** Output ordering of the merged list, by `orderByField` as Firestore orders it. Default 'asc' (oldest → newest). */
166
- sort?: 'asc' | 'desc';
167
- }
168
- /**
169
- * Result page for infinite queries.
170
- */
171
- export interface InfinitePage<T> {
172
- items: WithId<T>[];
173
- lastDoc: DocumentSnapshot | null;
174
- size: number;
175
- }
176
- /**
177
- * One page's cache entry for `useFirestorePaginated`, stored at `[...queryKey, 'page', n]`:
178
- * the page's rows, its last row (the next page's cursor; `null` for an empty page), and
179
- * whether a further page exists (read with a one-row look-ahead), and the id of the row it
180
- * was read after (`null` for page 1), checked against the previous page's cursor.
181
- */
182
- export interface PaginatedPage<T> {
183
- items: T[];
184
- cursor: DocumentSnapshot | null;
185
- hasMore: boolean;
186
- after: string | null;
187
- }
188
- /**
189
- * Mutation operation types for batch mutations.
190
- */
191
- export type MutationOperation = {
192
- type: 'set';
193
- docPath: string;
194
- data: DocumentData;
195
- merge?: boolean;
196
- } | {
197
- type: 'update';
198
- docPath: string;
199
- data: DocumentData;
200
- } | {
201
- type: 'delete';
202
- docPath: string;
203
- };
204
- /**
205
- * Options for document mutations.
206
- */
207
27
  export interface FirestoreMutationOptions<T> {
208
- /** Document path for single-doc mutations */
209
28
  docPath?: string;
210
- /** Query keys to invalidate on success */
211
29
  invalidateKeys?: readonly unknown[][];
212
- /** Enable optimistic updates */
213
30
  optimistic?: {
214
- /** Query key of the cache to update */
215
31
  queryKey: readonly unknown[];
216
- /** How to update the cached data */
217
32
  updater: (oldData: T | undefined, newData: Partial<T>) => T;
218
33
  };
219
34
  }
220
- /**
221
- * Options for batch mutations.
222
- */
223
35
  export interface FirestoreBatchOptions {
224
- /** Query keys to invalidate on success */
225
36
  invalidateKeys?: readonly unknown[][];
226
- /** Max operations per batch (default: 450) */
227
37
  batchSize?: number;
228
38
  }
229
39
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,kIAAkI;AAClI,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/E,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,WAAW,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAClC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC9B;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC;IACtC,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;KAC7D,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -1,7 +1,2 @@
1
- /**
2
- * Extract document data with ID from a QueryDocumentSnapshot.
3
- */
4
- export function docWithId(snap) {
5
- return { id: snap.id, ...snap.data() };
6
- }
1
+ export {};
7
2
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"AAgDA;;GAEG;AACH,MAAM,UAAU,SAAS,CACvB,IAA8B;IAE9B,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;AACzC,CAAC","sourcesContent":["import type {\n DocumentData,\n DocumentSnapshot,\n QueryDocumentSnapshot,\n QueryConstraint,\n} from 'firebase/firestore';\n\n/**\n * Document with ID included in the data object.\n */\nexport type WithId<T> = T & { id: string };\n\n/**\n * Metadata-derived liveness of a realtime subscription. Firestore serves cached\n * snapshots offline WITHOUT firing the error callback, so error-only detection\n * renders a stale cached empty result as \"live\". This four-state is derived from\n * `snapshot.metadata.fromCache` (server-confirmed vs cache) plus the listener\n * error callback:\n * - `connecting` — no server-confirmed snapshot yet (initial, or only cache-first data).\n * - `live` — at least one server-confirmed snapshot (`fromCache === false`).\n * - `offline` — only cached data after having been live (connectivity loss).\n * - `error` — the listener error callback fired (e.g. permission loss).\n *\n * Meaningful only for `subscribe: true`; a non-subscribed hook stays `connecting`.\n */\nexport type FirestoreSourceState = 'connecting' | 'live' | 'offline' | 'error';\n\n/** A query-hook result augmented with the metadata-derived subscription source state. */\nexport type WithSourceState<R> = R & { sourceState: FirestoreSourceState };\n\n/**\n * One requested id's answer from `useBatchFirestoreDocs`:\n * - `loading` — no answer yet (nothing cached for the id, or the hook is disabled).\n * - `present` — the document exists and is readable; `data` is it.\n * - `absent` — the read succeeded and the document does not exist.\n * - `failed` — the read (or, in subscribe mode, the listener) errored; `error` is the cause.\n * A failure is never reported as `absent`, and a document cached before the failure is\n * not reported as `present`. What a failure means for a given collection (a rules denial\n * that stands for \"not there for this reader\", say) is the consumer's to decide from `error`.\n * - A failed id stays `failed` through a retry of it, with the failure it showed and `retrying`\n * true while the retry runs; an answer replaces it, a new failure replaces its `error`.\n */\nexport type BatchFirestoreDocOutcome<T> =\n | { status: 'loading' }\n | { status: 'present'; data: T }\n | { status: 'absent' }\n | { status: 'failed'; error: Error; retrying: boolean };\n\n/**\n * Extract document data with ID from a QueryDocumentSnapshot.\n */\nexport function docWithId<T extends DocumentData>(\n snap: QueryDocumentSnapshot<T>\n): WithId<T> {\n return { id: snap.id, ...snap.data() };\n}\n\n/**\n * Base options shared across all Firestore hooks.\n */\nexport interface FirestoreBaseOptions {\n /** React Query cache key */\n queryKey: readonly unknown[];\n /** Enable/disable the query */\n enabled?: boolean;\n /** Stale time override (ms) */\n staleTime?: number;\n /** Garbage collection time override (ms) */\n gcTime?: number;\n}\n\n/**\n * Options for single document queries.\n */\nexport interface FirestoreDocOptions<T> extends FirestoreBaseOptions {\n /** Full document path (e.g., 'users/abc123') */\n docPath: string;\n /** Enable realtime updates via onSnapshot (default: false) */\n subscribe?: boolean;\n /** Transform function applied to document data. Receives data WITH id included. */\n select?: (data: DocumentData & { id: string }) => T;\n}\n\n/**\n * Options for collection queries.\n */\nexport interface FirestoreCollectionOptions<T> extends FirestoreBaseOptions {\n /** Collection path (e.g., 'users' or 'entities/abc/members') */\n collectionPath: string;\n /** Firestore query constraints (where, orderBy, etc.) */\n constraints?: QueryConstraint[];\n /** Enable realtime updates via onSnapshot (default: false) */\n subscribe?: boolean;\n /** Transform function applied to each document. Receives data WITH id included. */\n select?: (data: DocumentData & { id: string }) => T;\n}\n\n/**\n * Options for infinite scroll queries.\n */\nexport interface FirestoreInfiniteOptions<T> extends FirestoreBaseOptions {\n /** Collection path */\n collectionPath: string;\n /** Firestore query constraints (where, orderBy - required for pagination) */\n constraints?: QueryConstraint[];\n /** Number of items per page (default: 20) */\n pageSize?: number;\n /** Transform function applied to each document. Receives data WITH id included. */\n select?: (data: DocumentData & { id: string }) => T;\n}\n\n/**\n * Options for paginated queries with page numbers.\n */\nexport interface FirestorePaginatedOptions<T> extends FirestoreBaseOptions {\n /** Collection path */\n collectionPath: string;\n /** Firestore query constraints */\n constraints?: QueryConstraint[];\n /** Number of items per page (default: 10) */\n pageSize?: number;\n /** Initial page number (default: 1) */\n initialPage?: number;\n /** Re-read the displayed page every `refetchInterval` ms while it is mounted (omit for none). */\n refetchInterval?: number;\n /** Transform function applied to each document. Receives data WITH id included. */\n select?: (data: DocumentData & { id: string }) => T;\n}\n\n/**\n * Options for count() aggregation queries.\n */\nexport interface FirestoreCountOptions extends FirestoreBaseOptions {\n /** Collection path */\n collectionPath: string;\n /** Firestore query constraints (where, etc.) applied before counting */\n constraints?: QueryConstraint[];\n /** Polling interval in ms (omit for no polling) */\n refetchInterval?: number;\n}\n\n/**\n * Options for a live newest-window + cursor-bridged older-pages list\n * (e.g. chat messages, live comment threads, live activity feeds). The newest\n * page is a realtime onSnapshot window; older pages load on demand via getDocs,\n * seeded from the window's oldest document so there is no gap or re-read.\n */\nexport interface FirestoreLiveInfiniteOptions<T = DocumentData & { id: string }> {\n /** Collection path (slash-joined for nested paths, e.g. 'chats/t1/messages'). */\n collectionPath: string;\n /** React Query cache key. The older-pages query is keyed under `[...queryKey, 'older']`. */\n queryKey: readonly unknown[];\n /** Field both the live window and older pages order by (descending under the hood). */\n orderByField: string;\n /** Equality/filter constraints. Do NOT pass orderBy/limit/startAfter — the hook adds those. */\n constraints?: QueryConstraint[];\n /** Items per page / live-window size (default 20, capped at 100). */\n pageSize?: number;\n /** When false, no listener is opened and no pages are fetched. */\n enabled?: boolean;\n /** Map each raw doc (id included) to the item shape. Default: identity (WithId). */\n select?: (data: DocumentData & { id: string }) => T;\n /** Output ordering of the merged list, by `orderByField` as Firestore orders it. Default 'asc' (oldest → newest). */\n sort?: 'asc' | 'desc';\n}\n\n/**\n * Result page for infinite queries.\n */\nexport interface InfinitePage<T> {\n items: WithId<T>[];\n lastDoc: DocumentSnapshot | null;\n size: number;\n}\n\n/**\n * One page's cache entry for `useFirestorePaginated`, stored at `[...queryKey, 'page', n]`:\n * the page's rows, its last row (the next page's cursor; `null` for an empty page), and\n * whether a further page exists (read with a one-row look-ahead), and the id of the row it\n * was read after (`null` for page 1), checked against the previous page's cursor.\n */\nexport interface PaginatedPage<T> {\n items: T[];\n cursor: DocumentSnapshot | null;\n hasMore: boolean;\n after: string | null;\n}\n\n/**\n * Mutation operation types for batch mutations.\n */\nexport type MutationOperation =\n | { type: 'set'; docPath: string; data: DocumentData; merge?: boolean }\n | { type: 'update'; docPath: string; data: DocumentData }\n | { type: 'delete'; docPath: string };\n\n/**\n * Options for document mutations.\n */\nexport interface FirestoreMutationOptions<T> {\n /** Document path for single-doc mutations */\n docPath?: string;\n /** Query keys to invalidate on success */\n invalidateKeys?: readonly unknown[][];\n /** Enable optimistic updates */\n optimistic?: {\n /** Query key of the cache to update */\n queryKey: readonly unknown[];\n /** How to update the cached data */\n updater: (oldData: T | undefined, newData: Partial<T>) => T;\n };\n}\n\n/**\n * Options for batch mutations.\n */\nexport interface FirestoreBatchOptions {\n /** Query keys to invalidate on success */\n invalidateKeys?: readonly unknown[][];\n /** Max operations per batch (default: 450) */\n batchSize?: number;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"","sourcesContent":["export type WithId<T> = T & { id: string };\n\n/** Firestore serves cached snapshots offline without firing the error callback, so liveness is read from `metadata.fromCache`. */\nexport type FirestoreSourceState = 'connecting' | 'live' | 'offline' | 'error';\n\nexport type WithSourceState<R> = R & { sourceState: FirestoreSourceState };\n\nexport type BatchFirestoreDocOutcome<T> =\n | { status: 'loading' }\n | { status: 'present'; data: T }\n | { status: 'absent' }\n | { status: 'failed'; error: Error; retrying: boolean };\n\nexport interface FirestoreBaseOptions {\n queryKey: readonly unknown[];\n enabled?: boolean;\n staleTime?: number;\n gcTime?: number;\n}\n\nexport interface FirestoreMutationOptions<T> {\n docPath?: string;\n invalidateKeys?: readonly unknown[][];\n optimistic?: {\n queryKey: readonly unknown[];\n updater: (oldData: T | undefined, newData: Partial<T>) => T;\n };\n}\n\nexport interface FirestoreBatchOptions {\n invalidateKeys?: readonly unknown[][];\n batchSize?: number;\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,11 +1,4 @@
1
1
  export { STALE_TIMES } from './defaults.js';
2
- export { invalidateByPrefix, removeByPrefix, updateQueryData, paginatedPageKey, mapPaginatedItems, prependToFirstPaginatedPage, placeRowInPages, } from './cache-helpers.js';
3
- export type { PagedRows } from './cache-helpers.js';
4
- export type { WithId, FirestoreSourceState, WithSourceState, BatchFirestoreDocOutcome, FirestoreBaseOptions, FirestoreDocOptions, FirestoreCollectionOptions, FirestoreInfiniteOptions, FirestorePaginatedOptions, InfinitePage, PaginatedPage, MutationOperation, FirestoreMutationOptions, FirestoreBatchOptions, } from './firestore/types.js';
5
- export { docWithId } from './firestore/types.js';
6
- export { flattenInfiniteData, getInfiniteDataCount, } from './firestore/infinite-helpers.js';
7
- export type { FirestoreSearchConfig, FirestoreSearchOptions, SearchEqualityFilter, } from './search/types.js';
8
- export { FIRESTORE_SEARCH_MIN_LENGTH, isSearchableText, normalizeSearchText } from './search/rule.js';
9
- export { createDomainEventInvalidator, exact, prefix, predicate, serializeInvalidation, applyInvalidations, } from "./domain-events/index.js";
10
- export type { DomainEventInvalidator, DomainEventInvalidationRegistry, CacheAction, CacheInvalidation, RefetchType, } from "./domain-events/index.js";
2
+ export type { FirestoreSearchConfig, SearchEqualityFilter } from './search/types.js';
3
+ export { FIRESTORE_SEARCH_MIN_LENGTH, isSearchableText, normalizeSearchText, } from './search/rule.js';
11
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,YAAY,EACV,MAAM,EACN,oBAAoB,EACpB,eAAe,EACf,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,iCAAiC,CAAC;AAGzC,YAAY,EACV,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGtG,OAAO,EACL,4BAA4B,EAC5B,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,sBAAsB,EACtB,+BAA+B,EAC/B,WAAW,EACX,iBAAiB,EACjB,WAAW,GACZ,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EACL,2BAA2B,EAC3B,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,10 +1,3 @@
1
- // Query defaults & staleTime presets (server-safe — plain constants, no React runtime)
2
1
  export { STALE_TIMES } from './defaults.js';
3
- // Cache Helpers
4
- export { invalidateByPrefix, removeByPrefix, updateQueryData, paginatedPageKey, mapPaginatedItems, prependToFirstPaginatedPage, placeRowInPages, } from './cache-helpers.js';
5
- export { docWithId } from './firestore/types.js';
6
- export { flattenInfiniteData, getInfiniteDataCount, } from './firestore/infinite-helpers.js';
7
- export { FIRESTORE_SEARCH_MIN_LENGTH, isSearchableText, normalizeSearchText } from './search/rule.js';
8
- // Domain-event invalidator (mechanism — consumers register their event registry)
9
- export { createDomainEventInvalidator, exact, prefix, predicate, serializeInvalidation, applyInvalidations, } from "./domain-events/index.js";
2
+ export { FIRESTORE_SEARCH_MIN_LENGTH, isSearchableText, normalizeSearchText, } from './search/rule.js';
10
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,gBAAgB;AAChB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAoB5B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,iCAAiC,CAAC;AAQzC,OAAO,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEtG,iFAAiF;AACjF,OAAO,EACL,4BAA4B,EAC5B,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC","sourcesContent":["// Query defaults & staleTime presets (server-safe — plain constants, no React runtime)\nexport { STALE_TIMES } from './defaults.js';\n\n// Cache Helpers\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\n// Firestore Types & Pure Helpers\nexport type {\n WithId,\n FirestoreSourceState,\n WithSourceState,\n BatchFirestoreDocOutcome,\n FirestoreBaseOptions,\n FirestoreDocOptions,\n FirestoreCollectionOptions,\n FirestoreInfiniteOptions,\n FirestorePaginatedOptions,\n InfinitePage,\n PaginatedPage,\n MutationOperation,\n FirestoreMutationOptions,\n FirestoreBatchOptions,\n} from './firestore/types.js';\nexport { docWithId } from './firestore/types.js';\nexport {\n flattenInfiniteData,\n getInfiniteDataCount,\n} from './firestore/infinite-helpers.js';\n\n// Search Types\nexport type {\n FirestoreSearchConfig,\n FirestoreSearchOptions,\n SearchEqualityFilter,\n} from './search/types.js';\nexport { FIRESTORE_SEARCH_MIN_LENGTH, isSearchableText, normalizeSearchText } from './search/rule.js';\n\n// Domain-event invalidator (mechanism — consumers register their event registry)\nexport {\n createDomainEventInvalidator,\n exact,\n prefix,\n predicate,\n serializeInvalidation,\n applyInvalidations,\n} from \"./domain-events/index.js\";\nexport type {\n DomainEventInvalidator,\n DomainEventInvalidationRegistry,\n CacheAction,\n CacheInvalidation,\n RefetchType,\n} from \"./domain-events/index.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,OAAO,EACL,2BAA2B,EAC3B,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC","sourcesContent":["export { STALE_TIMES } from './defaults.js';\n\nexport type { FirestoreSearchConfig, SearchEqualityFilter } from './search/types.js';\nexport {\n FIRESTORE_SEARCH_MIN_LENGTH,\n isSearchableText,\n normalizeSearchText,\n} from './search/rule.js';\n"]}
package/dist/keys.d.ts CHANGED
@@ -1,21 +1,3 @@
1
- /**
2
- * Lightweight, stable, Firestore-safe query key helpers.
3
- *
4
- * All keys are arrays of `string | number | boolean | null` so they can
5
- * be written into Firestore docs (used by the unified upload pipeline's
6
- * `result.invalidate` field) and read back by the frontend hook to call
7
- * `queryClient.invalidateQueries`. Both sides produce structurally
8
- * identical arrays.
9
- *
10
- * Convention:
11
- * - `keys.user.all` => ['user']
12
- * - `keys.user.detail(id)` => ['user', 'detail', id]
13
- * - `keys.user.list(param?)` => ['user', 'list', param?]
14
- * - `keys.user.custom('accountStatus', id)` => ['user', 'accountStatus', id]
15
- *
16
- * For list filters that need multiple discriminators, use `custom`:
17
- * keys.feedback.custom('list', filter, sortBy)
18
- */
19
1
  type SerializedKeyPart = string | number | boolean | null | undefined;
20
2
  export type QueryKey = ReadonlyArray<string | number | boolean | null>;
21
3
  export declare const keys: {
@@ -81,10 +63,6 @@ export declare const keys: {
81
63
  };
82
64
  readonly custom: (...parts: SerializedKeyPart[]) => QueryKey;
83
65
  };
84
- /**
85
- * Utility for apps that want to define their own scoped key sets
86
- * while following the same conventions.
87
- */
88
66
  export declare function createKeyScope(scope: string): {
89
67
  readonly all: QueryKey;
90
68
  readonly detail: (id: string) => QueryKey;
@@ -1 +1 @@
1
- {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAEtE,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;AAOvE,eAAO,MAAM,IAAI;;;8BAGA,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;gCAErB,iBAAiB,EAAE;CAC9B,CAAC;AAEX;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM;;0BAG3B,MAAM;4BACJ,iBAAiB;gCACb,iBAAiB,EAAE;EAEzC"}
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA,KAAK,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAEtE,MAAM,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;AAOvE,eAAO,MAAM,IAAI;;;8BAGA,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;;;8BAIzB,MAAM;gCACJ,iBAAiB;oCACb,iBAAiB,EAAE;;gCAErB,iBAAiB,EAAE;CAC9B,CAAC;AAEX,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM;;0BAG3B,MAAM;4BACJ,iBAAiB;gCACb,iBAAiB,EAAE;EAEzC"}
package/dist/keys.js CHANGED
@@ -65,10 +65,6 @@ export const keys = {
65
65
  },
66
66
  custom: (...parts) => withScope('custom', ...parts),
67
67
  };
68
- /**
69
- * Utility for apps that want to define their own scoped key sets
70
- * while following the same conventions.
71
- */
72
68
  export function createKeyScope(scope) {
73
69
  return {
74
70
  all: withScope(scope),
package/dist/keys.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Lightweight, stable, Firestore-safe query key helpers.\n *\n * All keys are arrays of `string | number | boolean | null` so they can\n * be written into Firestore docs (used by the unified upload pipeline's\n * `result.invalidate` field) and read back by the frontend hook to call\n * `queryClient.invalidateQueries`. Both sides produce structurally\n * identical arrays.\n *\n * Convention:\n * - `keys.user.all` => ['user']\n * - `keys.user.detail(id)` => ['user', 'detail', id]\n * - `keys.user.list(param?)` => ['user', 'list', param?]\n * - `keys.user.custom('accountStatus', id)` => ['user', 'accountStatus', id]\n *\n * For list filters that need multiple discriminators, use `custom`:\n * keys.feedback.custom('list', filter, sortBy)\n */\ntype SerializedKeyPart = string | number | boolean | null | undefined;\n\nexport type QueryKey = ReadonlyArray<string | number | boolean | null>;\n\nfunction withScope(scope: string, ...parts: SerializedKeyPart[]): QueryKey {\n const cleaned = parts.filter((p): p is Exclude<SerializedKeyPart, undefined> => p !== undefined);\n return [scope, ...cleaned] as const;\n}\n\nexport const keys = {\n user: {\n all: withScope('user'),\n detail: (id: string) => withScope('user', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('user', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('user', ...parts),\n },\n follows: {\n all: withScope('follows'),\n detail: (id: string) => withScope('follows', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('follows', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('follows', ...parts),\n },\n entities: {\n all: withScope('entities'),\n detail: (id: string) => withScope('entities', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('entities', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('entities', ...parts),\n },\n messages: {\n all: withScope('messages'),\n detail: (id: string) => withScope('messages', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('messages', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('messages', ...parts),\n },\n admin: {\n all: withScope('admin'),\n detail: (id: string) => withScope('admin', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('admin', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('admin', ...parts),\n },\n chat: {\n all: withScope('chat'),\n detail: (id: string) => withScope('chat', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('chat', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('chat', ...parts),\n },\n notifications: {\n all: withScope('notifications'),\n detail: (id: string) => withScope('notifications', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('notifications', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('notifications', ...parts),\n },\n shortLinks: {\n all: withScope('shortLinks'),\n detail: (id: string) => withScope('shortLinks', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('shortLinks', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('shortLinks', ...parts),\n },\n mentions: {\n all: withScope('mentions'),\n detail: (id: string) => withScope('mentions', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('mentions', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('mentions', ...parts),\n },\n feedback: {\n all: withScope('feedback'),\n detail: (id: string) => withScope('feedback', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('feedback', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('feedback', ...parts),\n },\n custom: (...parts: SerializedKeyPart[]) => withScope('custom', ...parts),\n} as const;\n\n/**\n * Utility for apps that want to define their own scoped key sets\n * while following the same conventions.\n */\nexport function createKeyScope(scope: string) {\n return {\n all: withScope(scope),\n detail: (id: string) => withScope(scope, 'detail', id),\n list: (param?: SerializedKeyPart) => withScope(scope, 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope(scope, ...parts),\n } as const;\n}\n"]}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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","sourcesContent":["type SerializedKeyPart = string | number | boolean | null | undefined;\n\nexport type QueryKey = ReadonlyArray<string | number | boolean | null>;\n\nfunction withScope(scope: string, ...parts: SerializedKeyPart[]): QueryKey {\n const cleaned = parts.filter((p): p is Exclude<SerializedKeyPart, undefined> => p !== undefined);\n return [scope, ...cleaned] as const;\n}\n\nexport const keys = {\n user: {\n all: withScope('user'),\n detail: (id: string) => withScope('user', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('user', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('user', ...parts),\n },\n follows: {\n all: withScope('follows'),\n detail: (id: string) => withScope('follows', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('follows', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('follows', ...parts),\n },\n entities: {\n all: withScope('entities'),\n detail: (id: string) => withScope('entities', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('entities', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('entities', ...parts),\n },\n messages: {\n all: withScope('messages'),\n detail: (id: string) => withScope('messages', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('messages', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('messages', ...parts),\n },\n admin: {\n all: withScope('admin'),\n detail: (id: string) => withScope('admin', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('admin', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('admin', ...parts),\n },\n chat: {\n all: withScope('chat'),\n detail: (id: string) => withScope('chat', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('chat', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('chat', ...parts),\n },\n notifications: {\n all: withScope('notifications'),\n detail: (id: string) => withScope('notifications', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('notifications', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('notifications', ...parts),\n },\n shortLinks: {\n all: withScope('shortLinks'),\n detail: (id: string) => withScope('shortLinks', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('shortLinks', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('shortLinks', ...parts),\n },\n mentions: {\n all: withScope('mentions'),\n detail: (id: string) => withScope('mentions', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('mentions', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('mentions', ...parts),\n },\n feedback: {\n all: withScope('feedback'),\n detail: (id: string) => withScope('feedback', 'detail', id),\n list: (param?: SerializedKeyPart) => withScope('feedback', 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope('feedback', ...parts),\n },\n custom: (...parts: SerializedKeyPart[]) => withScope('custom', ...parts),\n} as const;\n\nexport function createKeyScope(scope: string) {\n return {\n all: withScope(scope),\n detail: (id: string) => withScope(scope, 'detail', id),\n list: (param?: SerializedKeyPart) => withScope(scope, 'list', param),\n custom: (...parts: SerializedKeyPart[]) => withScope(scope, ...parts),\n } as const;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import type { InfiniteData, QueryClient, QueryKey } from '@tanstack/react-query';
2
+ export declare function invalidateByPrefix(client: QueryClient, prefix: QueryKey): Promise<void>;
3
+ export declare function removeByPrefix(client: QueryClient, prefix: QueryKey): void;
4
+ export declare function updateQueryData<T>(client: QueryClient, key: QueryKey, updater: (prev: T | undefined) => T): void;
5
+ export declare function paginatedPageKey(queryKey: QueryKey, page: number): QueryKey;
6
+ export declare function mapPaginatedItems<T>(client: QueryClient, queryKey: QueryKey, mapItem: (item: T) => T): void;
7
+ export declare function prependToFirstPaginatedPage<T>(client: QueryClient, queryKey: QueryKey, item: T): void;
8
+ export interface PagedRows<P, T> {
9
+ rowsOf: (page: P) => readonly T[];
10
+ withRows: (page: P, rows: T[]) => P;
11
+ isRow: (candidate: T) => boolean;
12
+ sortsBefore: (a: T, b: T) => boolean;
13
+ hasMoreAfter: (page: P) => boolean;
14
+ }
15
+ export declare function placeRowInPages<P, T, TParam = unknown>(data: InfiniteData<P, TParam> | undefined, row: T, belongs: boolean, how: PagedRows<P, T>): InfiniteData<P, TParam> | undefined;
16
+ //# sourceMappingURL=cache-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-helpers.d.ts","sourceRoot":"","sources":["../../src/react/cache-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGjF,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,iBAE7E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,QAEnE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAC/B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,QAAQ,EACb,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK,CAAC,QAGpC;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAE3E;AAeD,wBAAgB,iBAAiB,CAAC,CAAC,EACjC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GACtB,IAAI,CAWN;AAED,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,GACN,IAAI,CAKN;AAED,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC;IAC7B,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC,EAAE,CAAC;IAClC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IACpC,KAAK,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO,CAAC;IACjC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IACrC,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CACpC;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,EACpD,IAAI,EAAE,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,SAAS,EACzC,GAAG,EAAE,CAAC,EACN,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GACnB,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,SAAS,CA2BrC"}
@@ -1,19 +1,12 @@
1
- /** Invalidate everything that matches a key prefix. */
2
1
  export async function invalidateByPrefix(client, prefix) {
3
2
  return client.invalidateQueries({ queryKey: prefix, exact: false });
4
3
  }
5
- /** Remove everything that matches a key prefix (drops cached data). */
6
4
  export function removeByPrefix(client, prefix) {
7
5
  return client.removeQueries({ queryKey: prefix, exact: false });
8
6
  }
9
- /**
10
- * Generic cache update helper.
11
- * Useful for optimistic updates without baking in business logic.
12
- */
13
7
  export function updateQueryData(client, key, updater) {
14
8
  client.setQueryData(key, (prev) => updater(prev));
15
9
  }
16
- /** The cache key of page `page` of a `useFirestorePaginated` list keyed `queryKey`. */
17
10
  export function paginatedPageKey(queryKey, page) {
18
11
  return [...queryKey, 'page', page];
19
12
  }
@@ -26,12 +19,6 @@ function isPaginatedPage(value) {
26
19
  function isPageKey(baseKey, key) {
27
20
  return key.length === baseKey.length + 2 && key[baseKey.length] === 'page';
28
21
  }
29
- /**
30
- * Patch rows in place across every cached page of a `useFirestorePaginated` list
31
- * (`queryKey` is the base key the hook was given). Return the same row to leave it
32
- * unchanged; a page with no changed row keeps its identity. Cursors and has-more are
33
- * untouched, so paging stays aligned with the server.
34
- */
35
22
  export function mapPaginatedItems(client, queryKey, mapItem) {
36
23
  for (const [key, value] of client.getQueriesData({ queryKey })) {
37
24
  if (!isPageKey(queryKey, key) || !isPaginatedPage(value))
@@ -47,13 +34,6 @@ export function mapPaginatedItems(client, queryKey, mapItem) {
47
34
  client.setQueryData(key, { ...value, items });
48
35
  }
49
36
  }
50
- /**
51
- * Put a just-created row at the top of page 1 of a `useFirestorePaginated` list, only
52
- * when page 1 is cached. Use it only for a list ordered newest-first. Page 1 keeps its
53
- * cursor, so it shows one extra row and page 2 keeps its place until page 1 is next read;
54
- * that read moves page 1's cursor, and the hook then re-reads page 2 from the new cursor
55
- * before showing it.
56
- */
57
37
  export function prependToFirstPaginatedPage(client, queryKey, item) {
58
38
  const key = paginatedPageKey(queryKey, 1);
59
39
  const value = client.getQueryData(key);
@@ -61,14 +41,6 @@ export function prependToFirstPaginatedPage(client, queryKey, item) {
61
41
  return;
62
42
  client.setQueryData(key, { ...value, items: [item, ...value.items] });
63
43
  }
64
- /**
65
- * Place, move, or drop ONE row in a cached infinite list's loaded pages, in place: the row leaves
66
- * wherever it sits and, when `belongs`, joins at its position in the list's own order. A row that
67
- * sorts after every loaded row is added only when no further page exists; otherwise the next page
68
- * read returns it, so placing it here would list it twice. Every other row, every page, and every
69
- * cursor stays put; a list the row neither left nor joined is returned as it was. Never a reset to the
70
- * first page.
71
- */
72
44
  export function placeRowInPages(data, row, belongs, how) {
73
45
  if (!data || data.pages.length === 0)
74
46
  return data;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-helpers.js","sourceRoot":"","sources":["../../src/react/cache-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InfiniteData, QueryClient, QueryKey } from '@tanstack/react-query';\nimport type { PaginatedPage } from './firestore/types.js';\n\nexport async function invalidateByPrefix(client: QueryClient, prefix: QueryKey) {\n return client.invalidateQueries({ queryKey: prefix, exact: false });\n}\n\nexport function removeByPrefix(client: QueryClient, prefix: QueryKey) {\n return client.removeQueries({ queryKey: prefix, exact: false });\n}\n\nexport function updateQueryData<T>(\n client: QueryClient,\n key: QueryKey,\n updater: (prev: T | undefined) => T,\n) {\n client.setQueryData<T>(key, (prev) => updater(prev));\n}\n\nexport function paginatedPageKey(queryKey: QueryKey, page: number): QueryKey {\n return [...queryKey, 'page', page];\n}\n\nfunction isPaginatedPage(value: unknown): value is PaginatedPage<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n Array.isArray((value as { items?: unknown }).items) &&\n typeof (value as { hasMore?: unknown }).hasMore === 'boolean'\n );\n}\n\nfunction isPageKey(baseKey: QueryKey, key: QueryKey): boolean {\n return key.length === baseKey.length + 2 && key[baseKey.length] === 'page';\n}\n\nexport function mapPaginatedItems<T>(\n client: QueryClient,\n queryKey: QueryKey,\n mapItem: (item: T) => T,\n): void {\n for (const [key, value] of client.getQueriesData<PaginatedPage<T>>({ queryKey })) {\n if (!isPageKey(queryKey, key) || !isPaginatedPage(value)) continue;\n let changed = false;\n const items = value.items.map((item) => {\n const next = mapItem(item as T);\n if (next !== item) changed = true;\n return next;\n });\n if (changed) client.setQueryData<PaginatedPage<T>>(key, { ...value, items });\n }\n}\n\nexport function prependToFirstPaginatedPage<T>(\n client: QueryClient,\n queryKey: QueryKey,\n item: T,\n): void {\n const key = paginatedPageKey(queryKey, 1);\n const value = client.getQueryData<PaginatedPage<T>>(key);\n if (!isPaginatedPage(value)) return;\n client.setQueryData<PaginatedPage<T>>(key, { ...value, items: [item, ...value.items] });\n}\n\nexport interface PagedRows<P, T> {\n rowsOf: (page: P) => readonly T[];\n withRows: (page: P, rows: T[]) => P;\n isRow: (candidate: T) => boolean;\n sortsBefore: (a: T, b: T) => boolean;\n hasMoreAfter: (page: P) => boolean;\n}\n\nexport function placeRowInPages<P, T, TParam = unknown>(\n data: InfiniteData<P, TParam> | undefined,\n row: T,\n belongs: boolean,\n how: PagedRows<P, T>,\n): InfiniteData<P, TParam> | undefined {\n if (!data || data.pages.length === 0) return data;\n let changed = false;\n const rows = data.pages.map((page) => {\n const kept = how.rowsOf(page).filter((candidate) => !how.isRow(candidate));\n if (kept.length !== how.rowsOf(page).length) changed = true;\n return kept;\n });\n if (belongs) {\n let placed = false;\n for (const pageRows of rows) {\n const index = pageRows.findIndex((candidate) => how.sortsBefore(row, candidate));\n if (index !== -1) {\n pageRows.splice(index, 0, row);\n placed = true;\n break;\n }\n }\n const lastIndex = data.pages.length - 1;\n if (!placed && !how.hasMoreAfter(data.pages[lastIndex])) {\n rows[lastIndex].push(row);\n placed = true;\n }\n changed = changed || placed;\n }\n if (!changed) return data;\n return { ...data, pages: data.pages.map((page, i) => how.withRows(page, rows[i])) };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { DefaultOptions, QueryClientConfig } from '@tanstack/react-query';
2
+ export declare const defaultQueryOptions: DefaultOptions;
3
+ export declare const defaultQueryClientConfig: QueryClientConfig;
4
+ //# sourceMappingURL=defaults.d.ts.map