@ttt-productions/query-core 0.14.23 → 0.14.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/firestore/types.d.ts +4 -0
- package/dist/firestore/types.d.ts.map +1 -1
- package/dist/firestore/types.js.map +1 -1
- package/dist/react/callables/create-callables.d.ts +39 -0
- package/dist/react/callables/create-callables.d.ts.map +1 -0
- package/dist/react/callables/create-callables.js +101 -0
- package/dist/react/callables/create-callables.js.map +1 -0
- package/dist/react/firestore/doc-subscription-registry.d.ts.map +1 -1
- package/dist/react/firestore/doc-subscription-registry.js +5 -1
- package/dist/react/firestore/doc-subscription-registry.js.map +1 -1
- package/dist/react/firestore/use-firestore-mutations.d.ts +6 -5
- package/dist/react/firestore/use-firestore-mutations.d.ts.map +1 -1
- package/dist/react/firestore/use-firestore-mutations.js +6 -5
- package/dist/react/firestore/use-firestore-mutations.js.map +1 -1
- package/dist/react/firestore/useBatchFirestoreDocs.d.ts.map +1 -1
- package/dist/react/firestore/useBatchFirestoreDocs.js +18 -6
- package/dist/react/firestore/useBatchFirestoreDocs.js.map +1 -1
- package/dist/react/index.d.ts +4 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +2 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/session-mutation.d.ts +42 -0
- package/dist/react/session-mutation.d.ts.map +1 -0
- package/dist/react/session-mutation.js +175 -0
- package/dist/react/session-mutation.js.map +1 -0
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,kIAAkI;AAClI,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/E,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,WAAW,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAClC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,kIAAkI;AAClI,MAAM,MAAM,oBAAoB,GAAG,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAE/E,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG;IAAE,WAAW,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAClC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GAC7E;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAE1D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC;IACtC,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;KAC7D,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,EAAE,SAAS,OAAO,EAAE,EAAE,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"","sourcesContent":["export type WithId<T> = T & { id: string };\n\n/** Firestore serves cached snapshots offline without firing the error callback, so liveness is read from `metadata.fromCache`. */\nexport type FirestoreSourceState = 'connecting' | 'live' | 'offline' | 'error';\n\nexport type WithSourceState<R> = R & { sourceState: FirestoreSourceState };\n\nexport type BatchFirestoreDocOutcome<T> =\n | { status: 'loading' }\n | { status: 'present'; data: T }\n | { status: 'absent' }\n | { status: 'failed'; error: Error; retrying: boolean };\n\nexport interface FirestoreBaseOptions {\n queryKey: readonly unknown[];\n enabled?: boolean;\n staleTime?: number;\n gcTime?: number;\n}\n\nexport interface FirestoreMutationOptions<T> {\n docPath?: string;\n invalidateKeys?: readonly unknown[][];\n optimistic?: {\n queryKey: readonly unknown[];\n updater: (oldData: T | undefined, newData: Partial<T>) => T;\n };\n}\n\nexport interface FirestoreBatchOptions {\n invalidateKeys?: readonly unknown[][];\n batchSize?: number;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/firestore/types.ts"],"names":[],"mappings":"","sourcesContent":["export type WithId<T> = T & { id: string };\n\n/** Firestore serves cached snapshots offline without firing the error callback, so liveness is read from `metadata.fromCache`. */\nexport type FirestoreSourceState = 'connecting' | 'live' | 'offline' | 'error';\n\nexport type WithSourceState<R> = R & { sourceState: FirestoreSourceState };\n\nexport type BatchFirestoreDocOutcome<T> =\n | { status: 'loading' }\n | { status: 'present'; data: T; failure?: { error: Error; retrying: boolean } }\n | { status: 'absent' }\n | { status: 'failed'; error: Error; retrying: boolean };\n\nexport interface FirestoreBaseOptions {\n queryKey: readonly unknown[];\n enabled?: boolean;\n staleTime?: number;\n gcTime?: number;\n}\n\nexport interface FirestoreMutationOptions<T> {\n docPath?: string;\n invalidateKeys?: readonly unknown[][];\n optimistic?: {\n queryKey: readonly unknown[];\n updater: (oldData: T | undefined, newData: Partial<T>) => T;\n };\n}\n\nexport interface FirestoreBatchOptions {\n invalidateKeys?: readonly unknown[][];\n batchSize?: number;\n}\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ExpectedCallableAnswerCode } from '@ttt-productions/firebase-helpers';
|
|
2
|
+
import { type FunctionsProvider } from '@ttt-productions/firebase-helpers/client';
|
|
3
|
+
import { type SessionMutationOptions, type SessionMutationResult } from '../session-mutation.js';
|
|
4
|
+
export interface CallableErrorRouting {
|
|
5
|
+
showErrorToast: boolean;
|
|
6
|
+
answeredRefusals: readonly ExpectedCallableAnswerCode[];
|
|
7
|
+
isAnswerSurfacedByCaller?: (error: unknown) => boolean;
|
|
8
|
+
}
|
|
9
|
+
export type CallableCaptureContext = Record<string, unknown>;
|
|
10
|
+
export interface CallablePolicy {
|
|
11
|
+
getFunctions: FunctionsProvider;
|
|
12
|
+
timeoutMs: number;
|
|
13
|
+
resolveLimitedUseAppCheck: (requested: boolean) => boolean;
|
|
14
|
+
captureFault: (error: unknown, context: CallableCaptureContext) => void;
|
|
15
|
+
captureRecoveredFallback: (error: unknown, context: CallableCaptureContext) => void;
|
|
16
|
+
onActionError: (error: unknown, routing: CallableErrorRouting) => void;
|
|
17
|
+
}
|
|
18
|
+
export interface CallableDeclaration {
|
|
19
|
+
limitedUseAppCheck?: true;
|
|
20
|
+
}
|
|
21
|
+
interface CallableTransportOptions extends Partial<CallableErrorRouting> {
|
|
22
|
+
captureFaults?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export type CallableMutationOptions<TInput, TResult, TOnMutateResult = unknown> = Omit<SessionMutationOptions<TResult, Error, TInput, TOnMutateResult>, 'mutationFn' | 'retry'> & Pick<CallableTransportOptions, 'showErrorToast' | 'answeredRefusals' | 'isAnswerSurfacedByCaller' | 'captureFaults'>;
|
|
25
|
+
export declare const MAX_RESUMABLE_CALLS = 12;
|
|
26
|
+
export type ResumableOutcome<TResult> = TResult & {
|
|
27
|
+
interruption: Error | null;
|
|
28
|
+
};
|
|
29
|
+
export interface Callables {
|
|
30
|
+
createCallableHook<TInput, TResult>(functionName: string, declaration?: CallableDeclaration): <TOnMutateResult = unknown>(options?: CallableMutationOptions<TInput, TResult, TOnMutateResult>) => SessionMutationResult<TResult, Error, TInput, TOnMutateResult>;
|
|
31
|
+
createResumableCallableHook<TInput, TResult extends {
|
|
32
|
+
complete: boolean;
|
|
33
|
+
}>(functionName: string, merge: (earlier: TResult, later: TResult) => TResult, declaration?: CallableDeclaration): <TOnMutateResult = unknown>(options?: CallableMutationOptions<TInput, ResumableOutcome<TResult>, TOnMutateResult>) => SessionMutationResult<ResumableOutcome<TResult>, Error, TInput, TOnMutateResult>;
|
|
34
|
+
createCallableReader<TInput, TResult>(functionName: string, declaration?: CallableDeclaration): () => (input: TInput) => Promise<TResult>;
|
|
35
|
+
createCallableInvoker<TInput, TResult>(functionName: string, declaration?: CallableDeclaration): () => (input: TInput) => Promise<TResult>;
|
|
36
|
+
}
|
|
37
|
+
export declare function createCallables(policy: CallablePolicy): Callables;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=create-callables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-callables.d.ts","sourceRoot":"","sources":["../../../src/react/callables/create-callables.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useCallback, useMemo, useRef } from 'react';
|
|
3
|
+
import { callCallable, isRecoveredFallbackReport, } from '@ttt-productions/firebase-helpers/client';
|
|
4
|
+
import { useMutationSessionCapture, useSessionMutation, } from '../session-mutation.js';
|
|
5
|
+
export const MAX_RESUMABLE_CALLS = 12;
|
|
6
|
+
export function createCallables(policy) {
|
|
7
|
+
function useCallableTransport(functionName, declaration, options) {
|
|
8
|
+
const optionsRef = useRef(options);
|
|
9
|
+
optionsRef.current = options;
|
|
10
|
+
const limitedUseAppCheck = policy.resolveLimitedUseAppCheck(declaration.limitedUseAppCheck === true);
|
|
11
|
+
return useCallback((input, session) => callCallable(policy.getFunctions, functionName, input, {
|
|
12
|
+
captureException: (error, context) => {
|
|
13
|
+
if (optionsRef.current.captureFaults !== false)
|
|
14
|
+
policy.captureFault(error, context);
|
|
15
|
+
else if (isRecoveredFallbackReport(context))
|
|
16
|
+
policy.captureRecoveredFallback(error, context);
|
|
17
|
+
},
|
|
18
|
+
onError: (error) => {
|
|
19
|
+
if (!session.isCurrent())
|
|
20
|
+
return;
|
|
21
|
+
const { showErrorToast = true, answeredRefusals = [], isAnswerSurfacedByCaller, } = optionsRef.current;
|
|
22
|
+
policy.onActionError(error, {
|
|
23
|
+
showErrorToast,
|
|
24
|
+
answeredRefusals,
|
|
25
|
+
isAnswerSurfacedByCaller,
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
}, { timeoutMs: policy.timeoutMs, limitedUseAppCheck }), [functionName, limitedUseAppCheck]);
|
|
29
|
+
}
|
|
30
|
+
function useSessionBoundCall(call) {
|
|
31
|
+
const captureSession = useMutationSessionCapture();
|
|
32
|
+
return useMemo(() => (input) => call(input, captureSession()), [call, captureSession]);
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
createCallableHook(functionName, declaration = {}) {
|
|
36
|
+
return function useNamedCallable(options = {}) {
|
|
37
|
+
const { showErrorToast, answeredRefusals, isAnswerSurfacedByCaller, captureFaults, ...mutationOptions } = options;
|
|
38
|
+
const call = useCallableTransport(functionName, declaration, {
|
|
39
|
+
showErrorToast,
|
|
40
|
+
answeredRefusals,
|
|
41
|
+
isAnswerSurfacedByCaller,
|
|
42
|
+
captureFaults,
|
|
43
|
+
});
|
|
44
|
+
// `retry: false` comes last so nothing overrides it: a deadline expiry is an unknown outcome,
|
|
45
|
+
// and a retry after a committed first attempt writes twice.
|
|
46
|
+
return useSessionMutation({
|
|
47
|
+
...mutationOptions,
|
|
48
|
+
retry: false,
|
|
49
|
+
mutationFn: (input, { session }) => call(input, session),
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
createResumableCallableHook(functionName, merge, declaration = {}) {
|
|
54
|
+
return function useNamedResumableCallable(options = {}) {
|
|
55
|
+
const { showErrorToast, answeredRefusals, isAnswerSurfacedByCaller, captureFaults, ...mutationOptions } = options;
|
|
56
|
+
const call = useCallableTransport(functionName, declaration, {
|
|
57
|
+
showErrorToast,
|
|
58
|
+
answeredRefusals,
|
|
59
|
+
isAnswerSurfacedByCaller,
|
|
60
|
+
captureFaults,
|
|
61
|
+
});
|
|
62
|
+
return useSessionMutation({
|
|
63
|
+
...mutationOptions,
|
|
64
|
+
retry: false,
|
|
65
|
+
mutationFn: async (input, { session }) => {
|
|
66
|
+
let progress = await call(input, session);
|
|
67
|
+
for (let calls = 1; !progress.complete && calls < MAX_RESUMABLE_CALLS; calls += 1) {
|
|
68
|
+
session.assertCurrent();
|
|
69
|
+
let later;
|
|
70
|
+
try {
|
|
71
|
+
later = await call(input, session);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const interruption = error instanceof Error ? error : new Error(String(error));
|
|
75
|
+
return { ...progress, complete: false, interruption };
|
|
76
|
+
}
|
|
77
|
+
progress = merge(progress, later);
|
|
78
|
+
}
|
|
79
|
+
return { ...progress, interruption: null };
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
createCallableReader(functionName, declaration = {}) {
|
|
85
|
+
return function useNamedCallableReader() {
|
|
86
|
+
const call = useCallableTransport(functionName, declaration, {
|
|
87
|
+
showErrorToast: false,
|
|
88
|
+
captureFaults: false,
|
|
89
|
+
});
|
|
90
|
+
return useSessionBoundCall(call);
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
createCallableInvoker(functionName, declaration = {}) {
|
|
94
|
+
return function useNamedCallableInvoker() {
|
|
95
|
+
const call = useCallableTransport(functionName, declaration, {});
|
|
96
|
+
return useSessionBoundCall(call);
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=create-callables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-callables.js","sourceRoot":"","sources":["../../../src/react/callables/create-callables.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useMemo, useRef } from 'react';\nimport type { ExpectedCallableAnswerCode } from '@ttt-productions/firebase-helpers';\nimport {\n callCallable,\n isRecoveredFallbackReport,\n type FunctionsProvider,\n} from '@ttt-productions/firebase-helpers/client';\nimport {\n useMutationSessionCapture,\n useSessionMutation,\n type MutationSession,\n type SessionMutationOptions,\n type SessionMutationResult,\n} from '../session-mutation.js';\n\nexport interface CallableErrorRouting {\n showErrorToast: boolean;\n answeredRefusals: readonly ExpectedCallableAnswerCode[];\n isAnswerSurfacedByCaller?: (error: unknown) => boolean;\n}\n\nexport type CallableCaptureContext = Record<string, unknown>;\n\nexport interface CallablePolicy {\n getFunctions: FunctionsProvider;\n timeoutMs: number;\n resolveLimitedUseAppCheck: (requested: boolean) => boolean;\n captureFault: (error: unknown, context: CallableCaptureContext) => void;\n captureRecoveredFallback: (error: unknown, context: CallableCaptureContext) => void;\n onActionError: (error: unknown, routing: CallableErrorRouting) => void;\n}\n\nexport interface CallableDeclaration {\n limitedUseAppCheck?: true;\n}\n\ninterface CallableTransportOptions extends Partial<CallableErrorRouting> {\n captureFaults?: boolean;\n}\n\nexport type CallableMutationOptions<TInput, TResult, TOnMutateResult = unknown> = Omit<\n SessionMutationOptions<TResult, Error, TInput, TOnMutateResult>,\n 'mutationFn' | 'retry'\n> &\n Pick<\n CallableTransportOptions,\n 'showErrorToast' | 'answeredRefusals' | 'isAnswerSurfacedByCaller' | 'captureFaults'\n >;\n\nexport const MAX_RESUMABLE_CALLS = 12;\n\nexport type ResumableOutcome<TResult> = TResult & { interruption: Error | null };\n\nexport interface Callables {\n createCallableHook<TInput, TResult>(\n functionName: string,\n declaration?: CallableDeclaration,\n ): <TOnMutateResult = unknown>(\n options?: CallableMutationOptions<TInput, TResult, TOnMutateResult>,\n ) => SessionMutationResult<TResult, Error, TInput, TOnMutateResult>;\n createResumableCallableHook<TInput, TResult extends { complete: boolean }>(\n functionName: string,\n merge: (earlier: TResult, later: TResult) => TResult,\n declaration?: CallableDeclaration,\n ): <TOnMutateResult = unknown>(\n options?: CallableMutationOptions<TInput, ResumableOutcome<TResult>, TOnMutateResult>,\n ) => SessionMutationResult<ResumableOutcome<TResult>, Error, TInput, TOnMutateResult>;\n createCallableReader<TInput, TResult>(\n functionName: string,\n declaration?: CallableDeclaration,\n ): () => (input: TInput) => Promise<TResult>;\n createCallableInvoker<TInput, TResult>(\n functionName: string,\n declaration?: CallableDeclaration,\n ): () => (input: TInput) => Promise<TResult>;\n}\n\ntype CallableTransport = <TInput, TResult>(\n input: TInput,\n session: MutationSession,\n) => Promise<TResult>;\n\nexport function createCallables(policy: CallablePolicy): Callables {\n function useCallableTransport(\n functionName: string,\n declaration: CallableDeclaration,\n options: CallableTransportOptions,\n ): CallableTransport {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n const limitedUseAppCheck = policy.resolveLimitedUseAppCheck(\n declaration.limitedUseAppCheck === true,\n );\n\n return useCallback(\n <TInput, TResult>(input: TInput, session: MutationSession) =>\n callCallable<TInput, TResult>(\n policy.getFunctions,\n functionName,\n input,\n {\n captureException: (error, context) => {\n if (optionsRef.current.captureFaults !== false) policy.captureFault(error, context);\n else if (isRecoveredFallbackReport(context))\n policy.captureRecoveredFallback(error, context);\n },\n onError: (error) => {\n if (!session.isCurrent()) return;\n const {\n showErrorToast = true,\n answeredRefusals = [],\n isAnswerSurfacedByCaller,\n } = optionsRef.current;\n policy.onActionError(error, {\n showErrorToast,\n answeredRefusals,\n isAnswerSurfacedByCaller,\n });\n },\n },\n { timeoutMs: policy.timeoutMs, limitedUseAppCheck },\n ),\n [functionName, limitedUseAppCheck],\n );\n }\n\n function useSessionBoundCall<TInput, TResult>(\n call: CallableTransport,\n ): (input: TInput) => Promise<TResult> {\n const captureSession = useMutationSessionCapture();\n return useMemo(\n () => (input: TInput) => call<TInput, TResult>(input, captureSession()),\n [call, captureSession],\n );\n }\n\n return {\n createCallableHook<TInput, TResult>(\n functionName: string,\n declaration: CallableDeclaration = {},\n ) {\n return function useNamedCallable<TOnMutateResult = unknown>(\n options: CallableMutationOptions<TInput, TResult, TOnMutateResult> = {},\n ): SessionMutationResult<TResult, Error, TInput, TOnMutateResult> {\n const {\n showErrorToast,\n answeredRefusals,\n isAnswerSurfacedByCaller,\n captureFaults,\n ...mutationOptions\n } = options;\n const call = useCallableTransport(functionName, declaration, {\n showErrorToast,\n answeredRefusals,\n isAnswerSurfacedByCaller,\n captureFaults,\n });\n // `retry: false` comes last so nothing overrides it: a deadline expiry is an unknown outcome,\n // and a retry after a committed first attempt writes twice.\n return useSessionMutation<TResult, Error, TInput, TOnMutateResult>({\n ...mutationOptions,\n retry: false,\n mutationFn: (input, { session }) => call<TInput, TResult>(input, session),\n });\n };\n },\n\n createResumableCallableHook<TInput, TResult extends { complete: boolean }>(\n functionName: string,\n merge: (earlier: TResult, later: TResult) => TResult,\n declaration: CallableDeclaration = {},\n ) {\n return function useNamedResumableCallable<TOnMutateResult = unknown>(\n options: CallableMutationOptions<TInput, ResumableOutcome<TResult>, TOnMutateResult> = {},\n ): SessionMutationResult<ResumableOutcome<TResult>, Error, TInput, TOnMutateResult> {\n const {\n showErrorToast,\n answeredRefusals,\n isAnswerSurfacedByCaller,\n captureFaults,\n ...mutationOptions\n } = options;\n const call = useCallableTransport(functionName, declaration, {\n showErrorToast,\n answeredRefusals,\n isAnswerSurfacedByCaller,\n captureFaults,\n });\n return useSessionMutation<ResumableOutcome<TResult>, Error, TInput, TOnMutateResult>({\n ...mutationOptions,\n retry: false,\n mutationFn: async (input, { session }): Promise<ResumableOutcome<TResult>> => {\n let progress = await call<TInput, TResult>(input, session);\n for (let calls = 1; !progress.complete && calls < MAX_RESUMABLE_CALLS; calls += 1) {\n session.assertCurrent();\n let later: TResult;\n try {\n later = await call<TInput, TResult>(input, session);\n } catch (error) {\n const interruption = error instanceof Error ? error : new Error(String(error));\n return { ...progress, complete: false, interruption };\n }\n progress = merge(progress, later);\n }\n return { ...progress, interruption: null };\n },\n });\n };\n },\n\n createCallableReader<TInput, TResult>(\n functionName: string,\n declaration: CallableDeclaration = {},\n ) {\n return function useNamedCallableReader(): (input: TInput) => Promise<TResult> {\n const call = useCallableTransport(functionName, declaration, {\n showErrorToast: false,\n captureFaults: false,\n });\n return useSessionBoundCall<TInput, TResult>(call);\n };\n },\n\n createCallableInvoker<TInput, TResult>(\n functionName: string,\n declaration: CallableDeclaration = {},\n ) {\n return function useNamedCallableInvoker(): (input: TInput) => Promise<TResult> {\n const call = useCallableTransport(functionName, declaration, {});\n return useSessionBoundCall<TInput, TResult>(call);\n };\n },\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doc-subscription-registry.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"doc-subscription-registry.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAoBzD,wBAAgB,eAAe,CAC7B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAET;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,GACT,KAAK,GAAG,IAAI,CAEd;AAWD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,EAAE,SAAS,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,IAAI,CA0DnE;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAEtE"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { doc, onSnapshot } from 'firebase/firestore';
|
|
3
|
+
import { isPermissionDeniedError } from './resubscribe.js';
|
|
3
4
|
const registries = new WeakMap();
|
|
4
5
|
function registryKey(queryKeyPrefix, id) {
|
|
5
6
|
return `${queryKeyPrefix} ${id}`;
|
|
@@ -39,7 +40,10 @@ export function subscribeDoc(params) {
|
|
|
39
40
|
sub.onUpdate();
|
|
40
41
|
}, (error) => {
|
|
41
42
|
created.error = error;
|
|
42
|
-
queryClient.
|
|
43
|
+
const held = queryClient.getQueryData([queryKeyPrefix, id]);
|
|
44
|
+
if (held === undefined || held === null || isPermissionDeniedError(error)) {
|
|
45
|
+
queryClient.setQueryData([queryKeyPrefix, id], null, { updatedAt: Date.now() });
|
|
46
|
+
}
|
|
43
47
|
for (const sub of [...subscribers])
|
|
44
48
|
sub.onError?.(error);
|
|
45
49
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doc-subscription-registry.js","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,GAAG,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"doc-subscription-registry.js","sourceRoot":"","sources":["../../../src/react/firestore/doc-subscription-registry.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { doc, onSnapshot, type Firestore } from 'firebase/firestore';\nimport type { QueryClient } from '@tanstack/react-query';\nimport { isPermissionDeniedError } from './resubscribe.js';\n\ntype Subscriber = {\n onUpdate: () => void;\n onError?: (error: Error) => void;\n};\n\ntype Entry = {\n unsubscribe: () => void;\n subscribers: Set<Subscriber>;\n error: Error | null;\n};\n\nconst registries = new WeakMap<QueryClient, Map<string, Entry>>();\n\nfunction registryKey(queryKeyPrefix: string, id: string): string {\n return `${queryKeyPrefix} ${id}`;\n}\n\nexport function isListenerOwned(\n queryClient: QueryClient,\n queryKeyPrefix: string,\n id: string,\n): boolean {\n return registries.get(queryClient)?.has(registryKey(queryKeyPrefix, id)) ?? false;\n}\n\nexport function listenerErrorOf(\n queryClient: QueryClient,\n queryKeyPrefix: string,\n id: string,\n): Error | null {\n return registries.get(queryClient)?.get(registryKey(queryKeyPrefix, id))?.error ?? null;\n}\n\nfunction getRegistry(queryClient: QueryClient): Map<string, Entry> {\n let registry = registries.get(queryClient);\n if (!registry) {\n registry = new Map();\n registries.set(queryClient, registry);\n }\n return registry;\n}\n\nexport interface SubscribeDocParams {\n queryClient: QueryClient;\n db: Firestore;\n collectionPath: string;\n queryKeyPrefix: string;\n id: string;\n onUpdate: () => void;\n onError?: (error: Error) => void;\n}\n\nexport function subscribeDoc(params: SubscribeDocParams): () => void {\n const { queryClient, db, collectionPath, queryKeyPrefix, id, onUpdate, onError } = params;\n const registry = getRegistry(queryClient);\n const key = registryKey(queryKeyPrefix, id);\n\n let entry = registry.get(key);\n if (!entry) {\n const created: Entry = {\n unsubscribe: () => {},\n subscribers: new Set<Subscriber>(),\n error: null,\n };\n const subscribers = created.subscribers;\n const ref = doc(db, collectionPath, id);\n created.unsubscribe = onSnapshot(\n ref,\n (snapshot) => {\n created.error = null;\n queryClient.setQueryData(\n [queryKeyPrefix, id],\n snapshot.exists() ? { id: snapshot.id, ...snapshot.data() } : null,\n { updatedAt: Date.now() },\n );\n // Copy before iterating: an onUpdate could (re-entrantly) unsubscribe.\n for (const sub of [...subscribers]) sub.onUpdate();\n },\n (error) => {\n created.error = error;\n const held = queryClient.getQueryData([queryKeyPrefix, id]);\n if (held === undefined || held === null || isPermissionDeniedError(error)) {\n queryClient.setQueryData([queryKeyPrefix, id], null, { updatedAt: Date.now() });\n }\n for (const sub of [...subscribers]) sub.onError?.(error);\n },\n );\n entry = created;\n registry.set(key, entry);\n }\n\n const subscriber: Subscriber = { onUpdate, onError };\n entry.subscribers.add(subscriber);\n if (entry.error) onError?.(entry.error);\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = registry.get(key);\n if (!current) return;\n current.subscribers.delete(subscriber);\n if (current.subscribers.size === 0) {\n current.unsubscribe();\n registry.delete(key);\n if (current.error) {\n void queryClient.invalidateQueries({ queryKey: [queryKeyPrefix, id], exact: true });\n }\n }\n };\n}\n\nexport function __activeListenerCount(queryClient: QueryClient): number {\n return registries.get(queryClient)?.size ?? 0;\n}\n"]}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { type QueryKey
|
|
1
|
+
import { type QueryKey } from '@tanstack/react-query';
|
|
2
2
|
import { type DocumentData } from 'firebase/firestore';
|
|
3
|
+
import { type SessionMutationResult } from '../session-mutation.js';
|
|
3
4
|
import type { FirestoreMutationOptions, FirestoreBatchOptions } from '../../firestore/types.js';
|
|
4
5
|
import type { MutationOperation } from './types.js';
|
|
5
6
|
interface SetResult<T> {
|
|
6
7
|
id: string;
|
|
7
8
|
data: T;
|
|
8
9
|
}
|
|
9
|
-
export declare function useFirestoreSet<T extends DocumentData>({ invalidateKeys, }?: Pick<FirestoreMutationOptions<T>, 'invalidateKeys'>):
|
|
10
|
+
export declare function useFirestoreSet<T extends DocumentData>({ invalidateKeys, }?: Pick<FirestoreMutationOptions<T>, 'invalidateKeys'>): SessionMutationResult<SetResult<T>, Error, {
|
|
10
11
|
docPath: string;
|
|
11
12
|
data: T;
|
|
12
13
|
merge?: boolean;
|
|
13
14
|
}>;
|
|
14
|
-
export declare function useFirestoreUpdate<T extends DocumentData>({ invalidateKeys, optimistic, }?: FirestoreMutationOptions<T>):
|
|
15
|
+
export declare function useFirestoreUpdate<T extends DocumentData>({ invalidateKeys, optimistic, }?: FirestoreMutationOptions<T>): SessionMutationResult<Partial<T>, Error, {
|
|
15
16
|
docPath: string;
|
|
16
17
|
data: Partial<T>;
|
|
17
18
|
}, {
|
|
@@ -23,7 +24,7 @@ export declare function useFirestoreDelete<T = unknown>({ invalidateKeys, optimi
|
|
|
23
24
|
queryKey: QueryKey;
|
|
24
25
|
updater: (oldData: T | undefined, docPath: string) => T;
|
|
25
26
|
};
|
|
26
|
-
}):
|
|
27
|
+
}): SessionMutationResult<string, Error, {
|
|
27
28
|
docPath: string;
|
|
28
29
|
}, {
|
|
29
30
|
previousData: T | undefined;
|
|
@@ -32,7 +33,7 @@ interface BatchResult {
|
|
|
32
33
|
committed: number;
|
|
33
34
|
batches: number;
|
|
34
35
|
}
|
|
35
|
-
export declare function useFirestoreBatch({ invalidateKeys, batchSize, }?: FirestoreBatchOptions):
|
|
36
|
+
export declare function useFirestoreBatch({ invalidateKeys, batchSize, }?: FirestoreBatchOptions): SessionMutationResult<BatchResult, Error, {
|
|
36
37
|
operations: MutationOperation[];
|
|
37
38
|
}>;
|
|
38
39
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-firestore-mutations.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/use-firestore-mutations.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"use-firestore-mutations.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/use-firestore-mutations.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAsB,KAAK,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAIpD,UAAU,SAAS,CAAC,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,CAAC,CAAC;CACT;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS,YAAY,EAAE,EACtD,cAAmB,GACpB,GAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,gBAAgB,CAAM,GAAG,qBAAqB,CACjF,SAAS,CAAC,CAAC,CAAC,EACZ,KAAK,EACL;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAC9C,CAwBA;AAED,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,YAAY,EAAE,EACzD,cAAmB,EACnB,UAAU,GACX,GAAE,wBAAwB,CAAC,CAAC,CAAM,GAAG,qBAAqB,CACzD,OAAO,CAAC,CAAC,CAAC,EACV,KAAK,EACL;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;CAAE,EACrC;IAAE,YAAY,EAAE,CAAC,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,CAC5C,CAoCA;AAED,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9C,cAAmB,EACnB,UAAU,GACX,GAAE;IACD,cAAc,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACrC,UAAU,CAAC,EAAE;QACX,QAAQ,EAAE,QAAQ,CAAC;QACnB,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC,CAAC;KACzD,CAAC;CACE,GAAG,qBAAqB,CAC5B,MAAM,EACN,KAAK,EACL;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EACnB;IAAE,YAAY,EAAE,CAAC,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,CAC5C,CAkCA;AAED,UAAU,WAAW;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,cAAmB,EACnB,SAA8B,GAC/B,GAAE,qBAA0B,GAAG,qBAAqB,CACnD,WAAW,EACX,KAAK,EACL;IAAE,UAAU,EAAE,iBAAiB,EAAE,CAAA;CAAE,CACpC,CAmDA"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
2
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
3
3
|
import { doc, setDoc, updateDoc, deleteDoc, writeBatch, } from 'firebase/firestore';
|
|
4
4
|
import { useFirestoreDb } from './context.js';
|
|
5
|
+
import { useSessionMutation } from '../session-mutation.js';
|
|
5
6
|
const DEFAULT_BATCH_SIZE = 450;
|
|
6
7
|
export function useFirestoreSet({ invalidateKeys = [], } = {}) {
|
|
7
8
|
const db = useFirestoreDb();
|
|
8
9
|
const queryClient = useQueryClient();
|
|
9
|
-
return
|
|
10
|
+
return useSessionMutation({
|
|
10
11
|
mutationFn: async ({ docPath, data, merge = false, }) => {
|
|
11
12
|
const docRef = doc(db, docPath);
|
|
12
13
|
await setDoc(docRef, data, { merge });
|
|
@@ -22,7 +23,7 @@ export function useFirestoreSet({ invalidateKeys = [], } = {}) {
|
|
|
22
23
|
export function useFirestoreUpdate({ invalidateKeys = [], optimistic, } = {}) {
|
|
23
24
|
const db = useFirestoreDb();
|
|
24
25
|
const queryClient = useQueryClient();
|
|
25
|
-
return
|
|
26
|
+
return useSessionMutation({
|
|
26
27
|
mutationFn: async ({ docPath, data }) => {
|
|
27
28
|
const docRef = doc(db, docPath);
|
|
28
29
|
await updateDoc(docRef, data);
|
|
@@ -54,7 +55,7 @@ export function useFirestoreUpdate({ invalidateKeys = [], optimistic, } = {}) {
|
|
|
54
55
|
export function useFirestoreDelete({ invalidateKeys = [], optimistic, } = {}) {
|
|
55
56
|
const db = useFirestoreDb();
|
|
56
57
|
const queryClient = useQueryClient();
|
|
57
|
-
return
|
|
58
|
+
return useSessionMutation({
|
|
58
59
|
mutationFn: async ({ docPath }) => {
|
|
59
60
|
const docRef = doc(db, docPath);
|
|
60
61
|
await deleteDoc(docRef);
|
|
@@ -86,7 +87,7 @@ export function useFirestoreDelete({ invalidateKeys = [], optimistic, } = {}) {
|
|
|
86
87
|
export function useFirestoreBatch({ invalidateKeys = [], batchSize = DEFAULT_BATCH_SIZE, } = {}) {
|
|
87
88
|
const db = useFirestoreDb();
|
|
88
89
|
const queryClient = useQueryClient();
|
|
89
|
-
return
|
|
90
|
+
return useSessionMutation({
|
|
90
91
|
mutationFn: async ({ operations }) => {
|
|
91
92
|
const chunks = [];
|
|
92
93
|
for (let i = 0; i < operations.length; i += batchSize) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-firestore-mutations.js","sourceRoot":"","sources":["../../../src/react/firestore/use-firestore-mutations.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport {\n useMutation,\n useQueryClient,\n type QueryKey,\n type UseMutationResult,\n} from '@tanstack/react-query';\nimport {\n doc,\n setDoc,\n updateDoc,\n deleteDoc,\n writeBatch,\n type DocumentData,\n} from 'firebase/firestore';\nimport { useFirestoreDb } from './context.js';\nimport type { FirestoreMutationOptions, FirestoreBatchOptions } from '../../firestore/types.js';\nimport type { MutationOperation } from './types.js';\n\nconst DEFAULT_BATCH_SIZE = 450;\n\ninterface SetResult<T> {\n id: string;\n data: T;\n}\n\nexport function useFirestoreSet<T extends DocumentData>({\n invalidateKeys = [],\n}: Pick<FirestoreMutationOptions<T>, 'invalidateKeys'> = {}): UseMutationResult<\n SetResult<T>,\n Error,\n { docPath: string; data: T; merge?: boolean }\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({\n docPath,\n data,\n merge = false,\n }: {\n docPath: string;\n data: T;\n merge?: boolean;\n }) => {\n const docRef = doc(db, docPath);\n await setDoc(docRef, data, { merge });\n return { id: docRef.id, data };\n },\n onSuccess: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n },\n });\n}\n\nexport function useFirestoreUpdate<T extends DocumentData>({\n invalidateKeys = [],\n optimistic,\n}: FirestoreMutationOptions<T> = {}): UseMutationResult<\n Partial<T>,\n Error,\n { docPath: string; data: Partial<T> },\n { previousData: T | undefined } | undefined\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ docPath, data }: { docPath: string; data: Partial<T> }) => {\n const docRef = doc(db, docPath);\n await updateDoc(docRef, data as DocumentData);\n return data;\n },\n onMutate: async ({ data }) => {\n if (!optimistic) return undefined;\n\n await queryClient.cancelQueries({ queryKey: optimistic.queryKey });\n const previousData = queryClient.getQueryData<T>(optimistic.queryKey);\n\n queryClient.setQueryData<T>(optimistic.queryKey, (old) =>\n optimistic.updater(old, data as Partial<T>),\n );\n\n return { previousData };\n },\n onError: (_error, _variables, context) => {\n if (optimistic && context?.previousData !== undefined) {\n queryClient.setQueryData(optimistic.queryKey, context.previousData);\n }\n },\n onSettled: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n if (optimistic) {\n queryClient.invalidateQueries({ queryKey: optimistic.queryKey });\n }\n },\n });\n}\n\nexport function useFirestoreDelete<T = unknown>({\n invalidateKeys = [],\n optimistic,\n}: {\n invalidateKeys?: readonly QueryKey[];\n optimistic?: {\n queryKey: QueryKey;\n updater: (oldData: T | undefined, docPath: string) => T;\n };\n} = {}): UseMutationResult<\n string,\n Error,\n { docPath: string },\n { previousData: T | undefined } | undefined\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ docPath }: { docPath: string }) => {\n const docRef = doc(db, docPath);\n await deleteDoc(docRef);\n return docPath;\n },\n onMutate: async ({ docPath }) => {\n if (!optimistic) return undefined;\n\n await queryClient.cancelQueries({ queryKey: optimistic.queryKey });\n const previousData = queryClient.getQueryData<T>(optimistic.queryKey);\n\n queryClient.setQueryData<T>(optimistic.queryKey, (old) => optimistic.updater(old, docPath));\n\n return { previousData };\n },\n onError: (_error, _variables, context) => {\n if (optimistic && context?.previousData !== undefined) {\n queryClient.setQueryData(optimistic.queryKey, context.previousData);\n }\n },\n onSettled: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n if (optimistic) {\n queryClient.invalidateQueries({ queryKey: optimistic.queryKey });\n }\n },\n });\n}\n\ninterface BatchResult {\n committed: number;\n batches: number;\n}\n\nexport function useFirestoreBatch({\n invalidateKeys = [],\n batchSize = DEFAULT_BATCH_SIZE,\n}: FirestoreBatchOptions = {}): UseMutationResult<\n BatchResult,\n Error,\n { operations: MutationOperation[] }\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: async ({ operations }: { operations: MutationOperation[] }) => {\n const chunks: MutationOperation[][] = [];\n for (let i = 0; i < operations.length; i += batchSize) {\n chunks.push(operations.slice(i, i + batchSize));\n }\n\n let totalCommitted = 0;\n\n for (const chunk of chunks) {\n const batch = writeBatch(db);\n\n for (const op of chunk) {\n const docRef = doc(db, op.docPath);\n\n switch (op.type) {\n case 'set':\n if (op.merge) {\n batch.set(docRef, op.data, { merge: true });\n } else {\n batch.set(docRef, op.data);\n }\n break;\n case 'update':\n batch.update(docRef, op.data);\n break;\n case 'delete':\n batch.delete(docRef);\n break;\n }\n }\n\n await batch.commit();\n totalCommitted += chunk.length;\n }\n\n return {\n committed: totalCommitted,\n batches: chunks.length,\n };\n },\n onSuccess: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n },\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"use-firestore-mutations.js","sourceRoot":"","sources":["../../../src/react/firestore/use-firestore-mutations.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useQueryClient, type QueryKey } from '@tanstack/react-query';\nimport {\n doc,\n setDoc,\n updateDoc,\n deleteDoc,\n writeBatch,\n type DocumentData,\n} from 'firebase/firestore';\nimport { useFirestoreDb } from './context.js';\nimport { useSessionMutation, type SessionMutationResult } from '../session-mutation.js';\nimport type { FirestoreMutationOptions, FirestoreBatchOptions } from '../../firestore/types.js';\nimport type { MutationOperation } from './types.js';\n\nconst DEFAULT_BATCH_SIZE = 450;\n\ninterface SetResult<T> {\n id: string;\n data: T;\n}\n\nexport function useFirestoreSet<T extends DocumentData>({\n invalidateKeys = [],\n}: Pick<FirestoreMutationOptions<T>, 'invalidateKeys'> = {}): SessionMutationResult<\n SetResult<T>,\n Error,\n { docPath: string; data: T; merge?: boolean }\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useSessionMutation({\n mutationFn: async ({\n docPath,\n data,\n merge = false,\n }: {\n docPath: string;\n data: T;\n merge?: boolean;\n }) => {\n const docRef = doc(db, docPath);\n await setDoc(docRef, data, { merge });\n return { id: docRef.id, data };\n },\n onSuccess: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n },\n });\n}\n\nexport function useFirestoreUpdate<T extends DocumentData>({\n invalidateKeys = [],\n optimistic,\n}: FirestoreMutationOptions<T> = {}): SessionMutationResult<\n Partial<T>,\n Error,\n { docPath: string; data: Partial<T> },\n { previousData: T | undefined } | undefined\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useSessionMutation({\n mutationFn: async ({ docPath, data }: { docPath: string; data: Partial<T> }) => {\n const docRef = doc(db, docPath);\n await updateDoc(docRef, data as DocumentData);\n return data;\n },\n onMutate: async ({ data }) => {\n if (!optimistic) return undefined;\n\n await queryClient.cancelQueries({ queryKey: optimistic.queryKey });\n const previousData = queryClient.getQueryData<T>(optimistic.queryKey);\n\n queryClient.setQueryData<T>(optimistic.queryKey, (old) =>\n optimistic.updater(old, data as Partial<T>),\n );\n\n return { previousData };\n },\n onError: (_error, _variables, context) => {\n if (optimistic && context?.previousData !== undefined) {\n queryClient.setQueryData(optimistic.queryKey, context.previousData);\n }\n },\n onSettled: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n if (optimistic) {\n queryClient.invalidateQueries({ queryKey: optimistic.queryKey });\n }\n },\n });\n}\n\nexport function useFirestoreDelete<T = unknown>({\n invalidateKeys = [],\n optimistic,\n}: {\n invalidateKeys?: readonly QueryKey[];\n optimistic?: {\n queryKey: QueryKey;\n updater: (oldData: T | undefined, docPath: string) => T;\n };\n} = {}): SessionMutationResult<\n string,\n Error,\n { docPath: string },\n { previousData: T | undefined } | undefined\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useSessionMutation({\n mutationFn: async ({ docPath }: { docPath: string }) => {\n const docRef = doc(db, docPath);\n await deleteDoc(docRef);\n return docPath;\n },\n onMutate: async ({ docPath }) => {\n if (!optimistic) return undefined;\n\n await queryClient.cancelQueries({ queryKey: optimistic.queryKey });\n const previousData = queryClient.getQueryData<T>(optimistic.queryKey);\n\n queryClient.setQueryData<T>(optimistic.queryKey, (old) => optimistic.updater(old, docPath));\n\n return { previousData };\n },\n onError: (_error, _variables, context) => {\n if (optimistic && context?.previousData !== undefined) {\n queryClient.setQueryData(optimistic.queryKey, context.previousData);\n }\n },\n onSettled: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n if (optimistic) {\n queryClient.invalidateQueries({ queryKey: optimistic.queryKey });\n }\n },\n });\n}\n\ninterface BatchResult {\n committed: number;\n batches: number;\n}\n\nexport function useFirestoreBatch({\n invalidateKeys = [],\n batchSize = DEFAULT_BATCH_SIZE,\n}: FirestoreBatchOptions = {}): SessionMutationResult<\n BatchResult,\n Error,\n { operations: MutationOperation[] }\n> {\n const db = useFirestoreDb();\n const queryClient = useQueryClient();\n\n return useSessionMutation({\n mutationFn: async ({ operations }: { operations: MutationOperation[] }) => {\n const chunks: MutationOperation[][] = [];\n for (let i = 0; i < operations.length; i += batchSize) {\n chunks.push(operations.slice(i, i + batchSize));\n }\n\n let totalCommitted = 0;\n\n for (const chunk of chunks) {\n const batch = writeBatch(db);\n\n for (const op of chunk) {\n const docRef = doc(db, op.docPath);\n\n switch (op.type) {\n case 'set':\n if (op.merge) {\n batch.set(docRef, op.data, { merge: true });\n } else {\n batch.set(docRef, op.data);\n }\n break;\n case 'update':\n batch.update(docRef, op.data);\n break;\n case 'delete':\n batch.delete(docRef);\n break;\n }\n }\n\n await batch.commit();\n totalCommitted += chunk.length;\n }\n\n return {\n committed: totalCommitted,\n batches: chunks.length,\n };\n },\n onSuccess: () => {\n invalidateKeys.forEach((key) => {\n queryClient.invalidateQueries({ queryKey: key });\n });\n },\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBatchFirestoreDocs.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAIpD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"useBatchFirestoreDocs.d.ts","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAIpD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAIzE,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,KAAK,CAAC;AAE1D,MAAM,MAAM,yBAAyB,GAAG;IACtC,EAAE,EAAE,SAAS,CAAC;IAEd,cAAc,EAAE,MAAM,CAAC;IAEvB,GAAG,EAAE,MAAM,EAAE,CAAC;IAEd,cAAc,EAAE,MAAM,CAAC;IAEvB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,iHAAiH;IACjH,SAAS,CAAC,EAAE,2BAA2B,CAAC;IAExC,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,CAAC,IAAI;IACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAExB,SAAS,EAAE,OAAO,CAAC;IAEnB,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAEpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtD,kBAAkB,EAAE,OAAO,CAAC;IAE5B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AA2CF,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACnE,EAAE,EACF,cAAc,EACd,GAAG,EACH,cAAc,EACd,SAA0B,EAC1B,MAAuB,EACvB,OAAc,EACd,SAAiB,EACjB,SAAmB,EACnB,eAA2B,EAC3B,mBAA4C,GAC7C,EAAE,yBAAyB,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAiLzD"}
|
|
@@ -5,20 +5,31 @@ import { isListenerOwned, listenerErrorOf, subscribeDoc } from './doc-subscripti
|
|
|
5
5
|
import { getDocLoader } from './batch-doc-loader.js';
|
|
6
6
|
import { ABSENT_RETRY_DELAYS_MS, trackAbsentDoc } from './absence-scheduler.js';
|
|
7
7
|
import { useReadRetryStates } from '../use-read-retry-state.js';
|
|
8
|
+
import { isPermissionDeniedError } from './resubscribe.js';
|
|
8
9
|
const LOADING_OUTCOME = { status: 'loading' };
|
|
9
10
|
const IDLE_SOURCE = { error: null, isFetching: false, isLoading: false };
|
|
10
11
|
const ABSENT_OUTCOME = { status: 'absent' };
|
|
11
12
|
function sameOutcome(a, b) {
|
|
12
13
|
if (a.status !== b.status)
|
|
13
14
|
return false;
|
|
14
|
-
if (a.status === 'present')
|
|
15
|
-
|
|
15
|
+
if (a.status === 'present') {
|
|
16
|
+
const other = b;
|
|
17
|
+
return (a.data === other.data &&
|
|
18
|
+
a.failure?.error === other.failure?.error &&
|
|
19
|
+
a.failure?.retrying === other.failure?.retrying);
|
|
20
|
+
}
|
|
16
21
|
if (a.status === 'failed') {
|
|
17
22
|
const other = b;
|
|
18
23
|
return a.error === other.error && a.retrying === other.retrying;
|
|
19
24
|
}
|
|
20
25
|
return true;
|
|
21
26
|
}
|
|
27
|
+
function failedOrHeld(value, error, retrying) {
|
|
28
|
+
if (value === null || value === undefined || isPermissionDeniedError(error)) {
|
|
29
|
+
return { status: 'failed', error, retrying };
|
|
30
|
+
}
|
|
31
|
+
return { status: 'present', data: value, failure: { error, retrying } };
|
|
32
|
+
}
|
|
22
33
|
function shallowRecordEqual(a, b) {
|
|
23
34
|
const aKeys = Object.keys(a);
|
|
24
35
|
if (aKeys.length !== Object.keys(b).length)
|
|
@@ -134,27 +145,28 @@ export function useBatchFirestoreDocs({ db, collectionPath, ids, queryKeyPrefix,
|
|
|
134
145
|
const retryState = retryStates[index];
|
|
135
146
|
if (result?.isError)
|
|
136
147
|
anyError ??= result.error;
|
|
148
|
+
const value = result?.data;
|
|
137
149
|
if (retryState && retryState.error !== null) {
|
|
138
|
-
outcome =
|
|
150
|
+
outcome = failedOrHeld(value, retryState.error, retryState.isRetrying);
|
|
139
151
|
}
|
|
140
152
|
else if (result) {
|
|
141
153
|
if (result.isLoading)
|
|
142
154
|
oneShotLoading = true;
|
|
143
|
-
const value = result.data;
|
|
144
155
|
if (value === undefined)
|
|
145
156
|
anyUnresolved = true;
|
|
146
157
|
if (listenerError) {
|
|
147
158
|
anyListenerError ??= listenerError;
|
|
148
|
-
outcome =
|
|
159
|
+
outcome = failedOrHeld(value, listenerError, false);
|
|
149
160
|
}
|
|
150
161
|
else if (value === null) {
|
|
151
162
|
outcome = ABSENT_OUTCOME;
|
|
152
163
|
}
|
|
153
164
|
else if (value !== undefined) {
|
|
154
|
-
nextData[id] = value;
|
|
155
165
|
outcome = { status: 'present', data: value };
|
|
156
166
|
}
|
|
157
167
|
}
|
|
168
|
+
if (outcome.status === 'present')
|
|
169
|
+
nextData[id] = outcome.data;
|
|
158
170
|
const committed = committedOutcomesRef.current[id];
|
|
159
171
|
nextOutcomes[id] = committed && sameOutcome(committed, outcome) ? committed : outcome;
|
|
160
172
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBatchFirestoreDocs.js","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useQueries, useQueryClient } from '@tanstack/react-query';\nimport type { Firestore } from 'firebase/firestore';\nimport { isListenerOwned, listenerErrorOf, subscribeDoc } from './doc-subscription-registry.js';\nimport { getDocLoader } from './batch-doc-loader.js';\nimport { ABSENT_RETRY_DELAYS_MS, trackAbsentDoc } from './absence-scheduler.js';\nimport type { BatchFirestoreDocOutcome } from '../../firestore/types.js';\nimport { useReadRetryStates, type ReadRetrySource } from '../use-read-retry-state.js';\n\nexport type BatchFirestoreDocsTransport = 'batch' | 'get';\n\nexport type BatchFirestoreDocsOptions = {\n db: Firestore;\n\n collectionPath: string;\n\n ids: string[];\n\n queryKeyPrefix: string;\n\n staleTime?: number;\n\n gcTime?: number;\n\n enabled?: boolean;\n\n subscribe?: boolean;\n\n /** `'get'` is required where rules gate reads on `resource.data`: there an id-list query is denied wholesale. */\n transport?: BatchFirestoreDocsTransport;\n\n absentStaleTime?: number;\n\n absentRetryDelaysMs?: readonly number[];\n};\n\nexport type BatchFirestoreDocsResult<T> = {\n data: Record<string, T>;\n\n isLoading: boolean;\n\n isError: boolean;\n\n error: Error | null;\n\n outcomes: Record<string, BatchFirestoreDocOutcome<T>>;\n\n failedReadsRunning: boolean;\n\n refetch: () => Promise<void>;\n};\n\nconst LOADING_OUTCOME = { status: 'loading' } as const;\nconst IDLE_SOURCE: ReadRetrySource<Error> = { error: null, isFetching: false, isLoading: false };\nconst ABSENT_OUTCOME = { status: 'absent' } as const;\n\nfunction sameOutcome<T>(a: BatchFirestoreDocOutcome<T>, b: BatchFirestoreDocOutcome<T>): boolean {\n if (a.status !== b.status) return false;\n if (a.status === 'present') return a.data === (b as { data: T }).data;\n if (a.status === 'failed') {\n const other = b as { error: Error; retrying: boolean };\n return a.error === other.error && a.retrying === other.retrying;\n }\n return true;\n}\n\nfunction shallowRecordEqual<T>(a: Record<string, T>, b: Record<string, T>): boolean {\n const aKeys = Object.keys(a);\n if (aKeys.length !== Object.keys(b).length) return false;\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(b, key) || a[key] !== b[key]) return false;\n }\n return true;\n}\n\nexport function useBatchFirestoreDocs<T extends Record<string, any>>({\n db,\n collectionPath,\n ids,\n queryKeyPrefix,\n staleTime = 30 * 60 * 1000,\n gcTime = 60 * 60 * 1000,\n enabled = true,\n subscribe = false,\n transport = 'batch',\n absentStaleTime = 30 * 1000,\n absentRetryDelaysMs = ABSENT_RETRY_DELAYS_MS,\n}: BatchFirestoreDocsOptions): BatchFirestoreDocsResult<T> {\n const queryClient = useQueryClient();\n\n const idsKey = JSON.stringify(ids);\n\n const uniqueIds = useMemo(() => {\n const parsed: string[] = JSON.parse(idsKey);\n return Array.from(new Set(parsed.filter(Boolean)));\n }, [idsKey]);\n\n const [subscribeErrors, setSubscribeErrors] = useState<Record<string, Error>>({});\n // Query observers notify on React Query's batched microtask; bumping state here shows a snapshot in the tick it lands.\n const [, setSnapshotVersion] = useState(0);\n\n const results = useQueries({\n queries: uniqueIds.map((id) => ({\n queryKey: [queryKeyPrefix, id],\n queryFn: async ({ signal }: { signal: AbortSignal }): Promise<T | null> => {\n const loader = getDocLoader(queryClient, db, collectionPath);\n const loaded =\n transport === 'get'\n ? await loader.loadOne(id, signal)\n : await loader.loadBatched(id, signal);\n // `onSnapshot` does not re-emit until the document changes, so a read that lands after a listener took the key yields to it.\n if (isListenerOwned(queryClient, queryKeyPrefix, id)) {\n const listenerError = listenerErrorOf(queryClient, queryKeyPrefix, id);\n if (listenerError) throw listenerError;\n const owned = queryClient.getQueryData([queryKeyPrefix, id]);\n if (owned !== undefined) return owned as T | null;\n }\n return loaded as T | null;\n },\n enabled: enabled && !subscribe,\n // Opts back into refetch-on-mount (the package default is off) so a remount re-reads a stale id.\n refetchOnMount: !subscribe,\n staleTime: subscribe\n ? Infinity\n : (query: { state: { data: unknown } }) =>\n query.state.data === null ? absentStaleTime : staleTime,\n gcTime,\n })),\n });\n\n useEffect(() => {\n if (!subscribe || !enabled || uniqueIds.length === 0) return;\n setSubscribeErrors({});\n const unsubscribers = uniqueIds.map((id) =>\n subscribeDoc({\n queryClient,\n db,\n collectionPath,\n queryKeyPrefix,\n id,\n onUpdate: () => {\n setSubscribeErrors((errors) => {\n if (!(id in errors)) return errors;\n const { [id]: _cleared, ...rest } = errors;\n return rest;\n });\n setSnapshotVersion((version) => version + 1);\n },\n onError: (error) =>\n setSubscribeErrors((errors) =>\n errors[id] === error ? errors : { ...errors, [id]: error },\n ),\n }),\n );\n return () => {\n for (const unsubscribe of unsubscribers) unsubscribe();\n };\n }, [uniqueIds, subscribe, enabled, collectionPath, queryKeyPrefix, queryClient, db]);\n\n const absentDelaysKey = absentRetryDelaysMs.join(',');\n const absentDelays = useMemo(\n () => absentDelaysKey.split(',').filter(Boolean).map(Number),\n [absentDelaysKey],\n );\n\n useEffect(() => {\n if (uniqueIds.length === 0) return;\n const releases = uniqueIds.map((id) =>\n trackAbsentDoc({ queryClient, queryKey: [queryKeyPrefix, id], delays: absentDelays }),\n );\n return () => {\n for (const release of releases) release();\n };\n }, [uniqueIds, queryKeyPrefix, queryClient, absentDelays]);\n\n // Only the effect writes these refs, so a concurrent render React discards never leaves them on an uncommitted map.\n const committedDataRef = useRef<Record<string, T>>({});\n const committedOutcomesRef = useRef<Record<string, BatchFirestoreDocOutcome<T>>>({});\n\n // TanStack clears a never-answered read's error as its refetch starts, so the failure is held through the retry.\n const retryStates = useReadRetryStates(\n uniqueIds.map((id, index) => ({\n source: (results[index] ?? IDLE_SOURCE) as ReadRetrySource<Error>,\n queryKey: [queryKeyPrefix, id],\n })),\n );\n\n const nextData: Record<string, T> = {};\n const nextOutcomes: Record<string, BatchFirestoreDocOutcome<T>> = {};\n let anyError: Error | null = null;\n let anyListenerError: Error | null = null;\n let oneShotLoading = false;\n let anyUnresolved = false;\n let failedReadsRunning = false;\n\n for (let index = 0; index < uniqueIds.length; index += 1) {\n const id = uniqueIds[index];\n const result = results[index];\n let outcome: BatchFirestoreDocOutcome<T> = LOADING_OUTCOME;\n const listenerError =\n (subscribe ? subscribeErrors[id] : undefined) ??\n listenerErrorOf(queryClient, queryKeyPrefix, id) ??\n undefined;\n if (\n result &&\n (result.isFetching || result.isPaused) &&\n result.errorUpdatedAt > result.dataUpdatedAt\n ) {\n failedReadsRunning = true;\n }\n const retryState = retryStates[index];\n if (result?.isError) anyError ??= result.error as Error;\n if (retryState && retryState.error !== null) {\n outcome = { status: 'failed', error: retryState.error, retrying: retryState.isRetrying };\n } else if (result) {\n if (result.isLoading) oneShotLoading = true;\n const value = result.data as T | null | undefined;\n if (value === undefined) anyUnresolved = true;\n if (listenerError) {\n anyListenerError ??= listenerError;\n outcome = { status: 'failed', error: listenerError, retrying: false };\n } else if (value === null) {\n outcome = ABSENT_OUTCOME;\n } else if (value !== undefined) {\n nextData[id] = value;\n outcome = { status: 'present', data: value };\n }\n }\n const committed = committedOutcomesRef.current[id];\n nextOutcomes[id] = committed && sameOutcome(committed, outcome) ? committed : outcome;\n }\n\n const data = shallowRecordEqual(committedDataRef.current, nextData)\n ? committedDataRef.current\n : nextData;\n const outcomes = shallowRecordEqual(committedOutcomesRef.current, nextOutcomes)\n ? committedOutcomesRef.current\n : nextOutcomes;\n\n useEffect(() => {\n committedDataRef.current = data;\n committedOutcomesRef.current = outcomes;\n }, [data, outcomes]);\n\n const refetch = useCallback(async () => {\n if (subscribe || !enabled) return;\n await Promise.all(\n uniqueIds.map((id) =>\n queryClient.refetchQueries({ queryKey: [queryKeyPrefix, id], exact: true }),\n ),\n );\n }, [uniqueIds, subscribe, enabled, queryClient, queryKeyPrefix]);\n\n const isLoading = subscribe ? enabled && anyUnresolved : oneShotLoading;\n\n return {\n data,\n isLoading,\n isError: anyError !== null || anyListenerError !== null,\n error: anyError ?? anyListenerError,\n outcomes,\n failedReadsRunning,\n refetch,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"useBatchFirestoreDocs.js","sourceRoot":"","sources":["../../../src/react/firestore/useBatchFirestoreDocs.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useQueries, useQueryClient } from '@tanstack/react-query';\nimport type { Firestore } from 'firebase/firestore';\nimport { isListenerOwned, listenerErrorOf, subscribeDoc } from './doc-subscription-registry.js';\nimport { getDocLoader } from './batch-doc-loader.js';\nimport { ABSENT_RETRY_DELAYS_MS, trackAbsentDoc } from './absence-scheduler.js';\nimport type { BatchFirestoreDocOutcome } from '../../firestore/types.js';\nimport { useReadRetryStates, type ReadRetrySource } from '../use-read-retry-state.js';\nimport { isPermissionDeniedError } from './resubscribe.js';\n\nexport type BatchFirestoreDocsTransport = 'batch' | 'get';\n\nexport type BatchFirestoreDocsOptions = {\n db: Firestore;\n\n collectionPath: string;\n\n ids: string[];\n\n queryKeyPrefix: string;\n\n staleTime?: number;\n\n gcTime?: number;\n\n enabled?: boolean;\n\n subscribe?: boolean;\n\n /** `'get'` is required where rules gate reads on `resource.data`: there an id-list query is denied wholesale. */\n transport?: BatchFirestoreDocsTransport;\n\n absentStaleTime?: number;\n\n absentRetryDelaysMs?: readonly number[];\n};\n\nexport type BatchFirestoreDocsResult<T> = {\n data: Record<string, T>;\n\n isLoading: boolean;\n\n isError: boolean;\n\n error: Error | null;\n\n outcomes: Record<string, BatchFirestoreDocOutcome<T>>;\n\n failedReadsRunning: boolean;\n\n refetch: () => Promise<void>;\n};\n\nconst LOADING_OUTCOME = { status: 'loading' } as const;\nconst IDLE_SOURCE: ReadRetrySource<Error> = { error: null, isFetching: false, isLoading: false };\nconst ABSENT_OUTCOME = { status: 'absent' } as const;\n\nfunction sameOutcome<T>(a: BatchFirestoreDocOutcome<T>, b: BatchFirestoreDocOutcome<T>): boolean {\n if (a.status !== b.status) return false;\n if (a.status === 'present') {\n const other = b as { data: T; failure?: { error: Error; retrying: boolean } };\n return (\n a.data === other.data &&\n a.failure?.error === other.failure?.error &&\n a.failure?.retrying === other.failure?.retrying\n );\n }\n if (a.status === 'failed') {\n const other = b as { error: Error; retrying: boolean };\n return a.error === other.error && a.retrying === other.retrying;\n }\n return true;\n}\n\nfunction failedOrHeld<T>(\n value: T | null | undefined,\n error: Error,\n retrying: boolean,\n): BatchFirestoreDocOutcome<T> {\n if (value === null || value === undefined || isPermissionDeniedError(error)) {\n return { status: 'failed', error, retrying };\n }\n return { status: 'present', data: value, failure: { error, retrying } };\n}\n\nfunction shallowRecordEqual<T>(a: Record<string, T>, b: Record<string, T>): boolean {\n const aKeys = Object.keys(a);\n if (aKeys.length !== Object.keys(b).length) return false;\n for (const key of aKeys) {\n if (!Object.prototype.hasOwnProperty.call(b, key) || a[key] !== b[key]) return false;\n }\n return true;\n}\n\nexport function useBatchFirestoreDocs<T extends Record<string, any>>({\n db,\n collectionPath,\n ids,\n queryKeyPrefix,\n staleTime = 30 * 60 * 1000,\n gcTime = 60 * 60 * 1000,\n enabled = true,\n subscribe = false,\n transport = 'batch',\n absentStaleTime = 30 * 1000,\n absentRetryDelaysMs = ABSENT_RETRY_DELAYS_MS,\n}: BatchFirestoreDocsOptions): BatchFirestoreDocsResult<T> {\n const queryClient = useQueryClient();\n\n const idsKey = JSON.stringify(ids);\n\n const uniqueIds = useMemo(() => {\n const parsed: string[] = JSON.parse(idsKey);\n return Array.from(new Set(parsed.filter(Boolean)));\n }, [idsKey]);\n\n const [subscribeErrors, setSubscribeErrors] = useState<Record<string, Error>>({});\n // Query observers notify on React Query's batched microtask; bumping state here shows a snapshot in the tick it lands.\n const [, setSnapshotVersion] = useState(0);\n\n const results = useQueries({\n queries: uniqueIds.map((id) => ({\n queryKey: [queryKeyPrefix, id],\n queryFn: async ({ signal }: { signal: AbortSignal }): Promise<T | null> => {\n const loader = getDocLoader(queryClient, db, collectionPath);\n const loaded =\n transport === 'get'\n ? await loader.loadOne(id, signal)\n : await loader.loadBatched(id, signal);\n // `onSnapshot` does not re-emit until the document changes, so a read that lands after a listener took the key yields to it.\n if (isListenerOwned(queryClient, queryKeyPrefix, id)) {\n const listenerError = listenerErrorOf(queryClient, queryKeyPrefix, id);\n if (listenerError) throw listenerError;\n const owned = queryClient.getQueryData([queryKeyPrefix, id]);\n if (owned !== undefined) return owned as T | null;\n }\n return loaded as T | null;\n },\n enabled: enabled && !subscribe,\n // Opts back into refetch-on-mount (the package default is off) so a remount re-reads a stale id.\n refetchOnMount: !subscribe,\n staleTime: subscribe\n ? Infinity\n : (query: { state: { data: unknown } }) =>\n query.state.data === null ? absentStaleTime : staleTime,\n gcTime,\n })),\n });\n\n useEffect(() => {\n if (!subscribe || !enabled || uniqueIds.length === 0) return;\n setSubscribeErrors({});\n const unsubscribers = uniqueIds.map((id) =>\n subscribeDoc({\n queryClient,\n db,\n collectionPath,\n queryKeyPrefix,\n id,\n onUpdate: () => {\n setSubscribeErrors((errors) => {\n if (!(id in errors)) return errors;\n const { [id]: _cleared, ...rest } = errors;\n return rest;\n });\n setSnapshotVersion((version) => version + 1);\n },\n onError: (error) =>\n setSubscribeErrors((errors) =>\n errors[id] === error ? errors : { ...errors, [id]: error },\n ),\n }),\n );\n return () => {\n for (const unsubscribe of unsubscribers) unsubscribe();\n };\n }, [uniqueIds, subscribe, enabled, collectionPath, queryKeyPrefix, queryClient, db]);\n\n const absentDelaysKey = absentRetryDelaysMs.join(',');\n const absentDelays = useMemo(\n () => absentDelaysKey.split(',').filter(Boolean).map(Number),\n [absentDelaysKey],\n );\n\n useEffect(() => {\n if (uniqueIds.length === 0) return;\n const releases = uniqueIds.map((id) =>\n trackAbsentDoc({ queryClient, queryKey: [queryKeyPrefix, id], delays: absentDelays }),\n );\n return () => {\n for (const release of releases) release();\n };\n }, [uniqueIds, queryKeyPrefix, queryClient, absentDelays]);\n\n // Only the effect writes these refs, so a concurrent render React discards never leaves them on an uncommitted map.\n const committedDataRef = useRef<Record<string, T>>({});\n const committedOutcomesRef = useRef<Record<string, BatchFirestoreDocOutcome<T>>>({});\n\n // TanStack clears a never-answered read's error as its refetch starts, so the failure is held through the retry.\n const retryStates = useReadRetryStates(\n uniqueIds.map((id, index) => ({\n source: (results[index] ?? IDLE_SOURCE) as ReadRetrySource<Error>,\n queryKey: [queryKeyPrefix, id],\n })),\n );\n\n const nextData: Record<string, T> = {};\n const nextOutcomes: Record<string, BatchFirestoreDocOutcome<T>> = {};\n let anyError: Error | null = null;\n let anyListenerError: Error | null = null;\n let oneShotLoading = false;\n let anyUnresolved = false;\n let failedReadsRunning = false;\n\n for (let index = 0; index < uniqueIds.length; index += 1) {\n const id = uniqueIds[index];\n const result = results[index];\n let outcome: BatchFirestoreDocOutcome<T> = LOADING_OUTCOME;\n const listenerError =\n (subscribe ? subscribeErrors[id] : undefined) ??\n listenerErrorOf(queryClient, queryKeyPrefix, id) ??\n undefined;\n if (\n result &&\n (result.isFetching || result.isPaused) &&\n result.errorUpdatedAt > result.dataUpdatedAt\n ) {\n failedReadsRunning = true;\n }\n const retryState = retryStates[index];\n if (result?.isError) anyError ??= result.error as Error;\n const value = result?.data as T | null | undefined;\n if (retryState && retryState.error !== null) {\n outcome = failedOrHeld(value, retryState.error, retryState.isRetrying);\n } else if (result) {\n if (result.isLoading) oneShotLoading = true;\n if (value === undefined) anyUnresolved = true;\n if (listenerError) {\n anyListenerError ??= listenerError;\n outcome = failedOrHeld(value, listenerError, false);\n } else if (value === null) {\n outcome = ABSENT_OUTCOME;\n } else if (value !== undefined) {\n outcome = { status: 'present', data: value };\n }\n }\n if (outcome.status === 'present') nextData[id] = outcome.data;\n const committed = committedOutcomesRef.current[id];\n nextOutcomes[id] = committed && sameOutcome(committed, outcome) ? committed : outcome;\n }\n\n const data = shallowRecordEqual(committedDataRef.current, nextData)\n ? committedDataRef.current\n : nextData;\n const outcomes = shallowRecordEqual(committedOutcomesRef.current, nextOutcomes)\n ? committedOutcomesRef.current\n : nextOutcomes;\n\n useEffect(() => {\n committedDataRef.current = data;\n committedOutcomesRef.current = outcomes;\n }, [data, outcomes]);\n\n const refetch = useCallback(async () => {\n if (subscribe || !enabled) return;\n await Promise.all(\n uniqueIds.map((id) =>\n queryClient.refetchQueries({ queryKey: [queryKeyPrefix, id], exact: true }),\n ),\n );\n }, [uniqueIds, subscribe, enabled, queryClient, queryKeyPrefix]);\n\n const isLoading = subscribe ? enabled && anyUnresolved : oneShotLoading;\n\n return {\n data,\n isLoading,\n isError: anyError !== null || anyListenerError !== null,\n error: anyError ?? anyListenerError,\n outcomes,\n failedReadsRunning,\n refetch,\n };\n}\n"]}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -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, SessionMutateOptions, SessionMutationFunctionContext, SessionMutationOptions, SessionMutationResult, } 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":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC3E,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,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;AAE9F,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAEhD,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;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;AAC5B,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,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;AAE/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;AAEhE,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAClF,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEjG,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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"}
|
package/dist/react/index.js
CHANGED
|
@@ -18,5 +18,7 @@ export { exact, prefix, predicate, serializeInvalidation, applyInvalidations, }
|
|
|
18
18
|
export { docWithId } from './firestore/types.js';
|
|
19
19
|
export { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';
|
|
20
20
|
export { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';
|
|
21
|
+
export { MutationSessionProvider, MutationSessionEndedError, useSessionMutation, } from './session-mutation.js';
|
|
22
|
+
export { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';
|
|
21
23
|
export { usePendingMutationVariables, pendingMutationVariables, usePendingMutationTargets, hasPendingMutation, duplicateSubmissionError, useDuplicateGuardedMutation, } from './pending-mutations.js';
|
|
22
24
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAE/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAGtF,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAM7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,2BAA2B,EAC3B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,oDAAoD,CAAC;AAClG,OAAO,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,uCAAuC,CAAC;AAW/C,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAYjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5F,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAGlF,OAAO,EACL,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 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;AAU/B,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAWvF,OAAO,EACL,2BAA2B,EAC3B,wBAAwB,EACxB,yBAAyB,EACzB,kBAAkB,EAClB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC","sourcesContent":["'use client';\n\nexport { createQueryClient } from './query-client.js';\nexport type { CreateQueryClientOptions } from './query-client.js';\n\nexport { QueryProvider } from './provider.js';\nexport type { QueryProviderProps } from './provider.js';\n\nexport { FirestoreProvider, useFirestoreDb } from './firestore/context.js';\nexport type { FirestoreProviderProps } from './firestore/context.js';\n\nexport { useFirestoreDoc } from './firestore/use-firestore-doc.js';\nexport { useFirestoreCollection } from './firestore/use-firestore-collection.js';\nexport { useFirestoreInfinite } from './firestore/use-firestore-infinite.js';\nexport { useFirestorePaginated } from './firestore/use-firestore-paginated.js';\nexport type { UseFirestorePaginatedResult } from './firestore/use-firestore-paginated.js';\nexport { useFirestoreCount } from './firestore/use-firestore-count.js';\nexport { useFirestoreLiveInfinite } from './firestore/use-firestore-live-infinite.js';\nexport type { FirestoreLiveInfiniteResult } from './firestore/use-firestore-live-infinite.js';\n\nexport {\n useFirestoreSet,\n useFirestoreUpdate,\n useFirestoreDelete,\n useFirestoreBatch,\n} from './firestore/use-firestore-mutations.js';\n\nexport { useBatchFirestoreDocs } from './firestore/useBatchFirestoreDocs.js';\nexport type {\n BatchFirestoreDocsOptions,\n BatchFirestoreDocsResult,\n BatchFirestoreDocsTransport,\n} from './firestore/useBatchFirestoreDocs.js';\nexport { ABSENT_RETRY_DELAYS_MS } from './firestore/absence-scheduler.js';\n\nexport { useFirestoreSearch } from './search/use-firestore-search.js';\n\nexport {\n invalidateByPrefix,\n removeByPrefix,\n updateQueryData,\n paginatedPageKey,\n mapPaginatedItems,\n prependToFirstPaginatedPage,\n placeRowInPages,\n} from './cache-helpers.js';\nexport type { PagedRows } from './cache-helpers.js';\n\nexport { createDomainEventInvalidator } from './domain-events/create-domain-event-invalidator.js';\nexport {\n exact,\n prefix,\n predicate,\n serializeInvalidation,\n applyInvalidations,\n} from './domain-events/cache-invalidation.js';\nexport type {\n DomainEventInvalidator,\n DomainEventInvalidationRegistry,\n} from './domain-events/create-domain-event-invalidator.js';\nexport type {\n CacheAction,\n CacheInvalidation,\n RefetchType,\n} from './domain-events/cache-invalidation.js';\n\nexport { docWithId } from './firestore/types.js';\nexport type {\n FirestoreDocOptions,\n FirestoreCollectionOptions,\n FirestoreInfiniteOptions,\n FirestorePaginatedOptions,\n FirestoreCountOptions,\n FirestoreLiveInfiniteOptions,\n InfinitePage,\n PaginatedPage,\n MutationOperation,\n} from './firestore/types.js';\nexport { flattenInfiniteData, getInfiniteDataCount } from './firestore/infinite-helpers.js';\nexport type { FirestoreSearchOptions } from './search/types.js';\n\nexport { useReadRetryState, useReadRetryStates } from './use-read-retry-state.js';\nexport type { ReadRetryEntry, ReadRetrySource, ReadRetryState } from './use-read-retry-state.js';\n\nexport {\n MutationSessionProvider,\n MutationSessionEndedError,\n useSessionMutation,\n} from './session-mutation.js';\nexport type {\n MutationSession,\n MutationSessionProviderProps,\n SessionMutateOptions,\n SessionMutationFunctionContext,\n SessionMutationOptions,\n SessionMutationResult,\n} from './session-mutation.js';\n\nexport { createCallables, MAX_RESUMABLE_CALLS } from './callables/create-callables.js';\nexport type {\n CallableCaptureContext,\n CallableDeclaration,\n CallableErrorRouting,\n CallableMutationOptions,\n CallablePolicy,\n Callables,\n ResumableOutcome,\n} from './callables/create-callables.js';\n\nexport {\n usePendingMutationVariables,\n pendingMutationVariables,\n usePendingMutationTargets,\n hasPendingMutation,\n duplicateSubmissionError,\n useDuplicateGuardedMutation,\n} from './pending-mutations.js';\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
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' | 'onMutate' | 'onSuccess' | 'onError' | 'onSettled'> & {
|
|
12
|
+
mutationFn: (variables: TVariables, context: SessionMutationFunctionContext) => Promise<TData>;
|
|
13
|
+
onMutate?: (variables: TVariables, context: SessionMutationFunctionContext) => Promise<TOnMutateResult> | TOnMutateResult;
|
|
14
|
+
onSuccess?: (data: TData, variables: TVariables, onMutateResult: TOnMutateResult, context: SessionMutationFunctionContext) => Promise<unknown> | unknown;
|
|
15
|
+
onError?: (error: TError, variables: TVariables, onMutateResult: TOnMutateResult | undefined, context: SessionMutationFunctionContext) => Promise<unknown> | unknown;
|
|
16
|
+
onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, onMutateResult: TOnMutateResult | undefined, context: SessionMutationFunctionContext) => Promise<unknown> | unknown;
|
|
17
|
+
};
|
|
18
|
+
export interface SessionMutateOptions<TData, TError, TVariables, TOnMutateResult> {
|
|
19
|
+
onSuccess?: (data: TData, variables: TVariables, onMutateResult: TOnMutateResult | undefined, context: SessionMutationFunctionContext) => void;
|
|
20
|
+
onError?: (error: TError, variables: TVariables, onMutateResult: TOnMutateResult | undefined, context: SessionMutationFunctionContext) => void;
|
|
21
|
+
onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, onMutateResult: TOnMutateResult | undefined, context: SessionMutationFunctionContext) => void;
|
|
22
|
+
}
|
|
23
|
+
type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
|
24
|
+
export type SessionMutationResult<TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown> = DistributiveOmit<UseMutationResult<TData, TError, TVariables, TOnMutateResult>, 'mutate' | 'mutateAsync'> & {
|
|
25
|
+
mutate: (variables: TVariables, options?: SessionMutateOptions<TData, TError, TVariables, TOnMutateResult>) => void;
|
|
26
|
+
mutateAsync: (variables: TVariables, options?: SessionMutateOptions<TData, TError, TVariables, TOnMutateResult>) => Promise<TData>;
|
|
27
|
+
};
|
|
28
|
+
export declare class MutationSessionEndedError extends Error {
|
|
29
|
+
name: string;
|
|
30
|
+
constructor(options?: {
|
|
31
|
+
cause?: unknown;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export interface MutationSessionProviderProps {
|
|
35
|
+
currentUid: string | null;
|
|
36
|
+
children?: ReactNode;
|
|
37
|
+
}
|
|
38
|
+
export declare function MutationSessionProvider({ currentUid, children }: MutationSessionProviderProps): import("react").JSX.Element;
|
|
39
|
+
export declare function useMutationSessionCapture(): () => MutationSession;
|
|
40
|
+
export declare function useSessionMutation<TData = unknown, TError = DefaultError, TVariables = void, TOnMutateResult = unknown>(options: SessionMutationOptions<TData, TError, TVariables, TOnMutateResult>): SessionMutationResult<TData, TError, TVariables, TOnMutateResult>;
|
|
41
|
+
export {};
|
|
42
|
+
//# 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":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, useCallback, useContext, useInsertionEffect, useState, } from 'react';
|
|
4
|
+
import { useMutation, useQueryClient, } from '@tanstack/react-query';
|
|
5
|
+
export class MutationSessionEndedError extends Error {
|
|
6
|
+
name = 'AbortError';
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super('The session that started this mutation has ended.', options);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const MutationSessionContext = createContext(null);
|
|
12
|
+
export function MutationSessionProvider({ currentUid, children }) {
|
|
13
|
+
const [store] = useState(() => ({
|
|
14
|
+
current: { uid: currentUid, generation: 0 },
|
|
15
|
+
}));
|
|
16
|
+
// Insertion effects run before any layout effect of the commit, so a child's layout effect
|
|
17
|
+
// never starts a mutation under the uid this commit ends.
|
|
18
|
+
useInsertionEffect(() => {
|
|
19
|
+
if (store.current.uid !== currentUid) {
|
|
20
|
+
store.current = { uid: currentUid, generation: store.current.generation + 1 };
|
|
21
|
+
}
|
|
22
|
+
}, [store, currentUid]);
|
|
23
|
+
return (_jsx(MutationSessionContext.Provider, { value: store, children: children }));
|
|
24
|
+
}
|
|
25
|
+
const ALWAYS_CURRENT = {
|
|
26
|
+
uid: null,
|
|
27
|
+
isCurrent: () => true,
|
|
28
|
+
assertCurrent: () => { },
|
|
29
|
+
};
|
|
30
|
+
function captureSession(store) {
|
|
31
|
+
if (!store)
|
|
32
|
+
return ALWAYS_CURRENT;
|
|
33
|
+
const { uid, generation } = store.current;
|
|
34
|
+
const isCurrent = () => store.current.generation === generation;
|
|
35
|
+
return {
|
|
36
|
+
uid,
|
|
37
|
+
isCurrent,
|
|
38
|
+
assertCurrent: () => {
|
|
39
|
+
if (!isCurrent())
|
|
40
|
+
throw new MutationSessionEndedError();
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function useMutationSessionCapture() {
|
|
45
|
+
const store = useContext(MutationSessionContext);
|
|
46
|
+
return useCallback(() => captureSession(store), [store]);
|
|
47
|
+
}
|
|
48
|
+
const runSessions = new WeakMap();
|
|
49
|
+
function runHasEnded(store, context) {
|
|
50
|
+
if (!store)
|
|
51
|
+
return false;
|
|
52
|
+
return !(runSessions.get(context)?.isCurrent() ?? false);
|
|
53
|
+
}
|
|
54
|
+
function retriesAfter(retry, failureCount, error) {
|
|
55
|
+
if (error instanceof MutationSessionEndedError)
|
|
56
|
+
return false;
|
|
57
|
+
if (typeof retry === 'function')
|
|
58
|
+
return retry(failureCount, error);
|
|
59
|
+
if (typeof retry === 'number')
|
|
60
|
+
return failureCount < retry;
|
|
61
|
+
return retry === true;
|
|
62
|
+
}
|
|
63
|
+
function throwsToBoundary(throwOnError, error) {
|
|
64
|
+
if (error instanceof MutationSessionEndedError)
|
|
65
|
+
return false;
|
|
66
|
+
if (typeof throwOnError === 'function')
|
|
67
|
+
return throwOnError(error);
|
|
68
|
+
return throwOnError === true;
|
|
69
|
+
}
|
|
70
|
+
function withSession(context, session) {
|
|
71
|
+
return { ...context, session };
|
|
72
|
+
}
|
|
73
|
+
function fenceCallOptions(session, options) {
|
|
74
|
+
if (!options)
|
|
75
|
+
return undefined;
|
|
76
|
+
const { onSuccess, onError, onSettled } = options;
|
|
77
|
+
return {
|
|
78
|
+
onSuccess: onSuccess
|
|
79
|
+
? (data, variables, onMutateResult, context) => {
|
|
80
|
+
if (session.isCurrent()) {
|
|
81
|
+
onSuccess(data, variables, onMutateResult, withSession(context, session));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
: undefined,
|
|
85
|
+
onError: onError
|
|
86
|
+
? (error, variables, onMutateResult, context) => {
|
|
87
|
+
if (!(error instanceof MutationSessionEndedError) && session.isCurrent()) {
|
|
88
|
+
onError(error, variables, onMutateResult, withSession(context, session));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
: undefined,
|
|
92
|
+
onSettled: onSettled
|
|
93
|
+
? (data, error, variables, onMutateResult, context) => {
|
|
94
|
+
if (!(error instanceof MutationSessionEndedError) && session.isCurrent()) {
|
|
95
|
+
onSettled(data, error, variables, onMutateResult, withSession(context, session));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
: undefined,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async function settleInSession(session, settled) {
|
|
102
|
+
let data;
|
|
103
|
+
try {
|
|
104
|
+
data = await settled;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (!(error instanceof MutationSessionEndedError) && !session.isCurrent()) {
|
|
108
|
+
throw new MutationSessionEndedError({ cause: error });
|
|
109
|
+
}
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
session.assertCurrent();
|
|
113
|
+
return data;
|
|
114
|
+
}
|
|
115
|
+
export function useSessionMutation(options) {
|
|
116
|
+
const store = useContext(MutationSessionContext);
|
|
117
|
+
const queryClient = useQueryClient();
|
|
118
|
+
const { mutationFn, onMutate, onSuccess, onError, onSettled, retry, throwOnError, ...rest } = options;
|
|
119
|
+
const defaults = queryClient.defaultMutationOptions({ mutationKey: options.mutationKey });
|
|
120
|
+
const baseRetry = (retry ?? defaults.retry);
|
|
121
|
+
const baseThrowOnError = (throwOnError ?? defaults.throwOnError);
|
|
122
|
+
const mutation = useMutation({
|
|
123
|
+
...rest,
|
|
124
|
+
retry: (failureCount, error) => retriesAfter(baseRetry, failureCount, error),
|
|
125
|
+
throwOnError: (error) => throwsToBoundary(baseThrowOnError, error),
|
|
126
|
+
onMutate: (variables, context) => {
|
|
127
|
+
const session = store ? captureSession(store) : ALWAYS_CURRENT;
|
|
128
|
+
if (store)
|
|
129
|
+
runSessions.set(context, session);
|
|
130
|
+
return onMutate?.(variables, withSession(context, session));
|
|
131
|
+
},
|
|
132
|
+
mutationFn: async (variables, context) => {
|
|
133
|
+
const session = store ? runSessions.get(context) : ALWAYS_CURRENT;
|
|
134
|
+
if (!session || !session.isCurrent())
|
|
135
|
+
throw new MutationSessionEndedError();
|
|
136
|
+
let data;
|
|
137
|
+
try {
|
|
138
|
+
data = await mutationFn(variables, { ...context, session });
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (!session.isCurrent())
|
|
142
|
+
throw new MutationSessionEndedError({ cause: error });
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
session.assertCurrent();
|
|
146
|
+
return data;
|
|
147
|
+
},
|
|
148
|
+
onSuccess: (data, variables, onMutateResult, context) => {
|
|
149
|
+
if (runHasEnded(store, context))
|
|
150
|
+
return;
|
|
151
|
+
return onSuccess?.(data, variables, onMutateResult, withSession(context, runSession(context)));
|
|
152
|
+
},
|
|
153
|
+
onError: (error, variables, onMutateResult, context) => {
|
|
154
|
+
if (error instanceof MutationSessionEndedError || runHasEnded(store, context))
|
|
155
|
+
return;
|
|
156
|
+
return onError?.(error, variables, onMutateResult, withSession(context, runSession(context)));
|
|
157
|
+
},
|
|
158
|
+
onSettled: (data, error, variables, onMutateResult, context) => {
|
|
159
|
+
if (error instanceof MutationSessionEndedError || runHasEnded(store, context))
|
|
160
|
+
return;
|
|
161
|
+
return onSettled?.(data, error, variables, onMutateResult, withSession(context, runSession(context)));
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
function runSession(context) {
|
|
165
|
+
return (store && runSessions.get(context)) || ALWAYS_CURRENT;
|
|
166
|
+
}
|
|
167
|
+
const { mutate: rawMutate, mutateAsync: rawMutateAsync } = mutation;
|
|
168
|
+
const mutate = useCallback((variables, callOptions) => rawMutate(variables, fenceCallOptions(captureSession(store), callOptions)), [rawMutate, store]);
|
|
169
|
+
const mutateAsync = useCallback((variables, callOptions) => {
|
|
170
|
+
const session = captureSession(store);
|
|
171
|
+
return settleInSession(session, rawMutateAsync(variables, fenceCallOptions(session, callOptions)));
|
|
172
|
+
}, [rawMutateAsync, store]);
|
|
173
|
+
return { ...mutation, mutate, mutateAsync };
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=session-mutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-mutation.js","sourceRoot":"","sources":["../../src/react/session-mutation.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EACL,aAAa,EACb,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,QAAQ,GAET,MAAM,OAAO,CAAC;AACf,OAAO,EACL,WAAW,EACX,cAAc,GAMf,MAAM,uBAAuB,CAAC;AA0F/B,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IACzC,IAAI,GAAG,YAAY,CAAC;IAE7B,YAAY,OAA6B;QACvC,KAAK,CAAC,mDAAmD,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;CACF;AAMD,MAAM,sBAAsB,GAAG,aAAa,CAAsB,IAAI,CAAC,CAAC;AAOxE,MAAM,UAAU,uBAAuB,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAgC;IAC5F,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAe,GAAG,EAAE,CAAC,CAAC;QAC5C,OAAO,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,EAAE;KAC5C,CAAC,CAAC,CAAC;IACJ,2FAA2F;IAC3F,0DAA0D;IAC1D,kBAAkB,CAAC,GAAG,EAAE;QACtB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;YACrC,KAAK,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAChF,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;IACxB,OAAO,CACL,KAAC,sBAAsB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAmC,CAC5F,CAAC;AACJ,CAAC;AAED,MAAM,cAAc,GAAoB;IACtC,GAAG,EAAE,IAAI;IACT,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;IACrB,aAAa,EAAE,GAAG,EAAE,GAAE,CAAC;CACxB,CAAC;AAEF,SAAS,cAAc,CAAC,KAA0B;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,cAAc,CAAC;IAClC,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC;IAC1C,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,KAAK,UAAU,CAAC;IAChE,OAAO;QACL,GAAG;QACH,SAAS;QACT,aAAa,EAAE,GAAG,EAAE;YAClB,IAAI,CAAC,SAAS,EAAE;gBAAE,MAAM,IAAI,yBAAyB,EAAE,CAAC;QAC1D,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,MAAM,KAAK,GAAG,UAAU,CAAC,sBAAsB,CAAC,CAAC;IACjD,OAAO,WAAW,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,OAAO,EAA4C,CAAC;AAE5E,SAAS,WAAW,CAAC,KAA0B,EAAE,OAAgC;IAC/E,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,KAAK,CAAC,CAAC;AAC3D,CAAC;AAKD,SAAS,YAAY,CAAS,KAAoB,EAAE,YAAoB,EAAE,KAAa;IACrF,IAAI,KAAK,YAAY,yBAAyB;QAAE,OAAO,KAAK,CAAC;IAC7D,IAAI,OAAO,KAAK,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACnE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,YAAY,GAAG,KAAK,CAAC;IAC3D,OAAO,KAAK,KAAK,IAAI,CAAC;AACxB,CAAC;AAED,SAAS,gBAAgB,CAAS,YAAkC,EAAE,KAAa;IACjF,IAAI,KAAK,YAAY,yBAAyB;QAAE,OAAO,KAAK,CAAC;IAC7D,IAAI,OAAO,YAAY,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IACnE,OAAO,YAAY,KAAK,IAAI,CAAC;AAC/B,CAAC;AAED,SAAS,WAAW,CAClB,OAAgC,EAChC,OAAwB;IAExB,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,gBAAgB,CACvB,OAAwB,EACxB,OAAqF;IAErF,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAClD,OAAO;QACL,SAAS,EAAE,SAAS;YAClB,CAAC,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;gBAC3C,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;oBACxB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;YACH,CAAC,CAAC,SAAS;QACb,OAAO,EAAE,OAAO;YACd,CAAC,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;gBAC5C,IAAI,CAAC,CAAC,KAAK,YAAY,yBAAyB,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;oBACzE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC3E,CAAC;YACH,CAAC;YACH,CAAC,CAAC,SAAS;QACb,SAAS,EAAE,SAAS;YAClB,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;gBAClD,IAAI,CAAC,CAAC,KAAK,YAAY,yBAAyB,CAAC,IAAI,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;oBACzE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBACnF,CAAC;YACH,CAAC;YACH,CAAC,CAAC,SAAS;KACd,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,OAAwB,EACxB,OAAuB;IAEvB,IAAI,IAAW,CAAC;IAChB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,OAAO,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,CAAC,KAAK,YAAY,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;YAC1E,MAAM,IAAI,yBAAyB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CAAC,aAAa,EAAE,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,kBAAkB,CAMhC,OAA2E;IAE3E,MAAM,KAAK,GAAG,UAAU,CAAC,sBAAsB,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GACzF,OAAO,CAAC;IACV,MAAM,QAAQ,GAAG,WAAW,CAAC,sBAAsB,CAEjD,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAkB,CAAC;IAC7D,MAAM,gBAAgB,GAAG,CAAC,YAAY,IAAI,QAAQ,CAAC,YAAY,CAAyB,CAAC;IAEzF,MAAM,QAAQ,GAAG,WAAW,CAA6C;QACvE,GAAG,IAAI;QACP,KAAK,EAAE,CAAC,YAAY,EAAE,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,CAAC;QAC5E,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,KAAK,CAAC;QAClE,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE;YAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;YAC/D,IAAI,KAAK;gBAAE,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CACd,CAAC;QAC/C,CAAC;QACD,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;YACvC,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;YAClE,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;gBAAE,MAAM,IAAI,yBAAyB,EAAE,CAAC;YAC5E,IAAI,IAAW,CAAC;YAChB,IAAI,CAAC;gBACH,IAAI,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YAC9D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE;oBAAE,MAAM,IAAI,yBAAyB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;gBAChF,MAAM,KAAK,CAAC;YACd,CAAC;YACD,OAAO,CAAC,aAAa,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,SAAS,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;YACtD,IAAI,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC;gBAAE,OAAO;YACxC,OAAO,SAAS,EAAE,CAChB,IAAI,EACJ,SAAS,EACT,cAAc,EACd,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAC1C,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;YACrD,IAAI,KAAK,YAAY,yBAAyB,IAAI,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC;gBAAE,OAAO;YACtF,OAAO,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChG,CAAC;QACD,SAAS,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,EAAE;YAC7D,IAAI,KAAK,YAAY,yBAAyB,IAAI,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC;gBAAE,OAAO;YACtF,OAAO,SAAS,EAAE,CAChB,IAAI,EACJ,KAAK,EACL,SAAS,EACT,cAAc,EACd,WAAW,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAC1C,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IAEH,SAAS,UAAU,CAAC,OAAgC;QAClD,OAAO,CAAC,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,cAAc,CAAC;IAC/D,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,GAAG,QAAQ,CAAC;IACpE,MAAM,MAAM,GAAG,WAAW,CACxB,CACE,SAAqB,EACrB,WAA8E,EAC9E,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,gBAAgB,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,WAAW,CAAC,CAAC,EAC/E,CAAC,SAAS,EAAE,KAAK,CAAC,CACnB,CAAC;IACF,MAAM,WAAW,GAAG,WAAW,CAC7B,CACE,SAAqB,EACrB,WAA8E,EAC9E,EAAE;QACF,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACtC,OAAO,eAAe,CACpB,OAAO,EACP,cAAc,CAAC,SAAS,EAAE,gBAAgB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAClE,CAAC;IACJ,CAAC,EACD,CAAC,cAAc,EAAE,KAAK,CAAC,CACxB,CAAC;IACF,OAAO,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,WAAW,EAKxC,CAAC;AACJ,CAAC","sourcesContent":["'use client';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useInsertionEffect,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n useMutation,\n useQueryClient,\n type DefaultError,\n type MutateOptions,\n type MutationFunctionContext,\n type UseMutationOptions,\n type UseMutationResult,\n} from '@tanstack/react-query';\n\nexport interface MutationSession {\n uid: string | null;\n isCurrent(): boolean;\n assertCurrent(): void;\n}\n\nexport type SessionMutationFunctionContext = MutationFunctionContext & {\n session: MutationSession;\n};\n\nexport type SessionMutationOptions<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TOnMutateResult = unknown,\n> = Omit<\n UseMutationOptions<TData, TError, TVariables, TOnMutateResult>,\n 'mutationFn' | 'onMutate' | 'onSuccess' | 'onError' | 'onSettled'\n> & {\n mutationFn: (variables: TVariables, context: SessionMutationFunctionContext) => Promise<TData>;\n onMutate?: (\n variables: TVariables,\n context: SessionMutationFunctionContext,\n ) => Promise<TOnMutateResult> | TOnMutateResult;\n onSuccess?: (\n data: TData,\n variables: TVariables,\n onMutateResult: TOnMutateResult,\n context: SessionMutationFunctionContext,\n ) => Promise<unknown> | unknown;\n onError?: (\n error: TError,\n variables: TVariables,\n onMutateResult: TOnMutateResult | undefined,\n context: SessionMutationFunctionContext,\n ) => Promise<unknown> | unknown;\n onSettled?: (\n data: TData | undefined,\n error: TError | null,\n variables: TVariables,\n onMutateResult: TOnMutateResult | undefined,\n context: SessionMutationFunctionContext,\n ) => Promise<unknown> | unknown;\n};\n\nexport interface SessionMutateOptions<TData, TError, TVariables, TOnMutateResult> {\n onSuccess?: (\n data: TData,\n variables: TVariables,\n onMutateResult: TOnMutateResult | undefined,\n context: SessionMutationFunctionContext,\n ) => void;\n onError?: (\n error: TError,\n variables: TVariables,\n onMutateResult: TOnMutateResult | undefined,\n context: SessionMutationFunctionContext,\n ) => void;\n onSettled?: (\n data: TData | undefined,\n error: TError | null,\n variables: TVariables,\n onMutateResult: TOnMutateResult | undefined,\n context: SessionMutationFunctionContext,\n ) => void;\n}\n\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\nexport type SessionMutationResult<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TOnMutateResult = unknown,\n> = DistributiveOmit<\n UseMutationResult<TData, TError, TVariables, TOnMutateResult>,\n 'mutate' | 'mutateAsync'\n> & {\n mutate: (\n variables: TVariables,\n options?: SessionMutateOptions<TData, TError, TVariables, TOnMutateResult>,\n ) => void;\n mutateAsync: (\n variables: TVariables,\n options?: SessionMutateOptions<TData, TError, TVariables, TOnMutateResult>,\n ) => Promise<TData>;\n};\n\nexport class MutationSessionEndedError extends Error {\n override name = 'AbortError';\n\n constructor(options?: { cause?: unknown }) {\n super('The session that started this mutation has ended.', options);\n }\n}\n\ninterface SessionStore {\n current: { uid: string | null; generation: number };\n}\n\nconst MutationSessionContext = createContext<SessionStore | null>(null);\n\nexport interface MutationSessionProviderProps {\n currentUid: string | null;\n children?: ReactNode;\n}\n\nexport function MutationSessionProvider({ currentUid, children }: MutationSessionProviderProps) {\n const [store] = useState<SessionStore>(() => ({\n current: { uid: currentUid, generation: 0 },\n }));\n // Insertion effects run before any layout effect of the commit, so a child's layout effect\n // never starts a mutation under the uid this commit ends.\n useInsertionEffect(() => {\n if (store.current.uid !== currentUid) {\n store.current = { uid: currentUid, generation: store.current.generation + 1 };\n }\n }, [store, currentUid]);\n return (\n <MutationSessionContext.Provider value={store}>{children}</MutationSessionContext.Provider>\n );\n}\n\nconst ALWAYS_CURRENT: MutationSession = {\n uid: null,\n isCurrent: () => true,\n assertCurrent: () => {},\n};\n\nfunction captureSession(store: SessionStore | null): MutationSession {\n if (!store) return ALWAYS_CURRENT;\n const { uid, generation } = store.current;\n const isCurrent = () => store.current.generation === generation;\n return {\n uid,\n isCurrent,\n assertCurrent: () => {\n if (!isCurrent()) throw new MutationSessionEndedError();\n },\n };\n}\n\nexport function useMutationSessionCapture(): () => MutationSession {\n const store = useContext(MutationSessionContext);\n return useCallback(() => captureSession(store), [store]);\n}\n\nconst runSessions = new WeakMap<MutationFunctionContext, MutationSession>();\n\nfunction runHasEnded(store: SessionStore | null, context: MutationFunctionContext): boolean {\n if (!store) return false;\n return !(runSessions.get(context)?.isCurrent() ?? false);\n}\n\ntype Retry<TError> = UseMutationOptions<unknown, TError, unknown, unknown>['retry'];\ntype ThrowOnError<TError> = UseMutationOptions<unknown, TError, unknown, unknown>['throwOnError'];\n\nfunction retriesAfter<TError>(retry: Retry<TError>, failureCount: number, error: TError): boolean {\n if (error instanceof MutationSessionEndedError) return false;\n if (typeof retry === 'function') return retry(failureCount, error);\n if (typeof retry === 'number') return failureCount < retry;\n return retry === true;\n}\n\nfunction throwsToBoundary<TError>(throwOnError: ThrowOnError<TError>, error: TError): boolean {\n if (error instanceof MutationSessionEndedError) return false;\n if (typeof throwOnError === 'function') return throwOnError(error);\n return throwOnError === true;\n}\n\nfunction withSession(\n context: MutationFunctionContext,\n session: MutationSession,\n): SessionMutationFunctionContext {\n return { ...context, session };\n}\n\nfunction fenceCallOptions<TData, TError, TVariables, TOnMutateResult>(\n session: MutationSession,\n options: SessionMutateOptions<TData, TError, TVariables, TOnMutateResult> | undefined,\n): MutateOptions<TData, TError, TVariables, TOnMutateResult> | undefined {\n if (!options) return undefined;\n const { onSuccess, onError, onSettled } = options;\n return {\n onSuccess: onSuccess\n ? (data, variables, onMutateResult, context) => {\n if (session.isCurrent()) {\n onSuccess(data, variables, onMutateResult, withSession(context, session));\n }\n }\n : undefined,\n onError: onError\n ? (error, variables, onMutateResult, context) => {\n if (!(error instanceof MutationSessionEndedError) && session.isCurrent()) {\n onError(error, variables, onMutateResult, withSession(context, session));\n }\n }\n : undefined,\n onSettled: onSettled\n ? (data, error, variables, onMutateResult, context) => {\n if (!(error instanceof MutationSessionEndedError) && session.isCurrent()) {\n onSettled(data, error, variables, onMutateResult, withSession(context, session));\n }\n }\n : undefined,\n };\n}\n\nasync function settleInSession<TData>(\n session: MutationSession,\n settled: Promise<TData>,\n): Promise<TData> {\n let data: TData;\n try {\n data = await settled;\n } catch (error) {\n if (!(error instanceof MutationSessionEndedError) && !session.isCurrent()) {\n throw new MutationSessionEndedError({ cause: error });\n }\n throw error;\n }\n session.assertCurrent();\n return data;\n}\n\nexport function useSessionMutation<\n TData = unknown,\n TError = DefaultError,\n TVariables = void,\n TOnMutateResult = unknown,\n>(\n options: SessionMutationOptions<TData, TError, TVariables, TOnMutateResult>,\n): SessionMutationResult<TData, TError, TVariables, TOnMutateResult> {\n const store = useContext(MutationSessionContext);\n const queryClient = useQueryClient();\n const { mutationFn, onMutate, onSuccess, onError, onSettled, retry, throwOnError, ...rest } =\n options;\n const defaults = queryClient.defaultMutationOptions<\n UseMutationOptions<unknown, TError, unknown, unknown>\n >({ mutationKey: options.mutationKey });\n const baseRetry = (retry ?? defaults.retry) as Retry<TError>;\n const baseThrowOnError = (throwOnError ?? defaults.throwOnError) as ThrowOnError<TError>;\n\n const mutation = useMutation<TData, TError, TVariables, TOnMutateResult>({\n ...rest,\n retry: (failureCount, error) => retriesAfter(baseRetry, failureCount, error),\n throwOnError: (error) => throwsToBoundary(baseThrowOnError, error),\n onMutate: (variables, context) => {\n const session = store ? captureSession(store) : ALWAYS_CURRENT;\n if (store) runSessions.set(context, session);\n return onMutate?.(variables, withSession(context, session)) as\n TOnMutateResult | Promise<TOnMutateResult>;\n },\n mutationFn: async (variables, context) => {\n const session = store ? runSessions.get(context) : ALWAYS_CURRENT;\n if (!session || !session.isCurrent()) throw new MutationSessionEndedError();\n let data: TData;\n try {\n data = await mutationFn(variables, { ...context, session });\n } catch (error) {\n if (!session.isCurrent()) throw new MutationSessionEndedError({ cause: error });\n throw error;\n }\n session.assertCurrent();\n return data;\n },\n onSuccess: (data, variables, onMutateResult, context) => {\n if (runHasEnded(store, context)) return;\n return onSuccess?.(\n data,\n variables,\n onMutateResult,\n withSession(context, runSession(context)),\n );\n },\n onError: (error, variables, onMutateResult, context) => {\n if (error instanceof MutationSessionEndedError || runHasEnded(store, context)) return;\n return onError?.(error, variables, onMutateResult, withSession(context, runSession(context)));\n },\n onSettled: (data, error, variables, onMutateResult, context) => {\n if (error instanceof MutationSessionEndedError || runHasEnded(store, context)) return;\n return onSettled?.(\n data,\n error,\n variables,\n onMutateResult,\n withSession(context, runSession(context)),\n );\n },\n });\n\n function runSession(context: MutationFunctionContext): MutationSession {\n return (store && runSessions.get(context)) || ALWAYS_CURRENT;\n }\n\n const { mutate: rawMutate, mutateAsync: rawMutateAsync } = mutation;\n const mutate = useCallback(\n (\n variables: TVariables,\n callOptions?: SessionMutateOptions<TData, TError, TVariables, TOnMutateResult>,\n ) => rawMutate(variables, fenceCallOptions(captureSession(store), callOptions)),\n [rawMutate, store],\n );\n const mutateAsync = useCallback(\n (\n variables: TVariables,\n callOptions?: SessionMutateOptions<TData, TError, TVariables, TOnMutateResult>,\n ) => {\n const session = captureSession(store);\n return settleInSession(\n session,\n rawMutateAsync(variables, fenceCallOptions(session, callOptions)),\n );\n },\n [rawMutateAsync, store],\n );\n return { ...mutation, mutate, mutateAsync } as SessionMutationResult<\n TData,\n TError,\n TVariables,\n TOnMutateResult\n >;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttt-productions/query-core",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.25",
|
|
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",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"prepublishOnly": "npm run clean && npm run build"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@tanstack/react-query": ">=5.
|
|
43
|
+
"@tanstack/react-query": ">=5.90.0",
|
|
44
44
|
"firebase": ">=12.0.0",
|
|
45
45
|
"react": ">=19.0.0",
|
|
46
46
|
"react-dom": ">=19.0.0"
|
|
@@ -60,10 +60,10 @@
|
|
|
60
60
|
}
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@ttt-productions/firebase-helpers": "^0.12.
|
|
63
|
+
"@ttt-productions/firebase-helpers": "^0.12.16"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
|
-
"@tanstack/react-query": "^5.
|
|
66
|
+
"@tanstack/react-query": "^5.90.0",
|
|
67
67
|
"@types/react": "^19.0.0",
|
|
68
68
|
"@types/react-dom": "^19.0.0",
|
|
69
69
|
"firebase": "^12.14.0",
|