@ttt-productions/query-core 0.14.22 → 0.14.24

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 (137) hide show
  1. package/README.md +6 -6
  2. package/dist/defaults.d.ts +0 -15
  3. package/dist/defaults.d.ts.map +1 -1
  4. package/dist/defaults.js +0 -15
  5. package/dist/defaults.js.map +1 -1
  6. package/dist/firestore/types.d.ts +5 -49
  7. package/dist/firestore/types.d.ts.map +1 -1
  8. package/dist/firestore/types.js.map +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +0 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/keys.d.ts +0 -22
  13. package/dist/keys.d.ts.map +1 -1
  14. package/dist/keys.js +0 -4
  15. package/dist/keys.js.map +1 -1
  16. package/dist/react/cache-helpers.d.ts +0 -32
  17. package/dist/react/cache-helpers.d.ts.map +1 -1
  18. package/dist/react/cache-helpers.js +0 -28
  19. package/dist/react/cache-helpers.js.map +1 -1
  20. package/dist/react/callables/create-callables.d.ts +40 -0
  21. package/dist/react/callables/create-callables.d.ts.map +1 -0
  22. package/dist/react/callables/create-callables.js +101 -0
  23. package/dist/react/callables/create-callables.js.map +1 -0
  24. package/dist/react/defaults.d.ts +0 -4
  25. package/dist/react/defaults.d.ts.map +1 -1
  26. package/dist/react/defaults.js +2 -6
  27. package/dist/react/defaults.js.map +1 -1
  28. package/dist/react/domain-events/cache-invalidation.d.ts +0 -37
  29. package/dist/react/domain-events/cache-invalidation.d.ts.map +1 -1
  30. package/dist/react/domain-events/cache-invalidation.js +4 -53
  31. package/dist/react/domain-events/cache-invalidation.js.map +1 -1
  32. package/dist/react/domain-events/create-domain-event-invalidator.d.ts +0 -18
  33. package/dist/react/domain-events/create-domain-event-invalidator.d.ts.map +1 -1
  34. package/dist/react/domain-events/create-domain-event-invalidator.js +0 -5
  35. package/dist/react/domain-events/create-domain-event-invalidator.js.map +1 -1
  36. package/dist/react/firestore/absence-scheduler.d.ts +0 -28
  37. package/dist/react/firestore/absence-scheduler.d.ts.map +1 -1
  38. package/dist/react/firestore/absence-scheduler.js +1 -39
  39. package/dist/react/firestore/absence-scheduler.js.map +1 -1
  40. package/dist/react/firestore/batch-doc-loader.d.ts +0 -30
  41. package/dist/react/firestore/batch-doc-loader.d.ts.map +1 -1
  42. package/dist/react/firestore/batch-doc-loader.js +0 -34
  43. package/dist/react/firestore/batch-doc-loader.js.map +1 -1
  44. package/dist/react/firestore/context.d.ts +0 -19
  45. package/dist/react/firestore/context.d.ts.map +1 -1
  46. package/dist/react/firestore/context.js +0 -19
  47. package/dist/react/firestore/context.js.map +1 -1
  48. package/dist/react/firestore/doc-subscription-registry.d.ts +0 -23
  49. package/dist/react/firestore/doc-subscription-registry.d.ts.map +1 -1
  50. package/dist/react/firestore/doc-subscription-registry.js +5 -26
  51. package/dist/react/firestore/doc-subscription-registry.js.map +1 -1
  52. package/dist/react/firestore/infinite-helpers.d.ts +0 -12
  53. package/dist/react/firestore/infinite-helpers.d.ts.map +1 -1
  54. package/dist/react/firestore/infinite-helpers.js +0 -12
  55. package/dist/react/firestore/infinite-helpers.js.map +1 -1
  56. package/dist/react/firestore/resubscribe.d.ts +0 -20
  57. package/dist/react/firestore/resubscribe.d.ts.map +1 -1
  58. package/dist/react/firestore/resubscribe.js +0 -20
  59. package/dist/react/firestore/resubscribe.js.map +1 -1
  60. package/dist/react/firestore/subscription-status.d.ts +0 -29
  61. package/dist/react/firestore/subscription-status.d.ts.map +1 -1
  62. package/dist/react/firestore/subscription-status.js +1 -34
  63. package/dist/react/firestore/subscription-status.js.map +1 -1
  64. package/dist/react/firestore/types.d.ts +0 -64
  65. package/dist/react/firestore/types.d.ts.map +1 -1
  66. package/dist/react/firestore/types.js +0 -3
  67. package/dist/react/firestore/types.js.map +1 -1
  68. package/dist/react/firestore/use-firestore-collection.d.ts +0 -20
  69. package/dist/react/firestore/use-firestore-collection.d.ts.map +1 -1
  70. package/dist/react/firestore/use-firestore-collection.js +1 -35
  71. package/dist/react/firestore/use-firestore-collection.js.map +1 -1
  72. package/dist/react/firestore/use-firestore-count.d.ts +0 -15
  73. package/dist/react/firestore/use-firestore-count.d.ts.map +1 -1
  74. package/dist/react/firestore/use-firestore-count.js +0 -15
  75. package/dist/react/firestore/use-firestore-count.js.map +1 -1
  76. package/dist/react/firestore/use-firestore-doc.d.ts +0 -23
  77. package/dist/react/firestore/use-firestore-doc.d.ts.map +1 -1
  78. package/dist/react/firestore/use-firestore-doc.js +3 -40
  79. package/dist/react/firestore/use-firestore-doc.js.map +1 -1
  80. package/dist/react/firestore/use-firestore-infinite.d.ts +0 -29
  81. package/dist/react/firestore/use-firestore-infinite.d.ts.map +1 -1
  82. package/dist/react/firestore/use-firestore-infinite.js +0 -32
  83. package/dist/react/firestore/use-firestore-infinite.js.map +1 -1
  84. package/dist/react/firestore/use-firestore-live-infinite.d.ts +0 -34
  85. package/dist/react/firestore/use-firestore-live-infinite.d.ts.map +1 -1
  86. package/dist/react/firestore/use-firestore-live-infinite.js +1 -35
  87. package/dist/react/firestore/use-firestore-live-infinite.js.map +1 -1
  88. package/dist/react/firestore/use-firestore-mutations.d.ts.map +1 -1
  89. package/dist/react/firestore/use-firestore-mutations.js +6 -5
  90. package/dist/react/firestore/use-firestore-mutations.js.map +1 -1
  91. package/dist/react/firestore/use-firestore-paginated.d.ts +0 -30
  92. package/dist/react/firestore/use-firestore-paginated.d.ts.map +1 -1
  93. package/dist/react/firestore/use-firestore-paginated.js +2 -33
  94. package/dist/react/firestore/use-firestore-paginated.js.map +1 -1
  95. package/dist/react/firestore/useBatchFirestoreDocs.d.ts +1 -123
  96. package/dist/react/firestore/useBatchFirestoreDocs.d.ts.map +1 -1
  97. package/dist/react/firestore/useBatchFirestoreDocs.js +23 -64
  98. package/dist/react/firestore/useBatchFirestoreDocs.js.map +1 -1
  99. package/dist/react/index.d.ts +4 -0
  100. package/dist/react/index.d.ts.map +1 -1
  101. package/dist/react/index.js +2 -13
  102. package/dist/react/index.js.map +1 -1
  103. package/dist/react/pending-mutations.d.ts +1 -21
  104. package/dist/react/pending-mutations.d.ts.map +1 -1
  105. package/dist/react/pending-mutations.js +1 -32
  106. package/dist/react/pending-mutations.js.map +1 -1
  107. package/dist/react/provider.d.ts +0 -5
  108. package/dist/react/provider.d.ts.map +1 -1
  109. package/dist/react/provider.js +0 -4
  110. package/dist/react/provider.js.map +1 -1
  111. package/dist/react/query-client.d.ts +0 -4
  112. package/dist/react/query-client.d.ts.map +1 -1
  113. package/dist/react/query-client.js +0 -4
  114. package/dist/react/query-client.js.map +1 -1
  115. package/dist/react/search/types.d.ts +0 -12
  116. package/dist/react/search/types.d.ts.map +1 -1
  117. package/dist/react/search/types.js.map +1 -1
  118. package/dist/react/search/use-firestore-search.d.ts +0 -29
  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/session-mutation.d.ts +27 -0
  123. package/dist/react/session-mutation.d.ts.map +1 -0
  124. package/dist/react/session-mutation.js +150 -0
  125. package/dist/react/session-mutation.js.map +1 -0
  126. package/dist/react/use-read-retry-state.d.ts +1 -21
  127. package/dist/react/use-read-retry-state.d.ts.map +1 -1
  128. package/dist/react/use-read-retry-state.js +2 -21
  129. package/dist/react/use-read-retry-state.js.map +1 -1
  130. package/dist/search/rule.d.ts +0 -6
  131. package/dist/search/rule.d.ts.map +1 -1
  132. package/dist/search/rule.js +0 -6
  133. package/dist/search/rule.js.map +1 -1
  134. package/dist/search/types.d.ts +1 -13
  135. package/dist/search/types.d.ts.map +1 -1
  136. package/dist/search/types.js.map +1 -1
  137. package/package.json +4 -4
