@ttt-productions/query-core 0.14.20 → 0.14.22
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.
- package/dist/defaults.d.ts +0 -7
- package/dist/defaults.d.ts.map +1 -1
- package/dist/defaults.js +0 -20
- package/dist/defaults.js.map +1 -1
- package/dist/firestore/types.d.ts +0 -142
- package/dist/firestore/types.d.ts.map +1 -1
- package/dist/firestore/types.js +1 -6
- package/dist/firestore/types.js.map +1 -1
- package/dist/index.d.ts +2 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -7
- package/dist/index.js.map +1 -1
- package/dist/react/cache-helpers.d.ts.map +1 -0
- package/dist/react/cache-helpers.js.map +1 -0
- package/dist/react/defaults.d.ts +8 -0
- package/dist/react/defaults.d.ts.map +1 -0
- package/dist/react/defaults.js +21 -0
- package/dist/react/defaults.js.map +1 -0
- package/dist/{domain-events → react/domain-events}/cache-invalidation.d.ts +8 -8
- package/dist/react/domain-events/cache-invalidation.d.ts.map +1 -0
- package/dist/{domain-events → react/domain-events}/cache-invalidation.js +28 -17
- package/dist/react/domain-events/cache-invalidation.js.map +1 -0
- package/dist/{domain-events → react/domain-events}/create-domain-event-invalidator.d.ts +4 -4
- package/dist/react/domain-events/create-domain-event-invalidator.d.ts.map +1 -0
- package/dist/{domain-events → react/domain-events}/create-domain-event-invalidator.js +1 -1
- package/dist/react/domain-events/create-domain-event-invalidator.js.map +1 -0
- package/dist/react/firestore/context.d.ts.map +1 -1
- package/dist/react/firestore/context.js +1 -1
- package/dist/react/firestore/context.js.map +1 -1
- package/dist/react/firestore/doc-subscription-registry.d.ts.map +1 -1
- package/dist/react/firestore/doc-subscription-registry.js +5 -1
- package/dist/react/firestore/doc-subscription-registry.js.map +1 -1
- package/dist/{firestore → react/firestore}/infinite-helpers.d.ts +2 -1
- package/dist/react/firestore/infinite-helpers.d.ts.map +1 -0
- package/dist/react/firestore/infinite-helpers.js.map +1 -0
- package/dist/react/firestore/types.d.ts +144 -0
- package/dist/react/firestore/types.d.ts.map +1 -0
- package/dist/react/firestore/types.js +7 -0
- package/dist/react/firestore/types.js.map +1 -0
- package/dist/react/firestore/use-firestore-collection.d.ts +2 -1
- package/dist/react/firestore/use-firestore-collection.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-collection.js +22 -9
- package/dist/react/firestore/use-firestore-collection.js.map +1 -1
- package/dist/react/firestore/use-firestore-count.d.ts +1 -1
- package/dist/react/firestore/use-firestore-count.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-count.js.map +1 -1
- package/dist/react/firestore/use-firestore-doc.d.ts +2 -1
- package/dist/react/firestore/use-firestore-doc.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-doc.js +18 -2
- package/dist/react/firestore/use-firestore-doc.js.map +1 -1
- package/dist/react/firestore/use-firestore-infinite.d.ts +1 -1
- package/dist/react/firestore/use-firestore-infinite.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-infinite.js.map +1 -1
- package/dist/react/firestore/use-firestore-live-infinite.d.ts +2 -1
- package/dist/react/firestore/use-firestore-live-infinite.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-live-infinite.js +9 -1
- package/dist/react/firestore/use-firestore-live-infinite.js.map +1 -1
- package/dist/react/firestore/use-firestore-mutations.d.ts +2 -1
- package/dist/react/firestore/use-firestore-mutations.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-mutations.js +3 -3
- package/dist/react/firestore/use-firestore-mutations.js.map +1 -1
- package/dist/react/firestore/use-firestore-paginated.d.ts +2 -1
- package/dist/react/firestore/use-firestore-paginated.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-paginated.js +6 -3
- package/dist/react/firestore/use-firestore-paginated.js.map +1 -1
- package/dist/react/firestore/useBatchFirestoreDocs.d.ts.map +1 -1
- package/dist/react/firestore/useBatchFirestoreDocs.js +7 -3
- package/dist/react/firestore/useBatchFirestoreDocs.js.map +1 -1
- package/dist/react/index.d.ts +13 -4
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +11 -3
- package/dist/react/index.js.map +1 -1
- package/dist/react/pending-mutations.d.ts +1 -1
- package/dist/react/pending-mutations.d.ts.map +1 -1
- package/dist/react/pending-mutations.js +6 -6
- package/dist/react/pending-mutations.js.map +1 -1
- package/dist/react/provider.d.ts +1 -1
- package/dist/react/provider.d.ts.map +1 -1
- package/dist/react/provider.js +1 -1
- package/dist/react/provider.js.map +1 -1
- package/dist/react/query-client.d.ts.map +1 -0
- package/dist/react/query-client.js.map +1 -0
- package/dist/react/search/types.d.ts +28 -0
- package/dist/react/search/types.d.ts.map +1 -0
- package/dist/react/search/types.js +2 -0
- package/dist/react/search/types.js.map +1 -0
- package/dist/react/search/use-firestore-search.d.ts +1 -1
- package/dist/react/search/use-firestore-search.d.ts.map +1 -1
- package/dist/react/search/use-firestore-search.js.map +1 -1
- package/dist/react/use-read-retry-state.d.ts.map +1 -1
- package/dist/react/use-read-retry-state.js +1 -1
- package/dist/react/use-read-retry-state.js.map +1 -1
- package/dist/search/types.d.ts +0 -26
- package/dist/search/types.d.ts.map +1 -1
- package/dist/search/types.js.map +1 -1
- package/package.json +2 -2
- package/dist/cache-helpers.d.ts.map +0 -1
- package/dist/cache-helpers.js.map +0 -1
- package/dist/domain-events/cache-invalidation.d.ts.map +0 -1
- package/dist/domain-events/cache-invalidation.js.map +0 -1
- package/dist/domain-events/create-domain-event-invalidator.d.ts.map +0 -1
- package/dist/domain-events/create-domain-event-invalidator.js.map +0 -1
- package/dist/domain-events/index.d.ts +0 -5
- package/dist/domain-events/index.d.ts.map +0 -1
- package/dist/domain-events/index.js +0 -3
- package/dist/domain-events/index.js.map +0 -1
- package/dist/firestore/infinite-helpers.d.ts.map +0 -1
- package/dist/firestore/infinite-helpers.js.map +0 -1
- package/dist/query-client.d.ts.map +0 -1
- package/dist/query-client.js.map +0 -1
- /package/dist/{cache-helpers.d.ts → react/cache-helpers.d.ts} +0 -0
- /package/dist/{cache-helpers.js → react/cache-helpers.js} +0 -0
- /package/dist/{firestore → react/firestore}/infinite-helpers.js +0 -0
- /package/dist/{query-client.d.ts → react/query-client.d.ts} +0 -0
- /package/dist/{query-client.js → react/query-client.js} +0 -0
package/dist/defaults.d.ts
CHANGED
|
@@ -1,10 +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
1
|
/**
|
|
9
2
|
* Named `staleTime` presets (milliseconds) for React Query call sites.
|
|
10
3
|
*
|
package/dist/defaults.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW;;;;;CAKd,CAAC"}
|
package/dist/defaults.js
CHANGED
|
@@ -1,23 +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
1
|
/**
|
|
22
2
|
* Named `staleTime` presets (milliseconds) for React Query call sites.
|
|
23
3
|
*
|
package/dist/defaults.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;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":["/**\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,4 +1,3 @@
|
|
|
1
|
-
import type { DocumentData, DocumentSnapshot, QueryDocumentSnapshot, QueryConstraint } from 'firebase/firestore';
|
|
2
1
|
/**
|
|
3
2
|
* Document with ID included in the data object.
|
|
4
3
|
*/
|
|
@@ -47,10 +46,6 @@ export type BatchFirestoreDocOutcome<T> = {
|
|
|
47
46
|
error: Error;
|
|
48
47
|
retrying: boolean;
|
|
49
48
|
};
|
|
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
49
|
/**
|
|
55
50
|
* Base options shared across all Firestore hooks.
|
|
56
51
|
*/
|
|
@@ -64,143 +59,6 @@ export interface FirestoreBaseOptions {
|
|
|
64
59
|
/** Garbage collection time override (ms) */
|
|
65
60
|
gcTime?: number;
|
|
66
61
|
}
|
|
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
62
|
/**
|
|
205
63
|
* Options for document mutations.
|
|
206
64
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/E,yFAAyF;AACzF,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,WAAW,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAE3E;;;;;;;;;;;GAWG;AACH,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;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,4BAA4B;IAC5B,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+BAA+B;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0CAA0C;IAC1C,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC;IACtC,gCAAgC;IAChC,UAAU,CAAC,EAAE;QACX,uCAAuC;QACvC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;QAC7B,oCAAoC;QACpC,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;KAC7D,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,0CAA0C;IAC1C,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC;IACtC,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
package/dist/firestore/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\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 * 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 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"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
1
|
export { STALE_TIMES } from './defaults.js';
|
|
2
|
-
export {
|
|
3
|
-
export
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,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,4 @@
|
|
|
1
1
|
// Query defaults & staleTime presets (server-safe — plain constants, no React runtime)
|
|
2
2
|
export { STALE_TIMES } from './defaults.js';
|
|
3
|
-
|
|
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";
|
|
3
|
+
export { FIRESTORE_SEARCH_MIN_LENGTH, isSearchableText, normalizeSearchText, } from './search/rule.js';
|
|
10
4
|
//# 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;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAI5C,OAAO,EACL,2BAA2B,EAC3B,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC","sourcesContent":["// Query defaults & staleTime presets (server-safe — plain constants, no React runtime)\nexport { STALE_TIMES } from './defaults.js';\n\n// Search Types\nexport type { FirestoreSearchConfig, SearchEqualityFilter } from './search/types.js';\nexport {\n FIRESTORE_SEARCH_MIN_LENGTH,\n isSearchableText,\n normalizeSearchText,\n} from './search/rule.js';\n"]}
|
|
@@ -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,uDAAuD;AACvD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,iBAE7E;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,QAEnE;AAED;;;GAGG;AACH,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,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAE3E;AAeD;;;;;GAKG;AACH,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;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,CAAC,GACN,IAAI,CAKN;AAED,wEAAwE;AACxE,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,8DAA8D;IAC9D,KAAK,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO,CAAC;IACjC,8DAA8D;IAC9D,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC;IACrC,qFAAqF;IACrF,YAAY,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,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"}
|
|
@@ -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\n/** Invalidate everything that matches a key prefix. */\nexport async function invalidateByPrefix(client: QueryClient, prefix: QueryKey) {\n return client.invalidateQueries({ queryKey: prefix, exact: false });\n}\n\n/** Remove everything that matches a key prefix (drops cached data). */\nexport function removeByPrefix(client: QueryClient, prefix: QueryKey) {\n return client.removeQueries({ queryKey: prefix, exact: false });\n}\n\n/**\n * Generic cache update helper.\n * Useful for optimistic updates without baking in business logic.\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\n/** The cache key of page `page` of a `useFirestorePaginated` list keyed `queryKey`. */\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\n/**\n * Patch rows in place across every cached page of a `useFirestorePaginated` list\n * (`queryKey` is the base key the hook was given). Return the same row to leave it\n * unchanged; a page with no changed row keeps its identity. Cursors and has-more are\n * untouched, so paging stays aligned with the server.\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\n/**\n * Put a just-created row at the top of page 1 of a `useFirestorePaginated` list, only\n * when page 1 is cached. Use it only for a list ordered newest-first. Page 1 keeps its\n * cursor, so it shows one extra row and page 2 keeps its place until page 1 is next read;\n * that read moves page 1's cursor, and the hook then re-reads page 2 from the new cursor\n * before showing it.\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\n/** How `placeRowInPages` reads and writes one infinite list's pages. */\nexport interface PagedRows<P, T> {\n rowsOf: (page: P) => readonly T[];\n withRows: (page: P, rows: T[]) => P;\n /** True when `candidate` is the row being placed (its id). */\n isRow: (candidate: T) => boolean;\n /** True when `a` comes before `b` in the list's own order. */\n sortsBefore: (a: T, b: T) => boolean;\n /** True when this page is not the last one the source holds (a next page exists). */\n hasMoreAfter: (page: P) => boolean;\n}\n\n/**\n * Place, move, or drop ONE row in a cached infinite list's loaded pages, in place: the row leaves\n * wherever it sits and, when `belongs`, joins at its position in the list's own order. A row that\n * sorts after every loaded row is added only when no further page exists; otherwise the next page\n * read returns it, so placing it here would list it twice. Every other row, every page, and every\n * cursor stays put; a list the row neither left nor joined is returned as it was. Never a reset to the\n * first page.\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,8 @@
|
|
|
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
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/react/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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/react/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","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"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Query, QueryClient, QueryKey } from
|
|
2
|
-
export type RefetchType =
|
|
1
|
+
import type { Query, QueryClient, QueryKey } from '@tanstack/react-query';
|
|
2
|
+
export type RefetchType = 'active' | 'all' | 'none';
|
|
3
3
|
/**
|
|
4
4
|
* What an entry does to the queries it matches:
|
|
5
5
|
* - `"refresh"` (the default) marks them stale and refetches per `refetchType`;
|
|
@@ -7,19 +7,19 @@ export type RefetchType = "active" | "all" | "none";
|
|
|
7
7
|
* held answer that must not be served again;
|
|
8
8
|
* - `"reset"` returns them to their initial state and refetches the active ones from scratch.
|
|
9
9
|
*/
|
|
10
|
-
export type CacheAction =
|
|
10
|
+
export type CacheAction = 'refresh' | 'remove' | 'reset';
|
|
11
11
|
export type CacheInvalidation = {
|
|
12
|
-
kind:
|
|
12
|
+
kind: 'exact';
|
|
13
13
|
queryKey: QueryKey;
|
|
14
14
|
refetchType?: RefetchType;
|
|
15
15
|
action?: CacheAction;
|
|
16
16
|
} | {
|
|
17
|
-
kind:
|
|
17
|
+
kind: 'prefix';
|
|
18
18
|
queryKey: QueryKey;
|
|
19
19
|
refetchType?: RefetchType;
|
|
20
20
|
action?: CacheAction;
|
|
21
21
|
} | {
|
|
22
|
-
kind:
|
|
22
|
+
kind: 'predicate';
|
|
23
23
|
description: string;
|
|
24
24
|
match: (query: Query) => boolean;
|
|
25
25
|
refetchType?: RefetchType;
|
|
@@ -28,9 +28,9 @@ export type CacheInvalidation = {
|
|
|
28
28
|
/** `refetchType` belongs to a refresh; a remove or reset takes none. */
|
|
29
29
|
type EntryOptions = {
|
|
30
30
|
refetchType?: RefetchType;
|
|
31
|
-
action?:
|
|
31
|
+
action?: 'refresh';
|
|
32
32
|
} | {
|
|
33
|
-
action:
|
|
33
|
+
action: 'remove' | 'reset';
|
|
34
34
|
};
|
|
35
35
|
export declare function exact(queryKey: QueryKey, opts?: EntryOptions): CacheInvalidation;
|
|
36
36
|
export declare function prefix(queryKey: QueryKey, opts?: EntryOptions): CacheInvalidation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-invalidation.d.ts","sourceRoot":"","sources":["../../../src/react/domain-events/cache-invalidation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAgB,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAExF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEzD,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GACvF;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IACjC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEN,wEAAwE;AACxE,KAAK,YAAY,GACf;IAAE,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,CAAC;AAOrF,wBAAgB,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAEhF;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAEjF;AAED,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,EAChC,IAAI,CAAC,EAAE,YAAY,GAClB,iBAAiB,CAEnB;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM,CAIpE;AA4CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,CAAC,iBAAiB,CAAC,GAC9C,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
const entryFields = (opts) => ({
|
|
2
|
-
refetchType: opts &&
|
|
2
|
+
refetchType: opts && 'refetchType' in opts ? opts.refetchType : undefined,
|
|
3
3
|
action: opts?.action,
|
|
4
4
|
});
|
|
5
5
|
export function exact(queryKey, opts) {
|
|
6
|
-
return { kind:
|
|
6
|
+
return { kind: 'exact', queryKey, ...entryFields(opts) };
|
|
7
7
|
}
|
|
8
8
|
export function prefix(queryKey, opts) {
|
|
9
|
-
return { kind:
|
|
9
|
+
return { kind: 'prefix', queryKey, ...entryFields(opts) };
|
|
10
10
|
}
|
|
11
11
|
export function predicate(description, match, opts) {
|
|
12
|
-
return { kind:
|
|
12
|
+
return { kind: 'predicate', description, match, ...entryFields(opts) };
|
|
13
13
|
}
|
|
14
14
|
export function serializeInvalidation(inv) {
|
|
15
|
-
const action = inv.action && inv.action !==
|
|
16
|
-
if (inv.kind ===
|
|
15
|
+
const action = inv.action && inv.action !== 'refresh' ? `${inv.action}:` : '';
|
|
16
|
+
if (inv.kind === 'predicate')
|
|
17
17
|
return `${action}predicate:${inv.description}`;
|
|
18
18
|
return `${action}${inv.kind}:${JSON.stringify(inv.queryKey)}`;
|
|
19
19
|
}
|
|
20
20
|
/** The cache filter that selects exactly the queries one invalidation targets. */
|
|
21
21
|
function invalidationFilters(inv) {
|
|
22
|
-
if (inv.kind ===
|
|
22
|
+
if (inv.kind === 'exact')
|
|
23
23
|
return { queryKey: inv.queryKey, exact: true };
|
|
24
|
-
if (inv.kind ===
|
|
24
|
+
if (inv.kind === 'prefix')
|
|
25
25
|
return { queryKey: inv.queryKey, exact: false };
|
|
26
26
|
return { predicate: inv.match };
|
|
27
27
|
}
|
|
@@ -43,13 +43,23 @@ function invalidationFilters(inv) {
|
|
|
43
43
|
*/
|
|
44
44
|
function cancelPendingInitialReads(queryClient, filters) {
|
|
45
45
|
for (const query of queryClient.getQueryCache().findAll(filters)) {
|
|
46
|
-
if (query.state.fetchStatus !==
|
|
46
|
+
if (query.state.fetchStatus !== 'fetching')
|
|
47
47
|
continue;
|
|
48
48
|
if (query.state.data !== undefined)
|
|
49
49
|
continue;
|
|
50
50
|
void queryClient.cancelQueries({ queryKey: query.queryKey, exact: true });
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Exactly the queries `filters` matches now. A remove or reset acts in two steps — cancel then
|
|
55
|
+
* remove, reset then refetch — and the first step changes the state a predicate may read (a reset
|
|
56
|
+
* clears the failure, a cancel idles the fetch), so the second step re-applying the filter would
|
|
57
|
+
* miss the queries the entry matched.
|
|
58
|
+
*/
|
|
59
|
+
function matchedNow(queryClient, filters) {
|
|
60
|
+
const matched = new Set(queryClient.getQueryCache().findAll(filters));
|
|
61
|
+
return { predicate: (query) => matched.has(query) };
|
|
62
|
+
}
|
|
53
63
|
/**
|
|
54
64
|
* Dispatch a deduplicated list of cache invalidations.
|
|
55
65
|
*
|
|
@@ -88,21 +98,22 @@ export function applyInvalidations(queryClient, invalidations) {
|
|
|
88
98
|
continue;
|
|
89
99
|
seen.add(sig);
|
|
90
100
|
const filters = invalidationFilters(inv);
|
|
91
|
-
const action = inv.action ??
|
|
92
|
-
if (action ===
|
|
101
|
+
const action = inv.action ?? 'refresh';
|
|
102
|
+
if (action === 'remove') {
|
|
103
|
+
const matched = matchedNow(queryClient, filters);
|
|
93
104
|
// Removing a query abandons its read in flight silently, so that read never puts the dropped
|
|
94
105
|
// answer back, but a screen still watching it would go on showing it as fetching. Cancelled
|
|
95
106
|
// first, the read ends visibly and the watcher reads idle.
|
|
96
|
-
void queryClient.cancelQueries(
|
|
97
|
-
queryClient.removeQueries(
|
|
107
|
+
void queryClient.cancelQueries(matched);
|
|
108
|
+
queryClient.removeQueries(matched);
|
|
98
109
|
continue;
|
|
99
110
|
}
|
|
100
|
-
if (action ===
|
|
101
|
-
refreshes.push(queryClient.resetQueries(filters));
|
|
111
|
+
if (action === 'reset') {
|
|
112
|
+
refreshes.push(queryClient.resetQueries(matchedNow(queryClient, filters)));
|
|
102
113
|
continue;
|
|
103
114
|
}
|
|
104
|
-
const refetchType = inv.refetchType ??
|
|
105
|
-
if (refetchType !==
|
|
115
|
+
const refetchType = inv.refetchType ?? 'active';
|
|
116
|
+
if (refetchType !== 'none') {
|
|
106
117
|
cancelPendingInitialReads(queryClient, filters);
|
|
107
118
|
}
|
|
108
119
|
refreshes.push(queryClient.invalidateQueries({ ...filters, refetchType }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-invalidation.js","sourceRoot":"","sources":["../../../src/react/domain-events/cache-invalidation.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Query, QueryClient, QueryFilters, QueryKey } from '@tanstack/react-query';\n\nexport type RefetchType = 'active' | 'all' | 'none';\n\n/**\n * What an entry does to the queries it matches:\n * - `\"refresh\"` (the default) marks them stale and refetches per `refetchType`;\n * - `\"remove\"` cancels them and drops them from the cache — for data that no longer exists, or a\n * held answer that must not be served again;\n * - `\"reset\"` returns them to their initial state and refetches the active ones from scratch.\n */\nexport type CacheAction = 'refresh' | 'remove' | 'reset';\n\nexport type CacheInvalidation =\n | { kind: 'exact'; queryKey: QueryKey; refetchType?: RefetchType; action?: CacheAction }\n | { kind: 'prefix'; queryKey: QueryKey; refetchType?: RefetchType; action?: CacheAction }\n | {\n kind: 'predicate';\n description: string;\n match: (query: Query) => boolean;\n refetchType?: RefetchType;\n action?: CacheAction;\n };\n\n/** `refetchType` belongs to a refresh; a remove or reset takes none. */\ntype EntryOptions =\n { refetchType?: RefetchType; action?: 'refresh' } | { action: 'remove' | 'reset' };\n\nconst entryFields = (opts?: EntryOptions) => ({\n refetchType: opts && 'refetchType' in opts ? opts.refetchType : undefined,\n action: opts?.action,\n});\n\nexport function exact(queryKey: QueryKey, opts?: EntryOptions): CacheInvalidation {\n return { kind: 'exact', queryKey, ...entryFields(opts) };\n}\n\nexport function prefix(queryKey: QueryKey, opts?: EntryOptions): CacheInvalidation {\n return { kind: 'prefix', queryKey, ...entryFields(opts) };\n}\n\nexport function predicate(\n description: string,\n match: (query: Query) => boolean,\n opts?: EntryOptions,\n): CacheInvalidation {\n return { kind: 'predicate', description, match, ...entryFields(opts) };\n}\n\nexport function serializeInvalidation(inv: CacheInvalidation): string {\n const action = inv.action && inv.action !== 'refresh' ? `${inv.action}:` : '';\n if (inv.kind === 'predicate') return `${action}predicate:${inv.description}`;\n return `${action}${inv.kind}:${JSON.stringify(inv.queryKey)}`;\n}\n\n/** The cache filter that selects exactly the queries one invalidation targets. */\nfunction invalidationFilters(inv: CacheInvalidation): QueryFilters {\n if (inv.kind === 'exact') return { queryKey: inv.queryKey, exact: true };\n if (inv.kind === 'prefix') return { queryKey: inv.queryKey, exact: false };\n return { predicate: inv.match };\n}\n\n/**\n * Cancel every query matched by `filters` that is in a PENDING INITIAL READ —\n * currently fetching with no data yet.\n *\n * TanStack's `Query.fetch` only cancels a running request on refetch when the\n * query already holds data; an initial fetch in flight is REUSED instead, so\n * the invalidation's refetch resolves with the value the server returned BEFORE\n * the mutation committed and then marks the query fresh. Cancelling first makes\n * the invalidation's refetch a genuinely new request: the retryer is rejected\n * synchronously (its `onCancel` reverts state to idle in the same tick), so the\n * `invalidateQueries` call that follows starts a fresh fetch, and the abandoned\n * promise's late, stale resolution is discarded.\n *\n * Cancellation is always scoped to one concrete query key — never a bare\n * `cancelQueries()`.\n */\nfunction cancelPendingInitialReads(queryClient: QueryClient, filters: QueryFilters): void {\n for (const query of queryClient.getQueryCache().findAll(filters)) {\n if (query.state.fetchStatus !== 'fetching') continue;\n if (query.state.data !== undefined) continue;\n void queryClient.cancelQueries({ queryKey: query.queryKey, exact: true });\n }\n}\n\n/**\n * Exactly the queries `filters` matches now. A remove or reset acts in two steps — cancel then\n * remove, reset then refetch — and the first step changes the state a predicate may read (a reset\n * clears the failure, a cancel idles the fetch), so the second step re-applying the filter would\n * miss the queries the entry matched.\n */\nfunction matchedNow(queryClient: QueryClient, filters: QueryFilters): QueryFilters {\n const matched = new Set(queryClient.getQueryCache().findAll(filters));\n return { predicate: (query) => matched.has(query) };\n}\n\n/**\n * Dispatch a deduplicated list of cache invalidations.\n *\n * Returns a promise that resolves once every `invalidateQueries` call it issued\n * has settled — i.e. once the refetches those invalidations triggered have\n * landed. The dispatch itself stays synchronous (every cancellation and\n * invalidation is issued before this function returns), so a fire-and-forget\n * caller can ignore the promise, while a mutation `onSuccess` that\n * RETURNS or awaits the promise stays pending until the refreshed data is in\n * the cache. The promise never rejects: `invalidateQueries` refetches without\n * `throwOnError`, so a failed refetch surfaces on its own query, never as a\n * failure of the committed action that triggered it. The scoped\n * `cancelQueries` calls stay fire-and-forget — cancellation takes effect\n * synchronously and is not part of the refresh being awaited.\n *\n * Before each invalidation, any query it matches that is mid-PENDING-INITIAL-READ\n * is cancelled (see `cancelPendingInitialReads`) so a read that started before\n * the write committed can never land as the query's first — and freshly-marked —\n * value.\n *\n * `refetchType` governs whether that cancellation happens:\n * - `'active'` (the default) and `'all'` cancel-then-invalidate every matched\n * pending initial read — including one TanStack's refetch pass will not\n * restart, since a stale first value would otherwise land and mark the query\n * fresh, while a cancelled one simply refetches for its next observer.\n * - `'none'` invalidates WITHOUT cancelling: the caller has asked for no\n * refetch at all, so cancelling would abandon the only in-flight read the\n * consumer has and leave it with no data and no pending request.\n */\nexport function applyInvalidations(\n queryClient: QueryClient,\n invalidations: ReadonlyArray<CacheInvalidation>,\n): Promise<void> {\n const seen = new Set<string>();\n const refreshes: Promise<void>[] = [];\n for (const inv of invalidations) {\n const sig = serializeInvalidation(inv);\n if (seen.has(sig)) continue;\n seen.add(sig);\n\n const filters = invalidationFilters(inv);\n const action: CacheAction = inv.action ?? 'refresh';\n\n if (action === 'remove') {\n const matched = matchedNow(queryClient, filters);\n // Removing a query abandons its read in flight silently, so that read never puts the dropped\n // answer back, but a screen still watching it would go on showing it as fetching. Cancelled\n // first, the read ends visibly and the watcher reads idle.\n void queryClient.cancelQueries(matched);\n queryClient.removeQueries(matched);\n continue;\n }\n if (action === 'reset') {\n refreshes.push(queryClient.resetQueries(matchedNow(queryClient, filters)));\n continue;\n }\n\n const refetchType: RefetchType = inv.refetchType ?? 'active';\n if (refetchType !== 'none') {\n cancelPendingInitialReads(queryClient, filters);\n }\n\n refreshes.push(queryClient.invalidateQueries({ ...filters, refetchType }));\n }\n return Promise.all(refreshes).then(() => undefined);\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { QueryClient } from
|
|
2
|
-
import { exact, prefix, predicate, type CacheInvalidation } from
|
|
1
|
+
import type { QueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { exact, prefix, predicate, type CacheInvalidation } from './cache-invalidation.js';
|
|
3
3
|
/**
|
|
4
4
|
* Registry shape: each event type maps to a function from the event's `ids`
|
|
5
5
|
* payload to the list of cache invalidations that event should trigger.
|
|
@@ -8,9 +8,9 @@ export type DomainEventInvalidationRegistry<TEvent extends {
|
|
|
8
8
|
type: string;
|
|
9
9
|
ids: unknown;
|
|
10
10
|
}> = {
|
|
11
|
-
[K in TEvent[
|
|
11
|
+
[K in TEvent['type']]: (ids: Extract<TEvent, {
|
|
12
12
|
type: K;
|
|
13
|
-
}>[
|
|
13
|
+
}>['ids']) => ReadonlyArray<CacheInvalidation>;
|
|
14
14
|
};
|
|
15
15
|
export interface DomainEventInvalidator<TEvent extends {
|
|
16
16
|
type: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-domain-event-invalidator.d.ts","sourceRoot":"","sources":["../../../src/react/domain-events/create-domain-event-invalidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAEL,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAEjC;;;GAGG;AACH,MAAM,MAAM,+BAA+B,CAAC,MAAM,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,IAAI;KAC1F,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CACrB,GAAG,EAAE,OAAO,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC,KAAK,CAAC,KACrC,aAAa,CAAC,iBAAiB,CAAC;CACtC,CAAC;AAEF,MAAM,WAAW,sBAAsB,CAAC,MAAM,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE;IACnF;;;;;OAKG;IACH,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/D,mFAAmF;IACnF,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,MAAM,EAAE,OAAO,MAAM,CAAC;QACtB,SAAS,EAAE,OAAO,SAAS,CAAC;KAC7B,CAAC;IACF,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,EAAE,+BAA+B,CAAC,MAAM,CAAC,CAAC;CAC5D;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,SAAS;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,EACxF,QAAQ,EAAE,+BAA+B,CAAC,MAAM,CAAC,GAChD,sBAAsB,CAAC,MAAM,CAAC,CA4BhC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyInvalidations, exact, prefix, predicate, } from
|
|
1
|
+
import { applyInvalidations, exact, prefix, predicate, } from './cache-invalidation.js';
|
|
2
2
|
/**
|
|
3
3
|
* Build a domain-event → cache-invalidation notifier from a typed registry.
|
|
4
4
|
* The registry's keys are statically tied to `TEvent["type"]`, so missing or
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-domain-event-invalidator.js","sourceRoot":"","sources":["../../../src/react/domain-events/create-domain-event-invalidator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,KAAK,EACL,MAAM,EACN,SAAS,GAEV,MAAM,yBAAyB,CAAC;AAgCjC;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAC1C,QAAiD;IAEjD,SAAS,MAAM,CAA+B,IAAW;QACvD,OAAO,QAAQ,CAAC,IAAI,CAEiB,CAAC;IACxC,CAAC;IAED,SAAS,MAAM,CAAC,WAAwB,EAAE,KAAa;QACrD,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAsB,CAAC,CAAC;QAChD,MAAM,aAAa,GAAG,EAAE,CAAC,KAAK,CAAC,GAAuD,CAAC,CAAC;QACxF,OAAO,kBAAkB,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACxD,CAAC;IAED,SAAS,SAAS,CAAC,WAAwB,EAAE,MAA6B;QACxE,MAAM,GAAG,GAAwB,EAAE,CAAC;QACpC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,IAAsB,CAAC,CAAC;YAChD,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAuD,CAAC,CAAC,CAAC;QACjF,CAAC;QACD,OAAO,kBAAkB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO;QACL,MAAM;QACN,SAAS;QACT,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE;QACrC,QAAQ;KACT,CAAC;AACJ,CAAC","sourcesContent":["import type { QueryClient } from '@tanstack/react-query';\nimport {\n applyInvalidations,\n exact,\n prefix,\n predicate,\n type CacheInvalidation,\n} from './cache-invalidation.js';\n\n/**\n * Registry shape: each event type maps to a function from the event's `ids`\n * payload to the list of cache invalidations that event should trigger.\n */\nexport type DomainEventInvalidationRegistry<TEvent extends { type: string; ids: unknown }> = {\n [K in TEvent['type']]: (\n ids: Extract<TEvent, { type: K }>['ids'],\n ) => ReadonlyArray<CacheInvalidation>;\n};\n\nexport interface DomainEventInvalidator<TEvent extends { type: string; ids: unknown }> {\n /**\n * Dispatch the event's invalidations. The returned promise resolves once\n * every refetch they triggered has settled, and never rejects — return or\n * await it from a mutation's `onSuccess` to keep the mutation pending until\n * the refreshed data lands; ignore it for fire-and-forget dispatch.\n */\n notify(queryClient: QueryClient, event: TEvent): Promise<void>;\n /** `notify` for several events, deduplicating their invalidations as one batch. */\n notifyAll(queryClient: QueryClient, events: ReadonlyArray<TEvent>): Promise<void>;\n /** Test/debug helpers. */\n readonly helpers: {\n exact: typeof exact;\n prefix: typeof prefix;\n predicate: typeof predicate;\n };\n /** Direct access to the registry, mainly for tests. */\n readonly registry: DomainEventInvalidationRegistry<TEvent>;\n}\n\n/**\n * Build a domain-event → cache-invalidation notifier from a typed registry.\n * The registry's keys are statically tied to `TEvent[\"type\"]`, so missing or\n * extra entries are compile errors.\n */\nexport function createDomainEventInvalidator<TEvent extends { type: string; ids: unknown }>(\n registry: DomainEventInvalidationRegistry<TEvent>,\n): DomainEventInvalidator<TEvent> {\n function lookup<TType extends TEvent['type']>(type: TType) {\n return registry[type] as (\n ids: Extract<TEvent, { type: TType }>['ids'],\n ) => ReadonlyArray<CacheInvalidation>;\n }\n\n function notify(queryClient: QueryClient, event: TEvent): Promise<void> {\n const fn = lookup(event.type as TEvent['type']);\n const invalidations = fn(event.ids as Extract<TEvent, { type: TEvent['type'] }>['ids']);\n return applyInvalidations(queryClient, invalidations);\n }\n\n function notifyAll(queryClient: QueryClient, events: ReadonlyArray<TEvent>): Promise<void> {\n const all: CacheInvalidation[] = [];\n for (const event of events) {\n const fn = lookup(event.type as TEvent['type']);\n all.push(...fn(event.ids as Extract<TEvent, { type: TEvent['type'] }>['ids']));\n }\n return applyInvalidations(queryClient, all);\n }\n\n return {\n notify,\n notifyAll,\n helpers: { exact, prefix, predicate },\n registry,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAQpD,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,SAAS,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,sBAAsB,+
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/context.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAQpD,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,SAAS,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,sBAAsB,+BAEzE;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,SAAS,CAS1C"}
|