@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
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAC1C;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY;IAC3E,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAC;IACvB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uEAAuE;IACvE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,CAAC,CAAC;IACpD,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAC1C"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAC1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentData } from 'firebase/firestore';\n\n/**\n * Equality filter applied before the prefix range in a Firestore search.\n * Each becomes a `where(field, '==', value)` constraint, ordered ahead of the\n * search field. The composite index must list these equality fields (ASC)\n * before the search field (ASC).\n */\nexport interface SearchEqualityFilter {\n field: string;\n value: unknown;\n}\n\n/**\n * Configuration for a Firestore search query\n */\nexport interface FirestoreSearchConfig {\n /** Firestore collection path to search */\n collectionPath: string;\n /** Field name to search on (must be indexed and lowercase) */\n searchField: string;\n /** Maximum number of results to return */\n limit: number;\n /** Optional equality filters applied before the prefix range. */\n equalityFilters?: SearchEqualityFilter[];\n}\n\n/**\n * Options for useFirestoreSearch hook\n */\nexport interface FirestoreSearchOptions<T extends DocumentData = DocumentData> {\n /** Firestore collection path to search */\n collectionPath: string;\n /** Field name to search on (must be indexed and lowercase) */\n searchField: string;\n /** Search query text */\n queryText: string;\n /** Maximum number of results (default: 5) */\n limit?: number;\n /** Enable/disable the search (default: true) */\n enabled?: boolean;\n /** Transform function to convert raw Firestore data to typed result */\n select?: (data: DocumentData & { id: string }) => T;\n /** Debounce delay in milliseconds (default: 300) */\n debounceMs?: number;\n /** React Query stale time (default: 60000ms) */\n staleTime?: number;\n /** Optional equality filters applied before the prefix range. */\n equalityFilters?: SearchEqualityFilter[];\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/search/types.ts"],"names":[],"mappings":"","sourcesContent":["/** The composite index must list these equality fields (ASC) before the search field (ASC). */\nexport interface SearchEqualityFilter {\n field: string;\n value: unknown;\n}\n\nexport interface FirestoreSearchConfig {\n collectionPath: string;\n searchField: string;\n limit: number;\n equalityFilters?: SearchEqualityFilter[];\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/query-core",
3
- "version": "0.14.21",
3
+ "version": "0.14.23",
4
4
  "description": "Shared TanStack Query (React Query) client defaults, query key helpers, and Firestore integration hooks for TTT Productions apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -60,7 +60,7 @@
60
60
  }
61
61
  },