@@ -29,5 +29,9 @@ export { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-
29
29
  export type { FirestoreSearchOptions } from './search/types.js';
30
30
  export { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';
31
31
  export type { ReadRetryEntry, ReadRetrySource, ReadRetryState } from './use-read-retry-state.js';
32
+ export { MutationSessionProvider, MutationSessionEndedError, useSessionMutation, } from './session-mutation.js';
33
+ export type { MutationSession, MutationSessionProviderProps, SessionMutationFunctionContext, SessionMutationOptions, } from './session-mutation.js';
34
+ export { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';
35
+ export type { CallableCaptureContext, CallableDeclaration, CallableErrorRouting, CallableMutationOptions, CallablePolicy, Callables, ResumableOutcome, } from './callables/create-callables.js';
32
36
  export { usePendingMutationVariables, pendingMutationVariables, usePendingMutationTargets, hasPendingMutation, duplicateSubmissionError, useDuplicateGuardedMutation, } from './pending-mutations.js';
33
37
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAGlE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC3E,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGrE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,YAAY,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AACtF,YAAY,EAAE,2BAA2B,EAAE,MAAM,4CAA4C,CAAC;AAG9F,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAGhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAC7E,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAG1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAGtE,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAGpD,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAC;AAClG,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EACV,sBAAsB,EACtB,+BAA+B,GAChC,MAAM,oDAAoD,CAAC;AAC5D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,WAAW,GACZ,MAAM,uCAAuC,CAAC;AAG/C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,YAAY,EACV,mBAAmB,EACnB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,4BAA4B,EAC5B,YAAY,EACZ,aAAa,EACb,iBAAiB,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAC5F,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAGhE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIjG,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
@@ -1,35 +1,24 @@
1
1
  'use client';
2
- // Query Client factory (client-only; requires @tanstack/react-query)
3
2
  export { createQueryClient } from './query-client.js';
4
- // Provider
5
3
  export { QueryProvider } from './provider.js';
6
- // Firestore Provider
7
4
  export { FirestoreProvider, useFirestoreDb } from './firestore/context.js';
8
- // Firestore Query Hooks
9
5
  export { useFirestoreDoc } from './firestore/use-firestore-doc.js';
10
6
  export { useFirestoreCollection } from './firestore/use-firestore-collection.js';
11
7
  export { useFirestoreInfinite } from './firestore/use-firestore-infinite.js';
12
8
  export { useFirestorePaginated } from './firestore/use-firestore-paginated.js';
13
9
  export { useFirestoreCount } from './firestore/use-firestore-count.js';
14
10
  export { useFirestoreLiveInfinite } from './firestore/use-firestore-live-infinite.js';
15
- // Firestore Mutation Hooks
16
11
  export { useFirestoreSet, useFirestoreUpdate, useFirestoreDelete, useFirestoreBatch, } from './firestore/use-firestore-mutations.js';
17
- // Batch Firestore Docs
18
12
  export { useBatchFirestoreDocs } from './firestore/useBatchFirestoreDocs.js';
19
13
  export { ABSENT_RETRY_DELAYS_MS } from './firestore/absence-scheduler.js';
20
- // Search Hook
21
14
  export { useFirestoreSearch } from './search/use-firestore-search.js';
22
- // Cache Helpers
23
15
  export { invalidateByPrefix, removeByPrefix, updateQueryData, paginatedPageKey, mapPaginatedItems, prependToFirstPaginatedPage, placeRowInPages, } from './cache-helpers.js';
24
- // Domain-event invalidator (mechanism — consumers register their event registry)
25
16
  export { createDomainEventInvalidator } from './domain-events/create-domain-event-invalidator.js';
26
17
  export { exact, prefix, predicate, serializeInvalidation, applyInvalidations, } from './domain-events/cache-invalidation.js';
27
- // Firestore hook option and page types, and the snapshot helpers
28
18
  export { docWithId } from './firestore/types.js';
29
19
  export { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';
30
- // Read retry state
31
20
  export { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';
32
- // Authoritative pending for interactive mutations: in-flight state and duplicate guards read from
33
- // the shared MutationCache under the app's stable mutation keys.
21
+ export { MutationSessionProvider, MutationSessionEndedError, useSessionMutation, } from './session-mutation.js';
22
+ export { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';
34
23
  export { usePendingMutationVariables, pendingMutationVariables, usePendingMutationTargets, hasPendingMutation, duplicateSubmissionError, useDuplicateGuardedMutation, } from './pending-mutations.js';
35
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,qEAAqE;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,WAAW;AACX,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,qBAAqB;AACrB,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG3E,wBAAwB;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAGtF,2BAA2B;AAC3B,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAEhD,uBAAuB;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAM7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE1E,cAAc;AACd,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE,gBAAgB;AAChB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,iFAAiF;AACjF,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAC;AAClG,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,uCAAuC,CAAC;AAW/C,iEAAiE;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAYjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5F,mBAAmB;AACnB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGlF,kGAAkG;AAClG,iEAAiE;AACjE,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC","sourcesContent":["'use client';\n\n// Query Client factory (client-only; requires @tanstack/react-query)\nexport { createQueryClient } from './query-client.js';\nexport type { CreateQueryClientOptions } from './query-client.js';\n\n// Provider\nexport { QueryProvider } from './provider.js';\nexport type { QueryProviderProps } from './provider.js';\n\n// Firestore Provider\nexport { FirestoreProvider, useFirestoreDb } from './firestore/context.js';\nexport type { FirestoreProviderProps } from './firestore/context.js';\n\n// Firestore Query Hooks\nexport { useFirestoreDoc } from './firestore/use-firestore-doc.js';\nexport { useFirestoreCollection } from './firestore/use-firestore-collection.js';\nexport { useFirestoreInfinite } from './firestore/use-firestore-infinite.js';\nexport { useFirestorePaginated } from './firestore/use-firestore-paginated.js';\nexport type { UseFirestorePaginatedResult } from './firestore/use-firestore-paginated.js';\nexport { useFirestoreCount } from './firestore/use-firestore-count.js';\nexport { useFirestoreLiveInfinite } from './firestore/use-firestore-live-infinite.js';\nexport type { FirestoreLiveInfiniteResult } from './firestore/use-firestore-live-infinite.js';\n\n// Firestore Mutation Hooks\nexport {\n useFirestoreSet,\n useFirestoreUpdate,\n useFirestoreDelete,\n useFirestoreBatch,\n} from './firestore/use-firestore-mutations.js';\n\n// Batch Firestore Docs\nexport { useBatchFirestoreDocs } from './firestore/useBatchFirestoreDocs.js';\nexport type {\n BatchFirestoreDocsOptions,\n BatchFirestoreDocsResult,\n BatchFirestoreDocsTransport,\n} from './firestore/useBatchFirestoreDocs.js';\nexport { ABSENT_RETRY_DELAYS_MS } from './firestore/absence-scheduler.js';\n\n// Search Hook\nexport { useFirestoreSearch } from './search/use-firestore-search.js';\n\n// Cache Helpers\nexport {\n invalidateByPrefix,\n removeByPrefix,\n updateQueryData,\n paginatedPageKey,\n mapPaginatedItems,\n prependToFirstPaginatedPage,\n placeRowInPages,\n} from './cache-helpers.js';\nexport type { PagedRows } from './cache-helpers.js';\n\n// Domain-event invalidator (mechanism — consumers register their event registry)\nexport { createDomainEventInvalidator } from './domain-events/create-domain-event-invalidator.js';\nexport {\n exact,\n prefix,\n predicate,\n serializeInvalidation,\n applyInvalidations,\n} from './domain-events/cache-invalidation.js';\nexport type {\n DomainEventInvalidator,\n DomainEventInvalidationRegistry,\n} from './domain-events/create-domain-event-invalidator.js';\nexport type {\n CacheAction,\n CacheInvalidation,\n RefetchType,\n} from './domain-events/cache-invalidation.js';\n\n// Firestore hook option and page types, and the snapshot helpers\nexport { docWithId } from './firestore/types.js';\nexport type {\n FirestoreDocOptions,\n FirestoreCollectionOptions,\n FirestoreInfiniteOptions,\n FirestorePaginatedOptions,\n FirestoreCountOptions,\n FirestoreLiveInfiniteOptions,\n InfinitePage,\n PaginatedPage,\n MutationOperation,\n} from './firestore/types.js';\nexport { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';\nexport type { FirestoreSearchOptions } from './search/types.js';\n\n// Read retry state\nexport { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';\nexport type { ReadRetryEntry, ReadRetrySource, ReadRetryState } from './use-read-retry-state.js';\n\n// Authoritative pending for interactive mutations: in-flight state and duplicate guards read from\n// the shared MutationCache under the app's stable mutation keys.\nexport {\n usePendingMutationVariables,\n pendingMutationVariables,\n usePendingMutationTargets,\n hasPendingMutation,\n duplicateSubmissionError,\n useDuplicateGuardedMutation,\n} from './pending-mutations.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAGtF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAM7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAC;AAClG,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAYjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5F,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGlF,OAAO,EACL,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAQ/B,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAWvF,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC","sourcesContent":["'use client';\n\nexport { createQueryClient } from './query-client.js';\nexport type { CreateQueryClientOptions } from './query-client.js';\n\nexport { QueryProvider } from './provider.js';\nexport type { QueryProviderProps } from './provider.js';\n\nexport { FirestoreProvider, useFirestoreDb } from './firestore/context.js';\nexport type { FirestoreProviderProps } from './firestore/context.js';\n\nexport { useFirestoreDoc } from './firestore/use-firestore-doc.js';\nexport { useFirestoreCollection } from './firestore/use-firestore-collection.js';\nexport { useFirestoreInfinite } from './firestore/use-firestore-infinite.js';\nexport { useFirestorePaginated } from './firestore/use-firestore-paginated.js';\nexport type { UseFirestorePaginatedResult } from './firestore/use-firestore-paginated.js';\nexport { useFirestoreCount } from './firestore/use-firestore-count.js';\nexport { useFirestoreLiveInfinite } from './firestore/use-firestore-live-infinite.js';\nexport type { FirestoreLiveInfiniteResult } from './firestore/use-firestore-live-infinite.js';\n\nexport {\n useFirestoreSet,\n useFirestoreUpdate,\n useFirestoreDelete,\n useFirestoreBatch,\n} from './firestore/use-firestore-mutations.js';\n\nexport { useBatchFirestoreDocs } from './firestore/useBatchFirestoreDocs.js';\nexport type {\n BatchFirestoreDocsOptions,\n BatchFirestoreDocsResult,\n BatchFirestoreDocsTransport,\n} from './firestore/useBatchFirestoreDocs.js';\nexport { ABSENT_RETRY_DELAYS_MS } from './firestore/absence-scheduler.js';\n\nexport { useFirestoreSearch } from './search/use-firestore-search.js';\n\nexport {\n invalidateByPrefix,\n removeByPrefix,\n updateQueryData,\n paginatedPageKey,\n mapPaginatedItems,\n prependToFirstPaginatedPage,\n placeRowInPages,\n} from './cache-helpers.js';\nexport type { PagedRows } from './cache-helpers.js';\n\nexport { createDomainEventInvalidator } from './domain-events/create-domain-event-invalidator.js';\nexport {\n exact,\n prefix,\n predicate,\n serializeInvalidation,\n applyInvalidations,\n} from './domain-events/cache-invalidation.js';\nexport type {\n DomainEventInvalidator,\n DomainEventInvalidationRegistry,\n} from './domain-events/create-domain-event-invalidator.js';\nexport type {\n CacheAction,\n CacheInvalidation,\n RefetchType,\n} from './domain-events/cache-invalidation.js';\n\nexport { docWithId } from './firestore/types.js';\nexport type {\n FirestoreDocOptions,\n FirestoreCollectionOptions,\n FirestoreInfiniteOptions,\n FirestorePaginatedOptions,\n FirestoreCountOptions,\n FirestoreLiveInfiniteOptions,\n InfinitePage,\n PaginatedPage,\n MutationOperation,\n} from './firestore/types.js';\nexport { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';\nexport type { FirestoreSearchOptions } from './search/types.js';\n\nexport { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';\nexport type { ReadRetryEntry, ReadRetrySource, ReadRetryState } from './use-read-retry-state.js';\n\nexport {\n MutationSessionProvider,\n MutationSessionEndedError,\n useSessionMutation,\n} from './session-mutation.js';\nexport type {\n MutationSession,\n MutationSessionProviderProps,\n SessionMutationFunctionContext,\n SessionMutationOptions,\n} from './session-mutation.js';\n\nexport { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';\nexport type {\n CallableCaptureContext,\n CallableDeclaration,\n CallableErrorRouting,\n CallableMutationOptions,\n CallablePolicy,\n Callables,\n ResumableOutcome,\n} from './callables/create-callables.js';\n\nexport {\n usePendingMutationVariables,\n pendingMutationVariables,\n usePendingMutationTargets,\n hasPendingMutation,\n duplicateSubmissionError,\n useDuplicateGuardedMutation,\n} from './pending-mutations.js';\n"]}
@@ -1,29 +1,9 @@
1
1
  import { type MutationKey, type QueryClient, type UseMutationResult } from '@tanstack/react-query';
2
- /** The variables of every pending mutation under `mutationKey` (prefix-matched), live. */
3
2
  export declare function usePendingMutationVariables<V>(mutationKey: MutationKey): ReadonlyArray<V | undefined>;
4
- /** The variables of every pending mutation under `mutationKey`, read once — for a duplicate guard. */
5
3
  export declare function pendingMutationVariables<V>(queryClient: QueryClient, mutationKey: MutationKey): Array<V | undefined>;
6
- /**
7
- * The targets of every pending mutation under `mutationKey`, live — for a list whose rows each
8
- * ask "is mine pending?" through one hook call. `targetOf` names a variables' target, or returns
9
- * nothing for variables without one.
10
- */
11
4
  export declare function usePendingMutationTargets<V>(mutationKey: MutationKey, targetOf: (variables: V) => string | null | undefined): ReadonlySet<string>;
12
- /**
13
- * True when a mutation under `mutationKey` is pending — any one, or with `matches`, one whose
14
- * variables are for the same target.
15
- */
16
5
  export declare function hasPendingMutation<V>(queryClient: QueryClient, mutationKey: MutationKey, matches?: (variables: V) => boolean): boolean;
17
- /**
18
- * The rejection a guarded `mutateAsync` throws for a duplicate submission: an `AbortError`, the
19
- * shape a caller already treats as "nothing happened" rather than a failure to report.
20
- */
21
6
  export declare function duplicateSubmissionError(what: string): Error;
22
- /**
23
- * Wrap a keyed mutation's `mutate` / `mutateAsync` in the cache-consulting duplicate guard:
24
- * `mutate` drops a duplicate silently, and `mutateAsync` rejects it with
25
- * {@link duplicateSubmissionError}. `isDuplicate` must have a stable identity (declare it at module
26
- * level) so the guarded callbacks keep theirs.
27
- */
7
+ /** `isDuplicate` must have a stable identity (declare it at module level) so the guarded callbacks keep theirs. */
28
8
  export declare function useDuplicateGuardedMutation<TData, TError, TVariables, TContext>(mutation: UseMutationResult<TData, TError, TVariables, TContext>, isDuplicate: (queryClient: QueryClient, variables: TVariables) => boolean, what: string): UseMutationResult<TData, TError, TVariables, TContext>;
29
9
  //# sourceMappingURL=pending-mutations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pending-mutations.d.ts","sourceRoot":"","sources":["../../src/react/pending-mutations.ts"],"names":[],"mappings":"AAeA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,0FAA0F;AAC1F,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,WAAW,EAAE,WAAW,GACvB,aAAa,CAAC,CAAC,GAAG,SAAS,CAAC,CAK9B;AAED,sGAAsG;AACtG,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,GACvB,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC,CAKtB;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,WAAW,CAAC,MAAM,CAAC,CAQrB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,EACxB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO,GAClC,OAAO,CAIT;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAI5D;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAC7E,QAAQ,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAChE,WAAW,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,KAAK,OAAO,EACzE,IAAI,EAAE,MAAM,GACX,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAuBxD"}
1
+ {"version":3,"file":"pending-mutations.d.ts","sourceRoot":"","sources":["../../src/react/pending-mutations.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,wBAAgB,2BAA2B,CAAC,CAAC,EAC3C,WAAW,EAAE,WAAW,GACvB,aAAa,CAAC,CAAC,GAAG,SAAS,CAAC,CAK9B;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,GACvB,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC,CAKtB;AAED,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,GACpD,WAAW,CAAC,MAAM,CAAC,CAQrB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,EACxB,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,OAAO,GAClC,OAAO,CAIT;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAI5D;AAED,mHAAmH;AACnH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAC7E,QAAQ,EAAE,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,EAChE,WAAW,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,KAAK,OAAO,EACzE,IAAI,EAAE,MAAM,GACX,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAuBxD"}
@@ -1,36 +1,18 @@
1
1
  'use client';
2
- // Authoritative pending for interactive mutations. A mutation registers in React Query's shared
3
- // MutationCache under a stable `mutationKey` the app declares (one key per action), and its target
4
- // travels in the mutation's variables. Pending is read from that cache, never from one mounted
5
- // control's `isPending`, which gives three guarantees:
6
- //
7
- // 1. an in-flight request survives its originating control unmounting;
8
- // 2. a remounted control still renders pending for that target;
9
- // 3. a second submission for the same target is refused while the first is pending.
10
- //
11
- // The app owns its keys, its variable shapes and what counts as the same target; this module owns
12
- // only the mechanics.
13
2
  import { useCallback } from 'react';
14
3
  import { useMutationState, useQueryClient, } from '@tanstack/react-query';
15
- /** The variables of every pending mutation under `mutationKey` (prefix-matched), live. */
16
4
  export function usePendingMutationVariables(mutationKey) {
17
5
  return useMutationState({
18
6
  filters: { mutationKey, status: 'pending' },
19
7
  select: (mutation) => mutation.state.variables,
20
8
  });
21
9
  }
22
- /** The variables of every pending mutation under `mutationKey`, read once — for a duplicate guard. */
23
10
  export function pendingMutationVariables(queryClient, mutationKey) {
24
11
  return queryClient
25
12
  .getMutationCache()
26
13
  .findAll({ mutationKey, status: 'pending' })
27
14
  .map((mutation) => mutation.state.variables);
28
15
  }
29
- /**
30
- * The targets of every pending mutation under `mutationKey`, live — for a list whose rows each
31
- * ask "is mine pending?" through one hook call. `targetOf` names a variables' target, or returns
32
- * nothing for variables without one.
33
- */
34
16
  export function usePendingMutationTargets(mutationKey, targetOf) {
35
17
  const targets = new Set();
36
18
  for (const variables of usePendingMutationVariables(mutationKey)) {
@@ -42,31 +24,18 @@ export function usePendingMutationTargets(mutationKey, targetOf) {
42
24
  }
43
25
  return targets;
44
26
  }
45
- /**
46
- * True when a mutation under `mutationKey` is pending — any one, or with `matches`, one whose
47
- * variables are for the same target.
48
- */
49
27
  export function hasPendingMutation(queryClient, mutationKey, matches) {
50
28
  const pending = pendingMutationVariables(queryClient, mutationKey);
51
29
  if (!matches)
52
30
  return pending.length > 0;
53
31
  return pending.some((variables) => variables !== undefined && matches(variables));
54
32
  }
55
- /**
56
- * The rejection a guarded `mutateAsync` throws for a duplicate submission: an `AbortError`, the
57
- * shape a caller already treats as "nothing happened" rather than a failure to report.
58
- */
59
33
  export function duplicateSubmissionError(what) {
60
34
  const duplicate = new Error(`${what} is already in flight.`);
61
35
  duplicate.name = 'AbortError';
62
36
  return duplicate;
63
37
  }
64
- /**
65
- * Wrap a keyed mutation's `mutate` / `mutateAsync` in the cache-consulting duplicate guard:
66
- * `mutate` drops a duplicate silently, and `mutateAsync` rejects it with
67
- * {@link duplicateSubmissionError}. `isDuplicate` must have a stable identity (declare it at module
68
- * level) so the guarded callbacks keep theirs.
69
- */
38
+ /** `isDuplicate` must have a stable identity (declare it at module level) so the guarded callbacks keep theirs. */
70
39
  export function useDuplicateGuardedMutation(mutation, isDuplicate, what) {
71
40
  const queryClient = useQueryClient();
72
41
  const { mutate: rawMutate, mutateAsync: rawMutateAsync } = mutation;
@@ -1 +1 @@
1
- {"version":3,"file":"pending-mutations.js","sourceRoot":"","sources":["../../src/react/pending-mutations.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\n// Authoritative pending for interactive mutations. A mutation registers in React Query's shared\n// MutationCache under a stable `mutationKey` the app declares (one key per action), and its target\n// travels in the mutation's variables. Pending is read from that cache, never from one mounted\n// control's `isPending`, which gives three guarantees:\n//\n// 1. an in-flight request survives its originating control unmounting;\n// 2. a remounted control still renders pending for that target;\n// 3. a second submission for the same target is refused while the first is pending.\n//\n// The app owns its keys, its variable shapes and what counts as the same target; this module owns\n// only the mechanics.\n\nimport { useCallback } from 'react';\nimport {\n useMutationState,\n useQueryClient,\n type MutateOptions,\n type MutationKey,\n type QueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\n\n/** The variables of every pending mutation under `mutationKey` (prefix-matched), live. */\nexport function usePendingMutationVariables<V>(\n mutationKey: MutationKey,\n): ReadonlyArray<V | undefined> {\n return useMutationState({\n filters: { mutationKey, status: 'pending' },\n select: (mutation) => mutation.state.variables as V | undefined,\n });\n}\n\n/** The variables of every pending mutation under `mutationKey`, read once — for a duplicate guard. */\nexport function pendingMutationVariables<V>(\n queryClient: QueryClient,\n mutationKey: MutationKey,\n): Array<V | undefined> {\n return queryClient\n .getMutationCache()\n .findAll({ mutationKey, status: 'pending' })\n .map((mutation) => mutation.state.variables as V | undefined);\n}\n\n/**\n * The targets of every pending mutation under `mutationKey`, live — for a list whose rows each\n * ask \"is mine pending?\" through one hook call. `targetOf` names a variables' target, or returns\n * nothing for variables without one.\n */\nexport function usePendingMutationTargets<V>(\n mutationKey: MutationKey,\n targetOf: (variables: V) => string | null | undefined,\n): ReadonlySet<string> {\n const targets = new Set<string>();\n for (const variables of usePendingMutationVariables<V>(mutationKey)) {\n if (variables === undefined) continue;\n const target = targetOf(variables);\n if (target) targets.add(target);\n }\n return targets;\n}\n\n/**\n * True when a mutation under `mutationKey` is pending — any one, or with `matches`, one whose\n * variables are for the same target.\n */\nexport function hasPendingMutation<V>(\n queryClient: QueryClient,\n mutationKey: MutationKey,\n matches?: (variables: V) => boolean,\n): boolean {\n const pending = pendingMutationVariables<V>(queryClient, mutationKey);\n if (!matches) return pending.length > 0;\n return pending.some((variables) => variables !== undefined && matches(variables));\n}\n\n/**\n * The rejection a guarded `mutateAsync` throws for a duplicate submission: an `AbortError`, the\n * shape a caller already treats as \"nothing happened\" rather than a failure to report.\n */\nexport function duplicateSubmissionError(what: string): Error {\n const duplicate = new Error(`${what} is already in flight.`);\n duplicate.name = 'AbortError';\n return duplicate;\n}\n\n/**\n * Wrap a keyed mutation's `mutate` / `mutateAsync` in the cache-consulting duplicate guard:\n * `mutate` drops a duplicate silently, and `mutateAsync` rejects it with\n * {@link duplicateSubmissionError}. `isDuplicate` must have a stable identity (declare it at module\n * level) so the guarded callbacks keep theirs.\n */\nexport function useDuplicateGuardedMutation<TData, TError, TVariables, TContext>(\n mutation: UseMutationResult<TData, TError, TVariables, TContext>,\n isDuplicate: (queryClient: QueryClient, variables: TVariables) => boolean,\n what: string,\n): UseMutationResult<TData, TError, TVariables, TContext> {\n const queryClient = useQueryClient();\n const { mutate: rawMutate, mutateAsync: rawMutateAsync } = mutation;\n const mutate = useCallback(\n (variables: TVariables, options?: MutateOptions<TData, TError, TVariables, TContext>) => {\n if (isDuplicate(queryClient, variables)) return;\n rawMutate(variables, options);\n },\n [queryClient, rawMutate, isDuplicate],\n );\n const mutateAsync = useCallback(\n async (variables: TVariables, options?: MutateOptions<TData, TError, TVariables, TContext>) => {\n if (isDuplicate(queryClient, variables)) throw duplicateSubmissionError(what);\n return rawMutateAsync(variables, options);\n },\n [queryClient, rawMutateAsync, isDuplicate, what],\n );\n return { ...mutation, mutate, mutateAsync } as UseMutationResult<\n TData,\n TError,\n TVariables,\n TContext\n >;\n}\n"]}
1
+ {"version":3,"file":"pending-mutations.js","sourceRoot":"","sources":["../../src/react/pending-mutations.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback } from 'react';\nimport {\n useMutationState,\n useQueryClient,\n type MutateOptions,\n type MutationKey,\n type QueryClient,\n type UseMutationResult,\n} from '@tanstack/react-query';\n\nexport function usePendingMutationVariables<V>(\n mutationKey: MutationKey,\n): ReadonlyArray<V | undefined> {\n return useMutationState({\n filters: { mutationKey, status: 'pending' },\n select: (mutation) => mutation.state.variables as V | undefined,\n });\n}\n\nexport function pendingMutationVariables<V>(\n queryClient: QueryClient,\n mutationKey: MutationKey,\n): Array<V | undefined> {\n return queryClient\n .getMutationCache()\n .findAll({ mutationKey, status: 'pending' })\n .map((mutation) => mutation.state.variables as V | undefined);\n}\n\nexport function usePendingMutationTargets<V>(\n mutationKey: MutationKey,\n targetOf: (variables: V) => string | null | undefined,\n): ReadonlySet<string> {\n const targets = new Set<string>();\n for (const variables of usePendingMutationVariables<V>(mutationKey)) {\n if (variables === undefined) continue;\n const target = targetOf(variables);\n if (target) targets.add(target);\n }\n return targets;\n}\n\nexport function hasPendingMutation<V>(\n queryClient: QueryClient,\n mutationKey: MutationKey,\n matches?: (variables: V) => boolean,\n): boolean {\n const pending = pendingMutationVariables<V>(queryClient, mutationKey);\n if (!matches) return pending.length > 0;\n return pending.some((variables) => variables !== undefined && matches(variables));\n}\n\nexport function duplicateSubmissionError(what: string): Error {\n const duplicate = new Error(`${what} is already in flight.`);\n duplicate.name = 'AbortError';\n return duplicate;\n}\n\n/** `isDuplicate` must have a stable identity (declare it at module level) so the guarded callbacks keep theirs. */\nexport function useDuplicateGuardedMutation<TData, TError, TVariables, TContext>(\n mutation: UseMutationResult<TData, TError, TVariables, TContext>,\n isDuplicate: (queryClient: QueryClient, variables: TVariables) => boolean,\n what: string,\n): UseMutationResult<TData, TError, TVariables, TContext> {\n const queryClient = useQueryClient();\n const { mutate: rawMutate, mutateAsync: rawMutateAsync } = mutation;\n const mutate = useCallback(\n (variables: TVariables, options?: MutateOptions<TData, TError, TVariables, TContext>) => {\n if (isDuplicate(queryClient, variables)) return;\n rawMutate(variables, options);\n },\n [queryClient, rawMutate, isDuplicate],\n );\n const mutateAsync = useCallback(\n async (variables: TVariables, options?: MutateOptions<TData, TError, TVariables, TContext>) => {\n if (isDuplicate(queryClient, variables)) throw duplicateSubmissionError(what);\n return rawMutateAsync(variables, options);\n },\n [queryClient, rawMutateAsync, isDuplicate, what],\n );\n return { ...mutation, mutate, mutateAsync } as UseMutationResult<\n TData,\n TError,\n TVariables,\n TContext\n >;\n}\n"]}
@@ -1,12 +1,7 @@
1
1
  import React from 'react';
2
2
  import { type CreateQueryClientOptions } from './query-client.js';
3
3
  export type QueryProviderProps = React.PropsWithChildren<{
4
- /** Optional overrides applied when the client is first created. */
5
4
  clientOptions?: CreateQueryClientOptions;
6
5
  }>;
7
- /**
8
- * Client component wrapper for Next.js / React apps.
9
- * Creates a single QueryClient per browser session.
10
- */
11
6
  export declare function QueryProvider({ children, clientOptions }: QueryProviderProps): React.JSX.Element;
12
7
  //# sourceMappingURL=provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAErF,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IACvD,mEAAmE;IACnE,aAAa,CAAC,EAAE,wBAAwB,CAAC;CAC1C,CAAC,CAAC;AAEH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,kBAAkB,qBAG5E"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAErF,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IACvD,aAAa,CAAC,EAAE,wBAAwB,CAAC;CAC1C,CAAC,CAAC;AAEH,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,kBAAkB,qBAG5E"}
@@ -3,10 +3,6 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import React from 'react';
4
4
  import { QueryClientProvider } from '@tanstack/react-query';
5
5
  import { createQueryClient } from './query-client.js';
6
- /**
7
- * Client component wrapper for Next.js / React apps.
8
- * Creates a single QueryClient per browser session.
9
- */
10
6
  export function QueryProvider({ children, clientOptions }) {
11
7
  const [client] = React.useState(() => createQueryClient(clientOptions));
12
8
  return _jsx(QueryClientProvider, { client: client, children: children });
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAiC,MAAM,mBAAmB,CAAC;AAOrF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAsB;IAC3E,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAC;IACxE,OAAO,KAAC,mBAAmB,IAAC,MAAM,EAAE,MAAM,YAAG,QAAQ,GAAuB,CAAC;AAC/E,CAAC","sourcesContent":["'use client';\n\nimport React from 'react';\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { createQueryClient, type CreateQueryClientOptions } from './query-client.js';\n\nexport type QueryProviderProps = React.PropsWithChildren<{\n /** Optional overrides applied when the client is first created. */\n clientOptions?: CreateQueryClientOptions;\n}>;\n\n/**\n * Client component wrapper for Next.js / React apps.\n * Creates a single QueryClient per browser session.\n */\nexport function QueryProvider({ children, clientOptions }: QueryProviderProps) {\n const [client] = React.useState(() => createQueryClient(clientOptions));\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>;\n}\n"]}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAiC,MAAM,mBAAmB,CAAC;AAMrF,MAAM,UAAU,aAAa,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAsB;IAC3E,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC,CAAC;IACxE,OAAO,KAAC,mBAAmB,IAAC,MAAM,EAAE,MAAM,YAAG,QAAQ,GAAuB,CAAC;AAC/E,CAAC","sourcesContent":["'use client';\n\nimport React from 'react';\nimport { QueryClientProvider } from '@tanstack/react-query';\nimport { createQueryClient, type CreateQueryClientOptions } from './query-client.js';\n\nexport type QueryProviderProps = React.PropsWithChildren<{\n clientOptions?: CreateQueryClientOptions;\n}>;\n\nexport function QueryProvider({ children, clientOptions }: QueryProviderProps) {\n const [client] = React.useState(() => createQueryClient(clientOptions));\n return <QueryClientProvider client={client}>{children}</QueryClientProvider>;\n}\n"]}
@@ -1,8 +1,4 @@
1
1
  import { QueryClient, type QueryClientConfig } from '@tanstack/react-query';
2
2
  export type CreateQueryClientOptions = QueryClientConfig;
3
- /**
4
- * Factory so every app uses the same baseline behavior.
5
- * Pass overrides to adjust defaults without forking.
6
- */
7
3
  export declare function createQueryClient(overrides?: CreateQueryClientOptions): QueryClient;
8
4
  //# sourceMappingURL=query-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-client.d.ts","sourceRoot":"","sources":["../../src/react/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
+ {"version":3,"file":"query-client.d.ts","sourceRoot":"","sources":["../../src/react/query-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG5E,MAAM,MAAM,wBAAwB,GAAG,iBAAiB,CAAC;AAEzD,wBAAgB,iBAAiB,CAAC,SAAS,GAAE,wBAA6B,eAiBzE"}
@@ -1,9 +1,5 @@
1
1
  import { QueryClient } from '@tanstack/react-query';
2
2
  import { defaultQueryClientConfig } from './defaults.js';
3
- /**
4
- * Factory so every app uses the same baseline behavior.
5
- * Pass overrides to adjust defaults without forking.
6
- */
7
3
  export function createQueryClient(overrides = {}) {
8
4
  return new QueryClient({
9
5
  ...defaultQueryClientConfig,
@@ -1 +1 @@
1
- {"version":3,"file":"query-client.js","sourceRoot":"","sources":["../../src/react/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"]}
1
+ {"version":3,"file":"query-client.js","sourceRoot":"","sources":["../../src/react/query-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA0B,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAIzD,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\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"]}
@@ -1,28 +1,16 @@
1
1
  import type { DocumentData } from 'firebase/firestore';
2
2
  import type { SearchEqualityFilter } from '../../search/types.js';
3
- /**
4
- * Options for useFirestoreSearch hook
5
- */
6
3
  export interface FirestoreSearchOptions<T extends DocumentData = DocumentData> {
7
- /** Firestore collection path to search */
8
4
  collectionPath: string;
9
- /** Field name to search on (must be indexed and lowercase) */
10
5
  searchField: string;
11
- /** Search query text */
12
6
  queryText: string;
13
- /** Maximum number of results (default: 5) */
14
7
  limit?: number;
15
- /** Enable/disable the search (default: true) */
16
8
  enabled?: boolean;
17
- /** Transform function to convert raw Firestore data to typed result */
18
9
  select?: (data: DocumentData & {
19
10
  id: string;
20
11
  }) => T;
21
- /** Debounce delay in milliseconds (default: 300) */
22
12
  debounceMs?: number;
23
- /** React Query stale time (default: 60000ms) */
24
13
  staleTime?: number;
25
- /** Optional equality filters applied before the prefix range. */
26
14
  equalityFilters?: SearchEqualityFilter[];
27
15
  }
28
16
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/react/search/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE;;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/react/search/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,WAAW,sBAAsB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,GAAG;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,CAAC,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAC1C"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/react/search/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentData } from 'firebase/firestore';\nimport type { SearchEqualityFilter } from '../../search/types.js';\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/react/search/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DocumentData } from 'firebase/firestore';\nimport type { SearchEqualityFilter } from '../../search/types.js';\n\nexport interface FirestoreSearchOptions<T extends DocumentData = DocumentData> {\n collectionPath: string;\n searchField: string;\n queryText: string;\n limit?: number;\n enabled?: boolean;\n select?: (data: DocumentData & { id: string }) => T;\n debounceMs?: number;\n staleTime?: number;\n equalityFilters?: SearchEqualityFilter[];\n}\n"]}
@@ -2,34 +2,5 @@ import { type UseQueryResult } from '@tanstack/react-query';
2
2
  import { type DocumentData } from 'firebase/firestore';
3
3
  import type { FirestoreSearchOptions } from './types.js';
4
4
  import type { WithId } from '../../firestore/types.js';
5
- /**
6
- * Generic Firestore search hook with debouncing and case-insensitive prefix matching.
7
- * Automatically normalizes search text to lowercase and uses Firestore range queries.
8
- *
9
- * Features:
10
- * - Debounced input (default 300ms)
11
- * - Case-insensitive search
12
- * - Searches only a text `isSearchableText` accepts (`FIRESTORE_SEARCH_MIN_LENGTH`, trimmed)
13
- * - No answer while the debounce lags the typed text: `data` is undefined and `isLoading` is true
14
- * (idle instead when the typed text is too short or the search is disabled)
15
- * - Prefix matching with '\uf8ff' suffix
16
- * - Configurable result limit
17
- *
18
- * @example
19
- * ```typescript
20
- * const { data, isLoading } = useFirestoreSearch<UserProfile>({
21
- * collectionPath: 'userProfiles',
22
- * searchField: 'username',
23
- * queryText: searchValue,
24
- * });
25
- *
26
- * const { data } = useFirestoreSearch<Team>({
27
- * collectionPath: 'teams',
28
- * searchField: 'name_lowercase',
29
- * queryText: searchValue,
30
- * limit: 10,
31
- * });
32
- * ```
33
- */
34
5
  export declare function useFirestoreSearch<T extends DocumentData = DocumentData>({ collectionPath, searchField, queryText, limit, enabled, select, debounceMs, staleTime, equalityFilters, }: FirestoreSearchOptions<T>): UseQueryResult<WithId<T>[], Error>;
35
6
  //# sourceMappingURL=use-firestore-search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-firestore-search.d.ts","sourceRoot":"","sources":["../../../src/react/search/use-firestore-search.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAOvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EACxE,cAAc,EACd,WAAW,EACX,SAAS,EACT,KAAqB,EACrB,OAAc,EACd,MAAM,EACN,UAAgC,EAChC,SAA8B,EAC9B,eAAoB,GACrB,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CA8DhE"}
1
+ {"version":3,"file":"use-firestore-search.d.ts","sourceRoot":"","sources":["../../../src/react/search/use-firestore-search.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAOL,KAAK,YAAY,EAElB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAOvD,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EAAE,EACxE,cAAc,EACd,WAAW,EACX,SAAS,EACT,KAAqB,EACrB,OAAc,EACd,MAAM,EACN,UAAgC,EAChC,SAA8B,EAC9B,eAAoB,GACrB,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,CAAC,CAyDhE"}
@@ -7,40 +7,10 @@ import { keys } from '../../keys.js';
7
7
  import { isSearchableText, normalizeSearchText } from '../../search/rule.js';
8
8
  const DEFAULT_LIMIT = 5;
9
9
  const DEFAULT_DEBOUNCE_MS = 300;
10
- const DEFAULT_STALE_TIME = 60 * 1000; // 1 minute
11
- /**
12
- * Generic Firestore search hook with debouncing and case-insensitive prefix matching.
13
- * Automatically normalizes search text to lowercase and uses Firestore range queries.
14
- *
15
- * Features:
16
- * - Debounced input (default 300ms)
17
- * - Case-insensitive search
18
- * - Searches only a text `isSearchableText` accepts (`FIRESTORE_SEARCH_MIN_LENGTH`, trimmed)
19
- * - No answer while the debounce lags the typed text: `data` is undefined and `isLoading` is true
20
- * (idle instead when the typed text is too short or the search is disabled)
21
- * - Prefix matching with '\uf8ff' suffix
22
- * - Configurable result limit
23
- *
24
- * @example
25
- * ```typescript
26
- * const { data, isLoading } = useFirestoreSearch<UserProfile>({
27
- * collectionPath: 'userProfiles',
28
- * searchField: 'username',
29
- * queryText: searchValue,
30
- * });
31
- *
32
- * const { data } = useFirestoreSearch<Team>({
33
- * collectionPath: 'teams',
34
- * searchField: 'name_lowercase',
35
- * queryText: searchValue,
36
- * limit: 10,
37
- * });
38
- * ```
39
- */
10
+ const DEFAULT_STALE_TIME = 60 * 1000;
40
11
  export function useFirestoreSearch({ collectionPath, searchField, queryText, limit = DEFAULT_LIMIT, enabled = true, select, debounceMs = DEFAULT_DEBOUNCE_MS, staleTime = DEFAULT_STALE_TIME, equalityFilters = [], }) {
41
12
  const db = useFirestoreDb();
42
13
  const [debouncedQuery, setDebouncedQuery] = useState(queryText);
43
- // Debounce the search query
44
14
  useEffect(() => {
45
15
  const timer = setTimeout(() => {
46
16
  setDebouncedQuery(queryText);
@@ -56,8 +26,7 @@ export function useFirestoreSearch({ collectionPath, searchField, queryText, lim
56
26
  return [];
57
27
  }
58
28
  const collectionRef = collection(db, collectionPath);
59
- // Build range query for prefix matching
60
- // Using '\uf8ff' as upper bound creates a range that matches all strings starting with the query
29
+ // '\uf8ff' is the highest code point Firestore orders, so the range covers every string with the prefix.
61
30
  const constraints = [
62
31
  ...equalityFilters.map((f) => where(f.field, '==', f.value)),
63
32
  where(searchField, '>=', normalizedQuery),
@@ -77,20 +46,13 @@ export function useFirestoreSearch({ collectionPath, searchField, queryText, lim
77
46
  enabled: shouldSearch,
78
47
  staleTime,
79
48
  });
80
- // Until the debounce catches up, the query's key holds an earlier text, so its result (or its
81
- // absence) is not an answer for the text typed now (FRONTEND-206): report no answer instead —
82
- // still searching when the typed text will be searched, idle when it will not.
83
49
  const typedQuery = normalizeSearchText(queryText);
84
50
  if (typedQuery === normalizedQuery)
85
51
  return searchQuery;
86
52
  const willSearch = enabled && isSearchableText(queryText);
87
53
  return withoutAnswer(searchQuery, willSearch);
88
54
  }
89
- /**
90
- * The query result with every answer field replaced. The other fields stay getters onto the
91
- * original result: TanStack tracks which fields a component reads to decide when it re-renders,
92
- * and reading them all here (a spread) would opt every consumer out of that.
93
- */
55
+ /** Other fields stay getters onto the original result: TanStack re-renders on the fields a component reads, and a spread reads them all. */
94
56
  function withoutAnswer(result, searching) {
95
57
  const answerFields = {
96
58
  data: undefined,
@@ -1 +1 @@
1
- {"version":3,"file":"use-firestore-search.js","sourceRoot":"","sources":["../../../src/react/search/use-firestore-search.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAuB,MAAM,uBAAuB,CAAC;AACtE,OAAO,EACL,UAAU,EACV,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,KAAK,IAAI,cAAc,GAGxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGrC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE7E,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,kBAAkB,CAAwC,EACxE,cAAc,EACd,WAAW,EACX,SAAS,EACT,KAAK,GAAG,aAAa,EACrB,OAAO,GAAG,IAAI,EACd,MAAM,EACN,UAAU,GAAG,mBAAmB,EAChC,SAAS,GAAG,kBAAkB,EAC9B,eAAe,GAAG,EAAE,GACM;IAC1B,MAAM,EAAE,GAAG,cAAc,EAAE,CAAC;IAC5B,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAEhE,4BAA4B;IAC5B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC,EAAE,UAAU,CAAC,CAAC;QAEf,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IAE5B,MAAM,eAAe,GAAG,mBAAmB,CAAC,cAAc,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,OAAO,IAAI,gBAAgB,CAAC,cAAc,CAAC,CAAC;IAEjE,MAAM,WAAW,GAAG,QAAQ,CAAC;QAC3B,QAAQ,EAAE,IAAI,CAAC,MAAM,CACnB,QAAQ,EACR,cAAc,EACd,WAAW,EACX,eAAe,EACf,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAChC;QACD,OAAO,EAAE,KAAK,IAA0B,EAAE;YACxC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,OAAO,EAAE,CAAC;YACZ,CAAC;YAED,MAAM,aAAa,GAAG,UAAU,CAAC,EAAE,EAAE,cAAc,CAAC,CAAC;YAErD,wCAAwC;YACxC,iGAAiG;YACjG,MAAM,WAAW,GAAsB;gBACrC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;gBAC5D,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,CAAC;gBACzC,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,eAAe,GAAG,QAAQ,CAAC;gBACpD,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC;gBAC3B,cAAc,CAAC,KAAK,CAAC;aACtB,CAAC;YAEF,MAAM,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,GAAG,WAAW,CAAC,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC;YAElC,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBACnC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;gBAC/B,MAAM,UAAU,GAAG,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC;gBAClD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;gBACtD,OAAO,IAAiB,CAAC;YAC3B,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,EAAE,YAAY;QACrB,SAAS;KACV,CAAC,CAAC;IAEH,8FAA8F;IAC9F,8FAA8F;IAC9F,+EAA+E;IAC/E,MAAM,UAAU,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;IAClD,IAAI,UAAU,KAAK,eAAe;QAAE,OAAO,WAAW,CAAC;IACvD,MAAM,UAAU,GAAG,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC1D,OAAO,aAAa,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAChD,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAA2C,MAAS,EAAE,SAAkB;IAC5F,MAAM,YAAY,GAA4B;QAC5C,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,IAAI;QACX,OAAO,EAAE,KAAK;QACd,cAAc,EAAE,KAAK;QACrB,cAAc,EAAE,KAAK;QACrB,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,IAAI;QACf,iBAAiB,EAAE,KAAK;QACxB,SAAS,EAAE,KAAK;QAChB,mBAAmB,EAAE,KAAK;QAC1B,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,SAAS;QACpB,UAAU,EAAE,SAAS;QACrB,MAAM,EAAE,SAAS;QACjB,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;QAC5C,aAAa,EAAE,CAAC;QAChB,cAAc,EAAE,CAAC;KAClB,CAAC;IACF,MAAM,IAAI,GAAG,EAAO,CAAC;IACrB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE;YAC/B,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,IAAI;YAClB,GAAG,EAAE,GAAG,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAc,CAAC;SAClF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["'use client';\n\nimport { useState, useEffect } from 'react';\nimport { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport {\n collection,\n getDocs,\n query,\n where,\n orderBy,\n limit as firestoreLimit,\n type DocumentData,\n type QueryConstraint,\n} from 'firebase/firestore';\nimport { useFirestoreDb } from '../firestore/context.js';\nimport { keys } from '../../keys.js';\nimport type { FirestoreSearchOptions } from './types.js';\nimport type { WithId } from '../../firestore/types.js';\nimport { isSearchableText, normalizeSearchText } from '../../search/rule.js';\n\nconst DEFAULT_LIMIT = 5;\nconst DEFAULT_DEBOUNCE_MS = 300;\nconst DEFAULT_STALE_TIME = 60 * 1000; // 1 minute\n\n/**\n * Generic Firestore search hook with debouncing and case-insensitive prefix matching.\n * Automatically normalizes search text to lowercase and uses Firestore range queries.\n *\n * Features:\n * - Debounced input (default 300ms)\n * - Case-insensitive search\n * - Searches only a text `isSearchableText` accepts (`FIRESTORE_SEARCH_MIN_LENGTH`, trimmed)\n * - No answer while the debounce lags the typed text: `data` is undefined and `isLoading` is true\n * (idle instead when the typed text is too short or the search is disabled)\n * - Prefix matching with '\\uf8ff' suffix\n * - Configurable result limit\n *\n * @example\n * ```typescript\n * const { data, isLoading } = useFirestoreSearch<UserProfile>({\n * collectionPath: 'userProfiles',\n * searchField: 'username',\n * queryText: searchValue,\n * });\n *\n * const { data } = useFirestoreSearch<Team>({\n * collectionPath: 'teams',\n * searchField: 'name_lowercase',\n * queryText: searchValue,\n * limit: 10,\n * });\n * ```\n */\nexport function useFirestoreSearch<T extends DocumentData = DocumentData>({\n collectionPath,\n searchField,\n queryText,\n limit = DEFAULT_LIMIT,\n enabled = true,\n select,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n staleTime = DEFAULT_STALE_TIME,\n equalityFilters = [],\n}: FirestoreSearchOptions<T>): UseQueryResult<WithId<T>[], Error> {\n const db = useFirestoreDb();\n const [debouncedQuery, setDebouncedQuery] = useState(queryText);\n\n // Debounce the search query\n useEffect(() => {\n const timer = setTimeout(() => {\n setDebouncedQuery(queryText);\n }, debounceMs);\n\n return () => clearTimeout(timer);\n }, [queryText, debounceMs]);\n\n const normalizedQuery = normalizeSearchText(debouncedQuery);\n const shouldSearch = enabled && isSearchableText(debouncedQuery);\n\n const searchQuery = useQuery({\n queryKey: keys.custom(\n 'search',\n collectionPath,\n searchField,\n normalizedQuery,\n JSON.stringify(equalityFilters),\n ),\n queryFn: async (): Promise<WithId<T>[]> => {\n if (!shouldSearch) {\n return [];\n }\n\n const collectionRef = collection(db, collectionPath);\n\n // Build range query for prefix matching\n // Using '\\uf8ff' as upper bound creates a range that matches all strings starting with the query\n const constraints: QueryConstraint[] = [\n ...equalityFilters.map((f) => where(f.field, '==', f.value)),\n where(searchField, '>=', normalizedQuery),\n where(searchField, '<=', normalizedQuery + '\\uf8ff'),\n orderBy(searchField, 'asc'),\n firestoreLimit(limit),\n ];\n\n const q = query(collectionRef, ...constraints);\n const snapshot = await getDocs(q);\n\n return snapshot.docs.map((docSnap) => {\n const rawData = docSnap.data();\n const dataWithId = { id: docSnap.id, ...rawData };\n const data = select ? select(dataWithId) : dataWithId;\n return data as WithId<T>;\n });\n },\n enabled: shouldSearch,\n staleTime,\n });\n\n // Until the debounce catches up, the query's key holds an earlier text, so its result (or its\n // absence) is not an answer for the text typed now (FRONTEND-206): report no answer instead —\n // still searching when the typed text will be searched, idle when it will not.\n const typedQuery = normalizeSearchText(queryText);\n if (typedQuery === normalizedQuery) return searchQuery;\n const willSearch = enabled && isSearchableText(queryText);\n return withoutAnswer(searchQuery, willSearch);\n}\n\n/**\n * The query result with every answer field replaced. The other fields stay getters onto the\n * original result: TanStack tracks which fields a component reads to decide when it re-renders,\n * and reading them all here (a spread) would opt every consumer out of that.\n */\nfunction withoutAnswer<R extends UseQueryResult<unknown, Error>>(result: R, searching: boolean): R {\n const answerFields: Record<string, unknown> = {\n data: undefined,\n error: null,\n isError: false,\n isLoadingError: false,\n isRefetchError: false,\n isSuccess: false,\n isPending: true,\n isPlaceholderData: false,\n isFetched: false,\n isFetchedAfterMount: false,\n isRefetching: false,\n isLoading: searching,\n isFetching: searching,\n status: 'pending',\n fetchStatus: searching ? 'fetching' : 'idle',\n dataUpdatedAt: 0,\n errorUpdatedAt: 0,\n };\n const view = {} as R;\n for (const key of Object.keys(result)) {\n Object.defineProperty(view, key, {\n enumerable: true,\n configurable: true,\n get: key in answerFields ? () => answerFields[key] : () => result[key as keyof R],\n });\n }\n return view;\n}\n"]}
1
+ {"version":3,"file":"use-firestore-search.js","sourceRoot":"","sources":["../../../src/react/search/use-firestore-search.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useState, useEffect } from 'react';\nimport { useQuery, type UseQueryResult } from '@tanstack/react-query';\nimport {\n collection,\n getDocs,\n query,\n where,\n orderBy,\n limit as firestoreLimit,\n type DocumentData,\n type QueryConstraint,\n} from 'firebase/firestore';\nimport { useFirestoreDb } from '../firestore/context.js';\nimport { keys } from '../../keys.js';\nimport type { FirestoreSearchOptions } from './types.js';\nimport type { WithId } from '../../firestore/types.js';\nimport { isSearchableText, normalizeSearchText } from '../../search/rule.js';\n\nconst DEFAULT_LIMIT = 5;\nconst DEFAULT_DEBOUNCE_MS = 300;\nconst DEFAULT_STALE_TIME = 60 * 1000;\n\nexport function useFirestoreSearch<T extends DocumentData = DocumentData>({\n collectionPath,\n searchField,\n queryText,\n limit = DEFAULT_LIMIT,\n enabled = true,\n select,\n debounceMs = DEFAULT_DEBOUNCE_MS,\n staleTime = DEFAULT_STALE_TIME,\n equalityFilters = [],\n}: FirestoreSearchOptions<T>): UseQueryResult<WithId<T>[], Error> {\n const db = useFirestoreDb();\n const [debouncedQuery, setDebouncedQuery] = useState(queryText);\n\n useEffect(() => {\n const timer = setTimeout(() => {\n setDebouncedQuery(queryText);\n }, debounceMs);\n\n return () => clearTimeout(timer);\n }, [queryText, debounceMs]);\n\n const normalizedQuery = normalizeSearchText(debouncedQuery);\n const shouldSearch = enabled && isSearchableText(debouncedQuery);\n\n const searchQuery = useQuery({\n queryKey: keys.custom(\n 'search',\n collectionPath,\n searchField,\n normalizedQuery,\n JSON.stringify(equalityFilters),\n ),\n queryFn: async (): Promise<WithId<T>[]> => {\n if (!shouldSearch) {\n return [];\n }\n\n const collectionRef = collection(db, collectionPath);\n\n // '\\uf8ff' is the highest code point Firestore orders, so the range covers every string with the prefix.\n const constraints: QueryConstraint[] = [\n ...equalityFilters.map((f) => where(f.field, '==', f.value)),\n where(searchField, '>=', normalizedQuery),\n where(searchField, '<=', normalizedQuery + '\\uf8ff'),\n orderBy(searchField, 'asc'),\n firestoreLimit(limit),\n ];\n\n const q = query(collectionRef, ...constraints);\n const snapshot = await getDocs(q);\n\n return snapshot.docs.map((docSnap) => {\n const rawData = docSnap.data();\n const dataWithId = { id: docSnap.id, ...rawData };\n const data = select ? select(dataWithId) : dataWithId;\n return data as WithId<T>;\n });\n },\n enabled: shouldSearch,\n staleTime,\n });\n\n const typedQuery = normalizeSearchText(queryText);\n if (typedQuery === normalizedQuery) return searchQuery;\n const willSearch = enabled && isSearchableText(queryText);\n return withoutAnswer(searchQuery, willSearch);\n}\n\n/** Other fields stay getters onto the original result: TanStack re-renders on the fields a component reads, and a spread reads them all. */\nfunction withoutAnswer<R extends UseQueryResult<unknown, Error>>(result: R, searching: boolean): R {\n const answerFields: Record<string, unknown> = {\n data: undefined,\n error: null,\n isError: false,\n isLoadingError: false,\n isRefetchError: false,\n isSuccess: false,\n isPending: true,\n isPlaceholderData: false,\n isFetched: false,\n isFetchedAfterMount: false,\n isRefetching: false,\n isLoading: searching,\n isFetching: searching,\n status: 'pending',\n fetchStatus: searching ? 'fetching' : 'idle',\n dataUpdatedAt: 0,\n errorUpdatedAt: 0,\n };\n const view = {} as R;\n for (const key of Object.keys(result)) {\n Object.defineProperty(view, key, {\n enumerable: true,\n configurable: true,\n get: key in answerFields ? () => answerFields[key] : () => result[key as keyof R],\n });\n }\n return view;\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type DefaultError, type MutationFunctionContext, type UseMutationOptions, type UseMutationResult } from '@tanstack/react-query';
3
+ export interface MutationSession {
4
+ uid: string | null;
5
+ isCurrent(): boolean;
6
+ assertCurrent(): void;
7
+ }
8
+ export type SessionMutationFunctionContext = MutationFunctionContext & {
9
+ session: MutationSession;
10
+ };
11
+ export type SessionMutationOptions<TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown> = Omit<UseMutationOptions<TData, TError, TVariables, TOnMutateResult>, 'mutationFn'> & {
12
+ mutationFn: (variables: TVariables, context: SessionMutationFunctionContext) => Promise<TData>;
13
+ };
14
+ export declare class MutationSessionEndedError extends Error {
15
+ name: string;
16
+ constructor(options?: {
17
+ cause?: unknown;
18
+ });
19
+ }
20
+ export interface MutationSessionProviderProps {
21
+ currentUid: string | null;
22
+ children?: ReactNode;
23
+ }
24
+ export declare function MutationSessionProvider({ currentUid, children }: MutationSessionProviderProps): import("react").JSX.Element;
25
+ export declare function useMutationSessionCapture(): () => MutationSession;
26
+ export declare function useSessionMutation<TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown>(options: SessionMutationOptions<TData, TError, TVariables, TOnMutateResult>): UseMutationResult<TData, TError, TVariables, TOnMutateResult>;
27
+ //# sourceMappingURL=session-mutation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-mutation.d.ts","sourceRoot":"","sources":["../../src/react/session-mutation.tsx"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAGL,KAAK,YAAY,EAEjB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,IAAI,OAAO,CAAC;IACrB,aAAa,IAAI,IAAI,CAAC;CACvB;AAED,MAAM,MAAM,8BAA8B,GAAG,uBAAuB,GAAG;IACrE,OAAO,EAAE,eAAe,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,sBAAsB,CAChC,KAAK,GAAG,OAAO,EACf,MAAM,GAAG,YAAY,EACrB,UAAU,GAAG,IAAI,EACjB,eAAe,GAAG,OAAO,IACvB,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,EAAE,YAAY,CAAC,GAAG;IACvF,UAAU,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,8BAA8B,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;CAChG,CAAC;AAEF,qBAAa,yBAA0B,SAAQ,KAAK;IACzC,IAAI,SAAgB;gBAEjB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAG1C;AAQD,MAAM,WAAW,4BAA4B;IAC3C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wBAAgB,uBAAuB,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,4BAA4B,+BAc7F;AAqBD,wBAAgB,yBAAyB,IAAI,MAAM,eAAe,CAGjE;AAsDD,wBAAgB,kBAAkB,CAChC,KAAK,GAAG,OAAO,EACf,MAAM,GAAG,YAAY,EACrB,UAAU,GAAG,IAAI,EACjB,eAAe,GAAG,OAAO,EAEzB,OAAO,EAAE,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,GAC1E,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,eAAe,CAAC,CAmE/D"}