62
62
  "dependencies": {
63
- "@ttt-productions/firebase-helpers": "^0.12.12"
63
+ "@ttt-productions/firebase-helpers": "^0.12.15"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@tanstack/react-query": "^5.0.0",
@@ -1,48 +0,0 @@
1
- import type { InfiniteData, QueryClient, QueryKey } from '@tanstack/react-query';
2
- /** Invalidate everything that matches a key prefix. */
3
- export declare function invalidateByPrefix(client: QueryClient, prefix: QueryKey): Promise<void>;
4
- /** Remove everything that matches a key prefix (drops cached data). */
5
- export declare function removeByPrefix(client: QueryClient, prefix: QueryKey): void;
6
- /**
7
- * Generic cache update helper.
8
- * Useful for optimistic updates without baking in business logic.
9
- */
10
- export declare function updateQueryData<T>(client: QueryClient, key: QueryKey, updater: (prev: T | undefined) => T): void;
11
- /** The cache key of page `page` of a `useFirestorePaginated` list keyed `queryKey`. */
12
- export declare function paginatedPageKey(queryKey: QueryKey, page: number): QueryKey;
13
- /**
14
- * Patch rows in place across every cached page of a `useFirestorePaginated` list
15
- * (`queryKey` is the base key the hook was given). Return the same row to leave it
16
- * unchanged; a page with no changed row keeps its identity. Cursors and has-more are
17
- * untouched, so paging stays aligned with the server.
18
- */
19
- export declare function mapPaginatedItems<T>(client: QueryClient, queryKey: QueryKey, mapItem: (item: T) => T): void;
20
- /**
21
- * Put a just-created row at the top of page 1 of a `useFirestorePaginated` list, only
22
- * when page 1 is cached. Use it only for a list ordered newest-first. Page 1 keeps its
23
- * cursor, so it shows one extra row and page 2 keeps its place until page 1 is next read;
24
- * that read moves page 1's cursor, and the hook then re-reads page 2 from the new cursor
25
- * before showing it.
26
- */
27
- export declare function prependToFirstPaginatedPage<T>(client: QueryClient, queryKey: QueryKey, item: T): void;
28
- /** How `placeRowInPages` reads and writes one infinite list's pages. */
29
- export interface PagedRows<P, T> {
30
- rowsOf: (page: P) => readonly T[];
31
- withRows: (page: P, rows: T[]) => P;
32
- /** True when `candidate` is the row being placed (its id). */
33
- isRow: (candidate: T) => boolean;
34
- /** True when `a` comes before `b` in the list's own order. */
35
- sortsBefore: (a: T, b: T) => boolean;
36
- /** True when this page is not the last one the source holds (a next page exists). */
37
- hasMoreAfter: (page: P) => boolean;
38
- }
39
- /**
40
- * Place, move, or drop ONE row in a cached infinite list's loaded pages, in place: the row leaves
41
- * wherever it sits and, when `belongs`, joins at its position in the list's own order. A row that
42
- * sorts after every loaded row is added only when no further page exists; otherwise the next page
43
- * read returns it, so placing it here would list it twice. Every other row, every page, and every
44
- * cursor stays put; a list the row neither left nor joined is returned as it was. Never a reset to the
45
- * first page.
46
- */
47
- 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;
48
- //# sourceMappingURL=cache-helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache-helpers.d.ts","sourceRoot":"","sources":["../src/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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache-helpers.js","sourceRoot":"","sources":["../src/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"]}
@@ -1,70 +0,0 @@
1
- import type { Query, QueryClient, QueryKey } from "@tanstack/react-query";
2
- export type RefetchType = "active" | "all" | "none";
3
- /**
4
- * What an entry does to the queries it matches:
5
- * - `"refresh"` (the default) marks them stale and refetches per `refetchType`;
6
- * - `"remove"` cancels them and drops them from the cache — for data that no longer exists, or a
7
- * held answer that must not be served again;
8
- * - `"reset"` returns them to their initial state and refetches the active ones from scratch.
9
- */
10
- export type CacheAction = "refresh" | "remove" | "reset";
11
- export type CacheInvalidation = {
12
- kind: "exact";
13
- queryKey: QueryKey;
14
- refetchType?: RefetchType;
15
- action?: CacheAction;
16
- } | {
17
- kind: "prefix";
18
- queryKey: QueryKey;
19
- refetchType?: RefetchType;
20
- action?: CacheAction;
21
- } | {
22
- kind: "predicate";
23
- description: string;
24
- match: (query: Query) => boolean;
25
- refetchType?: RefetchType;
26
- action?: CacheAction;
27
- };
28
- /** `refetchType` belongs to a refresh; a remove or reset takes none. */
29
- type EntryOptions = {
30
- refetchType?: RefetchType;
31
- action?: "refresh";
32
- } | {
33
- action: "remove" | "reset";
34
- };
35
- export declare function exact(queryKey: QueryKey, opts?: EntryOptions): CacheInvalidation;
36
- export declare function prefix(queryKey: QueryKey, opts?: EntryOptions): CacheInvalidation;
37
- export declare function predicate(description: string, match: (query: Query) => boolean, opts?: EntryOptions): CacheInvalidation;
38
- export declare function serializeInvalidation(inv: CacheInvalidation): string;
39
- /**
40
- * Dispatch a deduplicated list of cache invalidations.
41
- *
42
- * Returns a promise that resolves once every `invalidateQueries` call it issued
43
- * has settled — i.e. once the refetches those invalidations triggered have
44
- * landed. The dispatch itself stays synchronous (every cancellation and
45
- * invalidation is issued before this function returns), so a fire-and-forget
46
- * caller can ignore the promise, while a mutation `onSuccess` that
47
- * RETURNS or awaits the promise stays pending until the refreshed data is in
48
- * the cache. The promise never rejects: `invalidateQueries` refetches without
49
- * `throwOnError`, so a failed refetch surfaces on its own query, never as a
50
- * failure of the committed action that triggered it. The scoped
51
- * `cancelQueries` calls stay fire-and-forget — cancellation takes effect
52
- * synchronously and is not part of the refresh being awaited.
53
- *
54
- * Before each invalidation, any query it matches that is mid-PENDING-INITIAL-READ
55
- * is cancelled (see `cancelPendingInitialReads`) so a read that started before
56
- * the write committed can never land as the query's first — and freshly-marked —
57
- * value.
58
- *
59
- * `refetchType` governs whether that cancellation happens:
60
- * - `'active'` (the default) and `'all'` cancel-then-invalidate every matched
61
- * pending initial read — including one TanStack's refetch pass will not
62
- * restart, since a stale first value would otherwise land and mark the query
63
- * fresh, while a cancelled one simply refetches for its next observer.
64
- * - `'none'` invalidates WITHOUT cancelling: the caller has asked for no
65
- * refetch at all, so cancelling would abandon the only in-flight read the
66
- * consumer has and leave it with no data and no pending request.
67
- */
68
- export declare function applyInvalidations(queryClient: QueryClient, invalidations: ReadonlyArray<CacheInvalidation>): Promise<void>;
69
- export {};
70
- //# sourceMappingURL=cache-invalidation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache-invalidation.d.ts","sourceRoot":"","sources":["../../src/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,GAAG;IAAE,WAAW,CAAC,EAAE,WAAW,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,CAAC;AAOvG,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,123 +0,0 @@
1
- const entryFields = (opts) => ({
2
- refetchType: opts && "refetchType" in opts ? opts.refetchType : undefined,
3
- action: opts?.action,
4
- });
5
- export function exact(queryKey, opts) {
6
- return { kind: "exact", queryKey, ...entryFields(opts) };
7
- }
8
- export function prefix(queryKey, opts) {
9
- return { kind: "prefix", queryKey, ...entryFields(opts) };
10
- }
11
- export function predicate(description, match, opts) {
12
- return { kind: "predicate", description, match, ...entryFields(opts) };
13
- }
14
- export function serializeInvalidation(inv) {
15
- const action = inv.action && inv.action !== "refresh" ? `${inv.action}:` : "";
16
- if (inv.kind === "predicate")
17
- return `${action}predicate:${inv.description}`;
18
- return `${action}${inv.kind}:${JSON.stringify(inv.queryKey)}`;
19
- }
20
- /** The cache filter that selects exactly the queries one invalidation targets. */
21
- function invalidationFilters(inv) {
22
- if (inv.kind === "exact")
23
- return { queryKey: inv.queryKey, exact: true };
24
- if (inv.kind === "prefix")
25
- return { queryKey: inv.queryKey, exact: false };
26
- return { predicate: inv.match };
27
- }
28
- /**
29
- * Cancel every query matched by `filters` that is in a PENDING INITIAL READ —
30
- * currently fetching with no data yet.
31
- *
32
- * TanStack's `Query.fetch` only cancels a running request on refetch when the
33
- * query already holds data; an initial fetch in flight is REUSED instead, so
34
- * the invalidation's refetch resolves with the value the server returned BEFORE
35
- * the mutation committed and then marks the query fresh. Cancelling first makes
36
- * the invalidation's refetch a genuinely new request: the retryer is rejected
37
- * synchronously (its `onCancel` reverts state to idle in the same tick), so the
38
- * `invalidateQueries` call that follows starts a fresh fetch, and the abandoned
39
- * promise's late, stale resolution is discarded.
40
- *
41
- * Cancellation is always scoped to one concrete query key — never a bare
42
- * `cancelQueries()`.
43
- */
44
- function cancelPendingInitialReads(queryClient, filters) {
45
- for (const query of queryClient.getQueryCache().findAll(filters)) {
46
- if (query.state.fetchStatus !== "fetching")
47
- continue;
48
- if (query.state.data !== undefined)
49
- continue;
50
- void queryClient.cancelQueries({ queryKey: query.queryKey, exact: true });
51
- }
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
- }
63
- /**
64
- * Dispatch a deduplicated list of cache invalidations.
65
- *
66
- * Returns a promise that resolves once every `invalidateQueries` call it issued
67
- * has settled — i.e. once the refetches those invalidations triggered have
68
- * landed. The dispatch itself stays synchronous (every cancellation and
69
- * invalidation is issued before this function returns), so a fire-and-forget
70
- * caller can ignore the promise, while a mutation `onSuccess` that
71
- * RETURNS or awaits the promise stays pending until the refreshed data is in
72
- * the cache. The promise never rejects: `invalidateQueries` refetches without
73
- * `throwOnError`, so a failed refetch surfaces on its own query, never as a
74
- * failure of the committed action that triggered it. The scoped
75
- * `cancelQueries` calls stay fire-and-forget — cancellation takes effect
76
- * synchronously and is not part of the refresh being awaited.
77
- *
78
- * Before each invalidation, any query it matches that is mid-PENDING-INITIAL-READ
79
- * is cancelled (see `cancelPendingInitialReads`) so a read that started before
80
- * the write committed can never land as the query's first — and freshly-marked —
81
- * value.
82
- *
83
- * `refetchType` governs whether that cancellation happens:
84
- * - `'active'` (the default) and `'all'` cancel-then-invalidate every matched
85
- * pending initial read — including one TanStack's refetch pass will not
86
- * restart, since a stale first value would otherwise land and mark the query
87
- * fresh, while a cancelled one simply refetches for its next observer.
88
- * - `'none'` invalidates WITHOUT cancelling: the caller has asked for no
89
- * refetch at all, so cancelling would abandon the only in-flight read the
90
- * consumer has and leave it with no data and no pending request.
91
- */
92
- export function applyInvalidations(queryClient, invalidations) {
93
- const seen = new Set();
94
- const refreshes = [];
95
- for (const inv of invalidations) {
96
- const sig = serializeInvalidation(inv);
97
- if (seen.has(sig))
98
- continue;
99
- seen.add(sig);
100
- const filters = invalidationFilters(inv);
101
- const action = inv.action ?? "refresh";
102
- if (action === "remove") {
103
- const matched = matchedNow(queryClient, filters);
104
- // Removing a query abandons its read in flight silently, so that read never puts the dropped
105
- // answer back, but a screen still watching it would go on showing it as fetching. Cancelled
106
- // first, the read ends visibly and the watcher reads idle.
107
- void queryClient.cancelQueries(matched);
108
- queryClient.removeQueries(matched);
109
- continue;
110
- }
111
- if (action === "reset") {
112
- refreshes.push(queryClient.resetQueries(matchedNow(queryClient, filters)));
113
- continue;
114
- }
115
- const refetchType = inv.refetchType ?? "active";
116
- if (refetchType !== "none") {
117
- cancelPendingInitialReads(queryClient, filters);
118
- }
119
- refreshes.push(queryClient.invalidateQueries({ ...filters, refetchType }));
120
- }
121
- return Promise.all(refreshes).then(() => undefined);
122
- }
123
- //# sourceMappingURL=cache-invalidation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache-invalidation.js","sourceRoot":"","sources":["../../src/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 = { 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,46 +0,0 @@
1
- import type { QueryClient } from "@tanstack/react-query";
2
- import { exact, prefix, predicate, type CacheInvalidation } from "./cache-invalidation.js";
3
- /**
4
- * Registry shape: each event type maps to a function from the event's `ids`
5
- * payload to the list of cache invalidations that event should trigger.
6
- */
7
- export type DomainEventInvalidationRegistry<TEvent extends {
8
- type: string;
9
- ids: unknown;
10
- }> = {
11
- [K in TEvent["type"]]: (ids: Extract<TEvent, {
12
- type: K;
13
- }>["ids"]) => ReadonlyArray<CacheInvalidation>;
14
- };
15
- export interface DomainEventInvalidator<TEvent extends {
16
- type: string;
17
- ids: unknown;
18
- }> {
19
- /**
20
- * Dispatch the event's invalidations. The returned promise resolves once
21
- * every refetch they triggered has settled, and never rejects — return or
22
- * await it from a mutation's `onSuccess` to keep the mutation pending until
23
- * the refreshed data lands; ignore it for fire-and-forget dispatch.
24
- */
25
- notify(queryClient: QueryClient, event: TEvent): Promise<void>;
26
- /** `notify` for several events, deduplicating their invalidations as one batch. */
27
- notifyAll(queryClient: QueryClient, events: ReadonlyArray<TEvent>): Promise<void>;
28
- /** Test/debug helpers. */
29
- readonly helpers: {
30
- exact: typeof exact;
31
- prefix: typeof prefix;
32
- predicate: typeof predicate;
33
- };
34
- /** Direct access to the registry, mainly for tests. */
35
- readonly registry: DomainEventInvalidationRegistry<TEvent>;
36
- }
37
- /**
38
- * Build a domain-event → cache-invalidation notifier from a typed registry.
39
- * The registry's keys are statically tied to `TEvent["type"]`, so missing or
40
- * extra entries are compile errors.
41
- */
42
- export declare function createDomainEventInvalidator<TEvent extends {
43
- type: string;
44
- ids: unknown;
45
- }>(registry: DomainEventInvalidationRegistry<TEvent>): DomainEventInvalidator<TEvent>;
46
- //# sourceMappingURL=create-domain-event-invalidator.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create-domain-event-invalidator.d.ts","sourceRoot":"","sources":["../../src/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 +0,0 @@
1
- {"version":3,"file":"create-domain-event-invalidator.js","sourceRoot":"","sources":["../../src/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,5 +0,0 @@
1
- export { exact, prefix, predicate, serializeInvalidation, applyInvalidations, } from "./cache-invalidation.js";
2
- export type { CacheAction, CacheInvalidation, RefetchType } from "./cache-invalidation.js";
3
- export { createDomainEventInvalidator } from "./create-domain-event-invalidator.js";
4
- export type { DomainEventInvalidator, DomainEventInvalidationRegistry, } from "./create-domain-event-invalidator.js";
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/domain-events/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3F,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC;AACpF,YAAY,EACV,sBAAsB,EACtB,+BAA+B,GAChC,MAAM,sCAAsC,CAAC"}
@@ -1,3 +0,0 @@
1
- export { exact, prefix, predicate, serializeInvalidation, applyInvalidations, } from "./cache-invalidation.js";
2
- export { createDomainEventInvalidator } from "./create-domain-event-invalidator.js";
3
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/domain-events/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,4BAA4B,EAAE,MAAM,sCAAsC,CAAC","sourcesContent":["export {\n exact,\n prefix,\n predicate,\n serializeInvalidation,\n applyInvalidations,\n} from \"./cache-invalidation.js\";\nexport type { CacheAction, CacheInvalidation, RefetchType } from \"./cache-invalidation.js\";\n\nexport { createDomainEventInvalidator } from \"./create-domain-event-invalidator.js\";\nexport type {\n DomainEventInvalidator,\n DomainEventInvalidationRegistry,\n} from \"./create-domain-event-invalidator.js\";\n"]}
@@ -1,20 +0,0 @@
1
- import type { InfinitePage, WithId } from './types.js';
2
- /**
3
- * Flatten infinite query pages into a single array of items.
4
- *
5
- * @example
6
- * ```tsx
7
- * const { data } = useFirestoreInfinite<Post>({ ... });
8
- * const posts = flattenInfiniteData(data);
9
- * ```
10
- */
11
- export declare function flattenInfiniteData<T>(data: {
12
- pages: InfinitePage<T>[];
13
- } | undefined): WithId<T>[];
14
- /**
15
- * Get total count of items across all loaded pages.
16
- */
17
- export declare function getInfiniteDataCount<T>(data: {
18
- pages: InfinitePage<T>[];
19
- } | undefined): number;
20
- //# sourceMappingURL=infinite-helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"infinite-helpers.d.ts","sourceRoot":"","sources":["../../src/firestore/infinite-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,IAAI,EAAE;IAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAA;CAAE,GAAG,SAAS,GAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,CAGb;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,IAAI,EAAE;IAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,CAAA;CAAE,GAAG,SAAS,GAC7C,MAAM,CAGR"}
@@ -1,23 +0,0 @@
1
- /**
2
- * Flatten infinite query pages into a single array of items.
3
- *
4
- * @example
5
- * ```tsx
6
- * const { data } = useFirestoreInfinite<Post>({ ... });
7
- * const posts = flattenInfiniteData(data);
8
- * ```
9
- */
10
- export function flattenInfiniteData(data) {
11
- if (!data)
12
- return [];
13
- return data.pages.flatMap((page) => page.items);
14
- }
15
- /**
16
- * Get total count of items across all loaded pages.
17
- */
18
- export function getInfiniteDataCount(data) {
19
- if (!data)
20
- return 0;
21
- return data.pages.reduce((sum, page) => sum + page.items.length, 0);
22
- }
23
- //# sourceMappingURL=infinite-helpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"infinite-helpers.js","sourceRoot":"","sources":["../../src/firestore/infinite-helpers.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAA8C;IAE9C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAA8C;IAE9C,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAC;IACpB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AACtE,CAAC","sourcesContent":["import type { InfinitePage, WithId } from './types.js';\n\n/**\n * Flatten infinite query pages into a single array of items.\n *\n * @example\n * ```tsx\n * const { data } = useFirestoreInfinite<Post>({ ... });\n * const posts = flattenInfiniteData(data);\n * ```\n */\nexport function flattenInfiniteData<T>(\n data: { pages: InfinitePage<T>[] } | undefined\n): WithId<T>[] {\n if (!data) return [];\n return data.pages.flatMap((page) => page.items);\n}\n\n/**\n * Get total count of items across all loaded pages.\n */\nexport function getInfiniteDataCount<T>(\n data: { pages: InfinitePage<T>[] } | undefined\n): number {\n if (!data) return 0;\n return data.pages.reduce((sum, page) => sum + page.items.length, 0);\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query-client.d.ts","sourceRoot":"","sources":["../src/query-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG5E,MAAM,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;AAEzD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,wBAA6B,eAiBzE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"query-client.js","sourceRoot":"","sources":["../src/query-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA0B,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAIzD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAsC,EAAE;IACxE,OAAO,IAAI,WAAW,CAAC;QACrB,GAAG,wBAAwB;QAC3B,GAAG,SAAS;QACZ,cAAc,EAAE;YACd,GAAG,wBAAwB,CAAC,cAAc;YAC1C,GAAG,SAAS,CAAC,cAAc;YAC3B,OAAO,EAAE;gBACP,GAAG,wBAAwB,CAAC,cAAc,EAAE,OAAO;gBACnD,GAAG,SAAS,CAAC,cAAc,EAAE,OAAO;aACrC;YACD,SAAS,EAAE;gBACT,GAAG,wBAAwB,CAAC,cAAc,EAAE,SAAS;gBACrD,GAAG,SAAS,CAAC,cAAc,EAAE,SAAS;aACvC;SACF;KACF,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { QueryClient, type QueryClientConfig } from '@tanstack/react-query';\nimport { defaultQueryClientConfig } from './defaults.js';\n\nexport type CreateQueryClientOptions = QueryClientConfig;\n\n/**\n * Factory so every app uses the same baseline behavior.\n * Pass overrides to adjust defaults without forking.\n */\nexport function createQueryClient(overrides: CreateQueryClientOptions = {}) {\n return new QueryClient({\n ...defaultQueryClientConfig,\n ...overrides,\n defaultOptions: {\n ...defaultQueryClientConfig.defaultOptions,\n ...overrides.defaultOptions,\n queries: {\n ...defaultQueryClientConfig.defaultOptions?.queries,\n ...overrides.defaultOptions?.queries,\n },\n mutations: {\n ...defaultQueryClientConfig.defaultOptions?.mutations,\n ...overrides.defaultOptions?.mutations,\n },\n },\n });\n}\n"]}