@vielzeug/courier 1.1.2 → 1.1.3
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/README.md +1 -1
- package/dist/courier.cjs +1 -1
- package/dist/courier.cjs.map +1 -1
- package/dist/courier.iife.js +1 -1
- package/dist/courier.iife.js.map +1 -1
- package/dist/courier.js +1 -1
- package/dist/courier.js.map +1 -1
- package/dist/mutation.cjs +1 -1
- package/dist/mutation.cjs.map +1 -1
- package/dist/mutation.d.ts.map +1 -1
- package/dist/mutation.js +1 -1
- package/dist/mutation.js.map +1 -1
- package/dist/query-observe.cjs +1 -1
- package/dist/query-observe.cjs.map +1 -1
- package/dist/query-observe.d.ts.map +1 -1
- package/dist/query-observe.js +1 -1
- package/dist/query-observe.js.map +1 -1
- package/package.json +1 -1
package/dist/mutation.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./errors.cjs"),t=require("./transport.cjs"),n=require("./retry.cjs");let r=require("@vielzeug/arsenal");var i=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!
|
|
1
|
+
const e=require("./errors.cjs"),t=require("./transport.cjs"),n=require("./retry.cjs");let r=require("@vielzeug/arsenal");var i=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!0,status:`loading`,updatedAt:void 0});function a(a,o){let s=i,c=0,l=null,u=new Set,d=!1,f=null;function p(){u.forEach(e=>e())}async function m(e){try{await e?.()}catch(e){if(o?.onCallbackError)try{o.onCallbackError(e instanceof Error?e:Error(String(e)))}catch{}}}return{async cancel(){let e=l;e&&(e.controller.abort(),await e.promise.catch(()=>{}))},dispose(){d||(d=!0,l?.controller.abort(),l=null,u.clear())},get disposed(){return d},async mutate(u,f){if(d)throw new e.CourierDisposedError(`Mutation`);let h=new AbortController,g=f?.signal?t.anySignal(f.signal,h.signal):h.signal,_=++c;s={data:void 0,error:null,isFetching:!0,isLoading:!0,status:`loading`,updatedAt:void 0},p();let v={controller:h,promise:null};l=v;let y=(async()=>{try{let e=await(0,r.retry)(()=>a(u,g),{delay:e=>n.resolveRetryDelay(e,o?.delay),shouldRetry:o?.shouldRetry,signal:g,times:o?.times??1});return _===c&&(s={data:e,error:null,isFetching:!1,isLoading:!1,status:`success`,updatedAt:Date.now()},p()),await m(()=>o?.onSuccess?.(e,u)),await m(()=>o?.onFinally?.(u)),await m(()=>o?.onSettled?.({data:e,status:`success`,variables:u})),e}catch(e){let t=e instanceof Error?e:Error(String(e)),n=g.aborted||(0,r.isAbortError)(t);throw _===c&&(s=n?i:{data:void 0,error:t,isFetching:!1,isLoading:!1,status:`error`,updatedAt:Date.now()},p()),n||await m(()=>o?.onError?.(t,u)),await m(()=>o?.onFinally?.(u)),await m(()=>o?.onSettled?.(n?{status:`aborted`,variables:u}:{error:t,status:`error`,variables:u})),t}finally{l?.controller===h&&(l=null)}})();return v.promise=y,y},peek(){return s},reset(){s=i,p()},get store(){return f??={peek:()=>s,subscribe:e=>d?()=>{}:(u.add(e),()=>u.delete(e))}},subscribe(e){return d?()=>{}:(u.add(e),()=>u.delete(e))},[Symbol.dispose](){this.dispose()}}}exports.createMutation=a;
|
|
2
2
|
//# sourceMappingURL=mutation.cjs.map
|
package/dist/mutation.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.cjs","names":[],"sources":["../src/mutation.ts"],"sourcesContent":["import { isAbortError, retry } from '@vielzeug/arsenal';\n\nimport type { RetryOptions } from './retry';\nimport type { MutationState, SyncStore, Unsubscribe } from './types';\n\nimport { CourierDisposedError } from './errors';\nimport { resolveRetryDelay } from './retry';\nimport { anySignal } from './transport';\n\nconst IDLE_STATE: MutationState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: false,\n status: 'loading',\n updatedAt: undefined,\n});\n\n/**\n * Discriminated union result passed to `onSettled`.\n * Switch on `result.status` to handle each outcome exhaustively.\n */\nexport type SettledResult<TData, TVariables> =\n | { readonly data: TData; readonly status: 'success'; readonly variables: TVariables }\n | { readonly error: Error; readonly status: 'error'; readonly variables: TVariables }\n | { readonly status: 'aborted'; readonly variables: TVariables };\n\nexport type MutationOptions<TData = unknown, TVariables = void> = RetryOptions & {\n /**\n * Called when a lifecycle callback (`onSuccess`, `onError`, `onSettled`, or `onFinally`) throws.\n * Does not affect the `mutate()` result or re-throw. Optional — for development/debugging.\n */\n onCallbackError?: (error: Error) => void;\n /**\n * Called after a failed run, before `mutate()` rejects.\n * Not called when the mutation was aborted (use `onSettled` if you need abort awareness).\n */\n onError?: (error: Error, variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Use for cleanup patterns that do not need to inspect the result.\n * Runs after `onSuccess` / `onError` and before `onSettled`.\n */\n onFinally?: (variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Switch on `result.status` to handle `'success'`, `'error'`, or `'aborted'` exhaustively.\n */\n onSettled?: (result: SettledResult<TData, TVariables>) => void | Promise<void>;\n /** Called after a successful run, before `mutate()` resolves. */\n onSuccess?: (data: TData, variables: TVariables) => void | Promise<void>;\n};\n\nexport type MutationFn<TData, TVariables = void> = (input: TVariables, signal: AbortSignal) => Promise<TData>;\n\n/**\n * Wraps an async function (typically a write operation — create/update/delete) with\n * loading/success/error state tracking, retries, cancellation, and lifecycle callbacks.\n *\n * @example\n * ```ts\n * const createUser = createMutation(\n * (input: NewUser, signal) => api.post<User>('/users', { body: input, signal }),\n * { onSuccess: (user) => console.log('created', user.id) },\n * );\n *\n * const unsub = createUser.subscribe(() => console.log(createUser.peek()));\n * const user = await createUser.mutate({ name: 'Ada' });\n *\n * // later:\n * createUser.dispose();\n * ```\n */\nexport function createMutation<TData, TVariables = void>(\n mutationFn: MutationFn<TData, TVariables>,\n mutOpts?: MutationOptions<TData, TVariables>,\n): Mutation<TData, TVariables> {\n let snap: MutationState<TData> = IDLE_STATE as MutationState<TData>;\n let currentRun = 0;\n let activeRun: { controller: AbortController; promise: Promise<unknown> } | null = null;\n const observers = new Set<() => void>();\n let disposed = false;\n let cachedStore: SyncStore<MutationState<TData>> | null = null;\n\n function notifyObservers(): void {\n observers.forEach((l) => l());\n }\n\n async function safeCall(fn: (() => void | Promise<void>) | undefined): Promise<void> {\n try {\n await fn?.();\n } catch (err) {\n if (mutOpts?.onCallbackError) {\n try {\n mutOpts.onCallbackError(err instanceof Error ? err : new Error(String(err)));\n } catch {\n // Silently ignore errors in error handler itself.\n }\n }\n }\n }\n\n return {\n async cancel(): Promise<void> {\n const run = activeRun;\n\n if (!run) return;\n\n run.controller.abort();\n await run.promise.catch(() => {});\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n activeRun?.controller.abort();\n activeRun = null;\n observers.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n /**\n * Execute the mutation with the given variables.\n *\n * Concurrent calls are allowed. State updates (`isFetching`, `data`, `error`) always\n * reflect the **latest** `mutate()` call. Lifecycle callbacks (`onSuccess`, `onError`,\n * `onSettled`) fire for **every** call independently — not just the last one.\n * Cancel earlier calls via `mutation.cancel()` if you need only-last-wins callback semantics.\n *\n * @throws {CourierDisposedError} If called after `dispose()`.\n */\n async mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData> {\n if (disposed) throw new CourierDisposedError('Mutation');\n\n const localController = new AbortController();\n\n const signal = callOpts?.signal ? anySignal(callOpts.signal, localController.signal)! : localController.signal;\n const run = ++currentRun;\n\n snap = {\n data: undefined,\n error: null,\n isFetching: true,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n };\n notifyObservers();\n\n const pendingRun = { controller: localController, promise: null as unknown as Promise<TData> };\n\n activeRun = pendingRun;\n\n const operation = (async () => {\n try {\n const data = await retry(() => mutationFn(variables, signal), {\n delay: (attempt) => resolveRetryDelay(attempt, mutOpts?.delay),\n shouldRetry: mutOpts?.shouldRetry,\n signal,\n times: mutOpts?.times ?? 1,\n });\n\n if (run === currentRun) {\n snap = { data, error: null, isFetching: false, isLoading: false, status: 'success', updatedAt: Date.now() };\n notifyObservers();\n }\n\n await safeCall(() => mutOpts?.onSuccess?.(data, variables));\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() => mutOpts?.onSettled?.({ data, status: 'success', variables }));\n\n return data;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isAborted = signal.aborted || isAbortError(error);\n\n if (run === currentRun) {\n snap = isAborted\n ? (IDLE_STATE as MutationState<TData>)\n : { data: undefined, error, isFetching: false, isLoading: false, status: 'error', updatedAt: Date.now() };\n notifyObservers();\n }\n\n if (!isAborted) {\n await safeCall(() => mutOpts?.onError?.(error, variables));\n }\n\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() =>\n mutOpts?.onSettled?.(isAborted ? { status: 'aborted', variables } : { error, status: 'error', variables }),\n );\n\n throw error;\n } finally {\n if (activeRun?.controller === localController) {\n activeRun = null;\n }\n }\n })();\n\n pendingRun.promise = operation;\n\n return operation;\n },\n\n /**\n * Read the current mutation state snapshot.\n * For framework integrations prefer `peek()` + `subscribe()` directly.\n */\n peek(): MutationState<TData> {\n return snap;\n },\n\n reset(): void {\n snap = IDLE_STATE as MutationState<TData>;\n notifyObservers();\n },\n\n /**\n * A `SyncStore` view of the mutation state — identical to `{ peek, subscribe }` on this object.\n * Provided for framework integrations that accept a `SyncStore` directly:\n * - React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n * - Svelte: `readable(mutation.peek(), mutation.subscribe)`\n */\n get store(): SyncStore<MutationState<TData>> {\n return (cachedStore ??= {\n peek: () => snap,\n subscribe: (cb) => {\n observers.add(cb);\n\n return () => observers.delete(cb);\n },\n });\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n observers.add(onStoreChange);\n\n return () => observers.delete(onStoreChange);\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n}\n\nexport interface Mutation<TData, TVariables = void> {\n [Symbol.dispose](): void;\n cancel(): Promise<void>;\n dispose(): void;\n get disposed(): boolean;\n mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData>;\n peek(): MutationState<TData>;\n reset(): void;\n /**\n * `SyncStore` adapter — equivalent to `{ peek, subscribe }` on this object.\n * For React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n */\n get store(): SyncStore<MutationState<TData>>;\n subscribe(onStoreChange: () => void): Unsubscribe;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mutation.cjs","names":[],"sources":["../src/mutation.ts"],"sourcesContent":["import { isAbortError, retry } from '@vielzeug/arsenal';\n\nimport type { RetryOptions } from './retry';\nimport type { MutationState, SyncStore, Unsubscribe } from './types';\n\nimport { CourierDisposedError } from './errors';\nimport { resolveRetryDelay } from './retry';\nimport { anySignal } from './transport';\n\nconst IDLE_STATE: MutationState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n});\n\n/**\n * Discriminated union result passed to `onSettled`.\n * Switch on `result.status` to handle each outcome exhaustively.\n */\nexport type SettledResult<TData, TVariables> =\n | { readonly data: TData; readonly status: 'success'; readonly variables: TVariables }\n | { readonly error: Error; readonly status: 'error'; readonly variables: TVariables }\n | { readonly status: 'aborted'; readonly variables: TVariables };\n\nexport type MutationOptions<TData = unknown, TVariables = void> = RetryOptions & {\n /**\n * Called when a lifecycle callback (`onSuccess`, `onError`, `onSettled`, or `onFinally`) throws.\n * Does not affect the `mutate()` result or re-throw. Optional — for development/debugging.\n */\n onCallbackError?: (error: Error) => void;\n /**\n * Called after a failed run, before `mutate()` rejects.\n * Not called when the mutation was aborted (use `onSettled` if you need abort awareness).\n */\n onError?: (error: Error, variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Use for cleanup patterns that do not need to inspect the result.\n * Runs after `onSuccess` / `onError` and before `onSettled`.\n */\n onFinally?: (variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Switch on `result.status` to handle `'success'`, `'error'`, or `'aborted'` exhaustively.\n */\n onSettled?: (result: SettledResult<TData, TVariables>) => void | Promise<void>;\n /** Called after a successful run, before `mutate()` resolves. */\n onSuccess?: (data: TData, variables: TVariables) => void | Promise<void>;\n};\n\nexport type MutationFn<TData, TVariables = void> = (input: TVariables, signal: AbortSignal) => Promise<TData>;\n\n/**\n * Wraps an async function (typically a write operation — create/update/delete) with\n * loading/success/error state tracking, retries, cancellation, and lifecycle callbacks.\n *\n * @example\n * ```ts\n * const createUser = createMutation(\n * (input: NewUser, signal) => api.post<User>('/users', { body: input, signal }),\n * { onSuccess: (user) => console.log('created', user.id) },\n * );\n *\n * const unsub = createUser.subscribe(() => console.log(createUser.peek()));\n * const user = await createUser.mutate({ name: 'Ada' });\n *\n * // later:\n * createUser.dispose();\n * ```\n */\nexport function createMutation<TData, TVariables = void>(\n mutationFn: MutationFn<TData, TVariables>,\n mutOpts?: MutationOptions<TData, TVariables>,\n): Mutation<TData, TVariables> {\n let snap: MutationState<TData> = IDLE_STATE as MutationState<TData>;\n let currentRun = 0;\n let activeRun: { controller: AbortController; promise: Promise<unknown> } | null = null;\n const observers = new Set<() => void>();\n let disposed = false;\n let cachedStore: SyncStore<MutationState<TData>> | null = null;\n\n function notifyObservers(): void {\n observers.forEach((l) => l());\n }\n\n async function safeCall(fn: (() => void | Promise<void>) | undefined): Promise<void> {\n try {\n await fn?.();\n } catch (err) {\n if (mutOpts?.onCallbackError) {\n try {\n mutOpts.onCallbackError(err instanceof Error ? err : new Error(String(err)));\n } catch {\n // Silently ignore errors in error handler itself.\n }\n }\n }\n }\n\n return {\n async cancel(): Promise<void> {\n const run = activeRun;\n\n if (!run) return;\n\n run.controller.abort();\n await run.promise.catch(() => {});\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n activeRun?.controller.abort();\n activeRun = null;\n observers.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n /**\n * Execute the mutation with the given variables.\n *\n * Concurrent calls are allowed. State updates (`isFetching`, `data`, `error`) always\n * reflect the **latest** `mutate()` call. Lifecycle callbacks (`onSuccess`, `onError`,\n * `onSettled`) fire for **every** call independently — not just the last one.\n * Cancel earlier calls via `mutation.cancel()` if you need only-last-wins callback semantics.\n *\n * @throws {CourierDisposedError} If called after `dispose()`.\n */\n async mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData> {\n if (disposed) throw new CourierDisposedError('Mutation');\n\n const localController = new AbortController();\n\n const signal = callOpts?.signal ? anySignal(callOpts.signal, localController.signal)! : localController.signal;\n const run = ++currentRun;\n\n snap = {\n data: undefined,\n error: null,\n isFetching: true,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n };\n notifyObservers();\n\n const pendingRun = { controller: localController, promise: null as unknown as Promise<TData> };\n\n activeRun = pendingRun;\n\n const operation = (async () => {\n try {\n const data = await retry(() => mutationFn(variables, signal), {\n delay: (attempt) => resolveRetryDelay(attempt, mutOpts?.delay),\n shouldRetry: mutOpts?.shouldRetry,\n signal,\n times: mutOpts?.times ?? 1,\n });\n\n if (run === currentRun) {\n snap = { data, error: null, isFetching: false, isLoading: false, status: 'success', updatedAt: Date.now() };\n notifyObservers();\n }\n\n await safeCall(() => mutOpts?.onSuccess?.(data, variables));\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() => mutOpts?.onSettled?.({ data, status: 'success', variables }));\n\n return data;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isAborted = signal.aborted || isAbortError(error);\n\n if (run === currentRun) {\n snap = isAborted\n ? (IDLE_STATE as MutationState<TData>)\n : { data: undefined, error, isFetching: false, isLoading: false, status: 'error', updatedAt: Date.now() };\n notifyObservers();\n }\n\n if (!isAborted) {\n await safeCall(() => mutOpts?.onError?.(error, variables));\n }\n\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() =>\n mutOpts?.onSettled?.(isAborted ? { status: 'aborted', variables } : { error, status: 'error', variables }),\n );\n\n throw error;\n } finally {\n if (activeRun?.controller === localController) {\n activeRun = null;\n }\n }\n })();\n\n pendingRun.promise = operation;\n\n return operation;\n },\n\n /**\n * Read the current mutation state snapshot.\n * For framework integrations prefer `peek()` + `subscribe()` directly.\n */\n peek(): MutationState<TData> {\n return snap;\n },\n\n reset(): void {\n snap = IDLE_STATE as MutationState<TData>;\n notifyObservers();\n },\n\n /**\n * A `SyncStore` view of the mutation state — identical to `{ peek, subscribe }` on this object.\n * Provided for framework integrations that accept a `SyncStore` directly:\n * - React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n * - Svelte: `readable(mutation.peek(), mutation.subscribe)`\n */\n get store(): SyncStore<MutationState<TData>> {\n return (cachedStore ??= {\n peek: () => snap,\n subscribe: (cb) => {\n if (disposed) return () => {};\n\n observers.add(cb);\n\n return () => observers.delete(cb);\n },\n });\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n if (disposed) return () => {};\n\n observers.add(onStoreChange);\n\n return () => observers.delete(onStoreChange);\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n}\n\nexport interface Mutation<TData, TVariables = void> {\n [Symbol.dispose](): void;\n cancel(): Promise<void>;\n dispose(): void;\n get disposed(): boolean;\n mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData>;\n peek(): MutationState<TData>;\n reset(): void;\n /**\n * `SyncStore` adapter — equivalent to `{ peek, subscribe }` on this object.\n * For React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n */\n get store(): SyncStore<MutationState<TData>>;\n subscribe(onStoreChange: () => void): Unsubscribe;\n}\n"],"mappings":"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"}
|
package/dist/mutation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.d.ts","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAerE;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,KAAK,EAAE,UAAU,IACvC;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE,GACpF;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,UAAU,GAAG,IAAI,IAAI,YAAY,GAAG;IAC/E;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;AAE9G;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,EACrD,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,EACzC,OAAO,CAAC,EAAE,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC,GAC3C,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"mutation.d.ts","sourceRoot":"","sources":["../src/mutation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAerE;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,KAAK,EAAE,UAAU,IACvC;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE,GACpF;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE,GACnF;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,eAAe,CAAC,KAAK,GAAG,OAAO,EAAE,UAAU,GAAG,IAAI,IAAI,YAAY,GAAG;IAC/E;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACzC;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/E,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1E,CAAC;AAEF,MAAM,MAAM,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;AAE9G;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,EACrD,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,EACzC,OAAO,CAAC,EAAE,eAAe,CAAC,KAAK,EAAE,UAAU,CAAC,GAC3C,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,CAiL7B;AAED,MAAM,WAAW,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAChD,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACzB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,QAAQ,IAAI,OAAO,CAAC;IACxB,MAAM,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IACnF,IAAI,IAAI,aAAa,CAAC,KAAK,CAAC,CAAC;IAC7B,KAAK,IAAI,IAAI,CAAC;IACd;;;OAGG;IACH,IAAI,KAAK,IAAI,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,SAAS,CAAC,aAAa,EAAE,MAAM,IAAI,GAAG,WAAW,CAAC;CACnD"}
|
package/dist/mutation.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{CourierDisposedError as e}from"./errors.js";import{anySignal as t}from"./transport.js";import{resolveRetryDelay as n}from"./retry.js";import{isAbortError as r,retry as i}from"@vielzeug/arsenal";var a=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!
|
|
1
|
+
import{CourierDisposedError as e}from"./errors.js";import{anySignal as t}from"./transport.js";import{resolveRetryDelay as n}from"./retry.js";import{isAbortError as r,retry as i}from"@vielzeug/arsenal";var a=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!0,status:`loading`,updatedAt:void 0});function o(o,s){let c=a,l=0,u=null,d=new Set,f=!1,p=null;function m(){d.forEach(e=>e())}async function h(e){try{await e?.()}catch(e){if(s?.onCallbackError)try{s.onCallbackError(e instanceof Error?e:Error(String(e)))}catch{}}}return{async cancel(){let e=u;e&&(e.controller.abort(),await e.promise.catch(()=>{}))},dispose(){f||(f=!0,u?.controller.abort(),u=null,d.clear())},get disposed(){return f},async mutate(d,p){if(f)throw new e(`Mutation`);let g=new AbortController,_=p?.signal?t(p.signal,g.signal):g.signal,v=++l;c={data:void 0,error:null,isFetching:!0,isLoading:!0,status:`loading`,updatedAt:void 0},m();let y={controller:g,promise:null};u=y;let b=(async()=>{try{let e=await i(()=>o(d,_),{delay:e=>n(e,s?.delay),shouldRetry:s?.shouldRetry,signal:_,times:s?.times??1});return v===l&&(c={data:e,error:null,isFetching:!1,isLoading:!1,status:`success`,updatedAt:Date.now()},m()),await h(()=>s?.onSuccess?.(e,d)),await h(()=>s?.onFinally?.(d)),await h(()=>s?.onSettled?.({data:e,status:`success`,variables:d})),e}catch(e){let t=e instanceof Error?e:Error(String(e)),n=_.aborted||r(t);throw v===l&&(c=n?a:{data:void 0,error:t,isFetching:!1,isLoading:!1,status:`error`,updatedAt:Date.now()},m()),n||await h(()=>s?.onError?.(t,d)),await h(()=>s?.onFinally?.(d)),await h(()=>s?.onSettled?.(n?{status:`aborted`,variables:d}:{error:t,status:`error`,variables:d})),t}finally{u?.controller===g&&(u=null)}})();return y.promise=b,b},peek(){return c},reset(){c=a,m()},get store(){return p??={peek:()=>c,subscribe:e=>f?()=>{}:(d.add(e),()=>d.delete(e))}},subscribe(e){return f?()=>{}:(d.add(e),()=>d.delete(e))},[Symbol.dispose](){this.dispose()}}}export{o as createMutation};
|
|
2
2
|
//# sourceMappingURL=mutation.js.map
|
package/dist/mutation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mutation.js","names":[],"sources":["../src/mutation.ts"],"sourcesContent":["import { isAbortError, retry } from '@vielzeug/arsenal';\n\nimport type { RetryOptions } from './retry';\nimport type { MutationState, SyncStore, Unsubscribe } from './types';\n\nimport { CourierDisposedError } from './errors';\nimport { resolveRetryDelay } from './retry';\nimport { anySignal } from './transport';\n\nconst IDLE_STATE: MutationState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: false,\n status: 'loading',\n updatedAt: undefined,\n});\n\n/**\n * Discriminated union result passed to `onSettled`.\n * Switch on `result.status` to handle each outcome exhaustively.\n */\nexport type SettledResult<TData, TVariables> =\n | { readonly data: TData; readonly status: 'success'; readonly variables: TVariables }\n | { readonly error: Error; readonly status: 'error'; readonly variables: TVariables }\n | { readonly status: 'aborted'; readonly variables: TVariables };\n\nexport type MutationOptions<TData = unknown, TVariables = void> = RetryOptions & {\n /**\n * Called when a lifecycle callback (`onSuccess`, `onError`, `onSettled`, or `onFinally`) throws.\n * Does not affect the `mutate()` result or re-throw. Optional — for development/debugging.\n */\n onCallbackError?: (error: Error) => void;\n /**\n * Called after a failed run, before `mutate()` rejects.\n * Not called when the mutation was aborted (use `onSettled` if you need abort awareness).\n */\n onError?: (error: Error, variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Use for cleanup patterns that do not need to inspect the result.\n * Runs after `onSuccess` / `onError` and before `onSettled`.\n */\n onFinally?: (variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Switch on `result.status` to handle `'success'`, `'error'`, or `'aborted'` exhaustively.\n */\n onSettled?: (result: SettledResult<TData, TVariables>) => void | Promise<void>;\n /** Called after a successful run, before `mutate()` resolves. */\n onSuccess?: (data: TData, variables: TVariables) => void | Promise<void>;\n};\n\nexport type MutationFn<TData, TVariables = void> = (input: TVariables, signal: AbortSignal) => Promise<TData>;\n\n/**\n * Wraps an async function (typically a write operation — create/update/delete) with\n * loading/success/error state tracking, retries, cancellation, and lifecycle callbacks.\n *\n * @example\n * ```ts\n * const createUser = createMutation(\n * (input: NewUser, signal) => api.post<User>('/users', { body: input, signal }),\n * { onSuccess: (user) => console.log('created', user.id) },\n * );\n *\n * const unsub = createUser.subscribe(() => console.log(createUser.peek()));\n * const user = await createUser.mutate({ name: 'Ada' });\n *\n * // later:\n * createUser.dispose();\n * ```\n */\nexport function createMutation<TData, TVariables = void>(\n mutationFn: MutationFn<TData, TVariables>,\n mutOpts?: MutationOptions<TData, TVariables>,\n): Mutation<TData, TVariables> {\n let snap: MutationState<TData> = IDLE_STATE as MutationState<TData>;\n let currentRun = 0;\n let activeRun: { controller: AbortController; promise: Promise<unknown> } | null = null;\n const observers = new Set<() => void>();\n let disposed = false;\n let cachedStore: SyncStore<MutationState<TData>> | null = null;\n\n function notifyObservers(): void {\n observers.forEach((l) => l());\n }\n\n async function safeCall(fn: (() => void | Promise<void>) | undefined): Promise<void> {\n try {\n await fn?.();\n } catch (err) {\n if (mutOpts?.onCallbackError) {\n try {\n mutOpts.onCallbackError(err instanceof Error ? err : new Error(String(err)));\n } catch {\n // Silently ignore errors in error handler itself.\n }\n }\n }\n }\n\n return {\n async cancel(): Promise<void> {\n const run = activeRun;\n\n if (!run) return;\n\n run.controller.abort();\n await run.promise.catch(() => {});\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n activeRun?.controller.abort();\n activeRun = null;\n observers.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n /**\n * Execute the mutation with the given variables.\n *\n * Concurrent calls are allowed. State updates (`isFetching`, `data`, `error`) always\n * reflect the **latest** `mutate()` call. Lifecycle callbacks (`onSuccess`, `onError`,\n * `onSettled`) fire for **every** call independently — not just the last one.\n * Cancel earlier calls via `mutation.cancel()` if you need only-last-wins callback semantics.\n *\n * @throws {CourierDisposedError} If called after `dispose()`.\n */\n async mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData> {\n if (disposed) throw new CourierDisposedError('Mutation');\n\n const localController = new AbortController();\n\n const signal = callOpts?.signal ? anySignal(callOpts.signal, localController.signal)! : localController.signal;\n const run = ++currentRun;\n\n snap = {\n data: undefined,\n error: null,\n isFetching: true,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n };\n notifyObservers();\n\n const pendingRun = { controller: localController, promise: null as unknown as Promise<TData> };\n\n activeRun = pendingRun;\n\n const operation = (async () => {\n try {\n const data = await retry(() => mutationFn(variables, signal), {\n delay: (attempt) => resolveRetryDelay(attempt, mutOpts?.delay),\n shouldRetry: mutOpts?.shouldRetry,\n signal,\n times: mutOpts?.times ?? 1,\n });\n\n if (run === currentRun) {\n snap = { data, error: null, isFetching: false, isLoading: false, status: 'success', updatedAt: Date.now() };\n notifyObservers();\n }\n\n await safeCall(() => mutOpts?.onSuccess?.(data, variables));\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() => mutOpts?.onSettled?.({ data, status: 'success', variables }));\n\n return data;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isAborted = signal.aborted || isAbortError(error);\n\n if (run === currentRun) {\n snap = isAborted\n ? (IDLE_STATE as MutationState<TData>)\n : { data: undefined, error, isFetching: false, isLoading: false, status: 'error', updatedAt: Date.now() };\n notifyObservers();\n }\n\n if (!isAborted) {\n await safeCall(() => mutOpts?.onError?.(error, variables));\n }\n\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() =>\n mutOpts?.onSettled?.(isAborted ? { status: 'aborted', variables } : { error, status: 'error', variables }),\n );\n\n throw error;\n } finally {\n if (activeRun?.controller === localController) {\n activeRun = null;\n }\n }\n })();\n\n pendingRun.promise = operation;\n\n return operation;\n },\n\n /**\n * Read the current mutation state snapshot.\n * For framework integrations prefer `peek()` + `subscribe()` directly.\n */\n peek(): MutationState<TData> {\n return snap;\n },\n\n reset(): void {\n snap = IDLE_STATE as MutationState<TData>;\n notifyObservers();\n },\n\n /**\n * A `SyncStore` view of the mutation state — identical to `{ peek, subscribe }` on this object.\n * Provided for framework integrations that accept a `SyncStore` directly:\n * - React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n * - Svelte: `readable(mutation.peek(), mutation.subscribe)`\n */\n get store(): SyncStore<MutationState<TData>> {\n return (cachedStore ??= {\n peek: () => snap,\n subscribe: (cb) => {\n observers.add(cb);\n\n return () => observers.delete(cb);\n },\n });\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n observers.add(onStoreChange);\n\n return () => observers.delete(onStoreChange);\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n}\n\nexport interface Mutation<TData, TVariables = void> {\n [Symbol.dispose](): void;\n cancel(): Promise<void>;\n dispose(): void;\n get disposed(): boolean;\n mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData>;\n peek(): MutationState<TData>;\n reset(): void;\n /**\n * `SyncStore` adapter — equivalent to `{ peek, subscribe }` on this object.\n * For React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n */\n get store(): SyncStore<MutationState<TData>>;\n subscribe(onStoreChange: () => void): Unsubscribe;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mutation.js","names":[],"sources":["../src/mutation.ts"],"sourcesContent":["import { isAbortError, retry } from '@vielzeug/arsenal';\n\nimport type { RetryOptions } from './retry';\nimport type { MutationState, SyncStore, Unsubscribe } from './types';\n\nimport { CourierDisposedError } from './errors';\nimport { resolveRetryDelay } from './retry';\nimport { anySignal } from './transport';\n\nconst IDLE_STATE: MutationState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n});\n\n/**\n * Discriminated union result passed to `onSettled`.\n * Switch on `result.status` to handle each outcome exhaustively.\n */\nexport type SettledResult<TData, TVariables> =\n | { readonly data: TData; readonly status: 'success'; readonly variables: TVariables }\n | { readonly error: Error; readonly status: 'error'; readonly variables: TVariables }\n | { readonly status: 'aborted'; readonly variables: TVariables };\n\nexport type MutationOptions<TData = unknown, TVariables = void> = RetryOptions & {\n /**\n * Called when a lifecycle callback (`onSuccess`, `onError`, `onSettled`, or `onFinally`) throws.\n * Does not affect the `mutate()` result or re-throw. Optional — for development/debugging.\n */\n onCallbackError?: (error: Error) => void;\n /**\n * Called after a failed run, before `mutate()` rejects.\n * Not called when the mutation was aborted (use `onSettled` if you need abort awareness).\n */\n onError?: (error: Error, variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Use for cleanup patterns that do not need to inspect the result.\n * Runs after `onSuccess` / `onError` and before `onSettled`.\n */\n onFinally?: (variables: TVariables) => void | Promise<void>;\n /**\n * Called after every run regardless of outcome, including aborts.\n * Switch on `result.status` to handle `'success'`, `'error'`, or `'aborted'` exhaustively.\n */\n onSettled?: (result: SettledResult<TData, TVariables>) => void | Promise<void>;\n /** Called after a successful run, before `mutate()` resolves. */\n onSuccess?: (data: TData, variables: TVariables) => void | Promise<void>;\n};\n\nexport type MutationFn<TData, TVariables = void> = (input: TVariables, signal: AbortSignal) => Promise<TData>;\n\n/**\n * Wraps an async function (typically a write operation — create/update/delete) with\n * loading/success/error state tracking, retries, cancellation, and lifecycle callbacks.\n *\n * @example\n * ```ts\n * const createUser = createMutation(\n * (input: NewUser, signal) => api.post<User>('/users', { body: input, signal }),\n * { onSuccess: (user) => console.log('created', user.id) },\n * );\n *\n * const unsub = createUser.subscribe(() => console.log(createUser.peek()));\n * const user = await createUser.mutate({ name: 'Ada' });\n *\n * // later:\n * createUser.dispose();\n * ```\n */\nexport function createMutation<TData, TVariables = void>(\n mutationFn: MutationFn<TData, TVariables>,\n mutOpts?: MutationOptions<TData, TVariables>,\n): Mutation<TData, TVariables> {\n let snap: MutationState<TData> = IDLE_STATE as MutationState<TData>;\n let currentRun = 0;\n let activeRun: { controller: AbortController; promise: Promise<unknown> } | null = null;\n const observers = new Set<() => void>();\n let disposed = false;\n let cachedStore: SyncStore<MutationState<TData>> | null = null;\n\n function notifyObservers(): void {\n observers.forEach((l) => l());\n }\n\n async function safeCall(fn: (() => void | Promise<void>) | undefined): Promise<void> {\n try {\n await fn?.();\n } catch (err) {\n if (mutOpts?.onCallbackError) {\n try {\n mutOpts.onCallbackError(err instanceof Error ? err : new Error(String(err)));\n } catch {\n // Silently ignore errors in error handler itself.\n }\n }\n }\n }\n\n return {\n async cancel(): Promise<void> {\n const run = activeRun;\n\n if (!run) return;\n\n run.controller.abort();\n await run.promise.catch(() => {});\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n activeRun?.controller.abort();\n activeRun = null;\n observers.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n /**\n * Execute the mutation with the given variables.\n *\n * Concurrent calls are allowed. State updates (`isFetching`, `data`, `error`) always\n * reflect the **latest** `mutate()` call. Lifecycle callbacks (`onSuccess`, `onError`,\n * `onSettled`) fire for **every** call independently — not just the last one.\n * Cancel earlier calls via `mutation.cancel()` if you need only-last-wins callback semantics.\n *\n * @throws {CourierDisposedError} If called after `dispose()`.\n */\n async mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData> {\n if (disposed) throw new CourierDisposedError('Mutation');\n\n const localController = new AbortController();\n\n const signal = callOpts?.signal ? anySignal(callOpts.signal, localController.signal)! : localController.signal;\n const run = ++currentRun;\n\n snap = {\n data: undefined,\n error: null,\n isFetching: true,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n };\n notifyObservers();\n\n const pendingRun = { controller: localController, promise: null as unknown as Promise<TData> };\n\n activeRun = pendingRun;\n\n const operation = (async () => {\n try {\n const data = await retry(() => mutationFn(variables, signal), {\n delay: (attempt) => resolveRetryDelay(attempt, mutOpts?.delay),\n shouldRetry: mutOpts?.shouldRetry,\n signal,\n times: mutOpts?.times ?? 1,\n });\n\n if (run === currentRun) {\n snap = { data, error: null, isFetching: false, isLoading: false, status: 'success', updatedAt: Date.now() };\n notifyObservers();\n }\n\n await safeCall(() => mutOpts?.onSuccess?.(data, variables));\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() => mutOpts?.onSettled?.({ data, status: 'success', variables }));\n\n return data;\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isAborted = signal.aborted || isAbortError(error);\n\n if (run === currentRun) {\n snap = isAborted\n ? (IDLE_STATE as MutationState<TData>)\n : { data: undefined, error, isFetching: false, isLoading: false, status: 'error', updatedAt: Date.now() };\n notifyObservers();\n }\n\n if (!isAborted) {\n await safeCall(() => mutOpts?.onError?.(error, variables));\n }\n\n await safeCall(() => mutOpts?.onFinally?.(variables));\n await safeCall(() =>\n mutOpts?.onSettled?.(isAborted ? { status: 'aborted', variables } : { error, status: 'error', variables }),\n );\n\n throw error;\n } finally {\n if (activeRun?.controller === localController) {\n activeRun = null;\n }\n }\n })();\n\n pendingRun.promise = operation;\n\n return operation;\n },\n\n /**\n * Read the current mutation state snapshot.\n * For framework integrations prefer `peek()` + `subscribe()` directly.\n */\n peek(): MutationState<TData> {\n return snap;\n },\n\n reset(): void {\n snap = IDLE_STATE as MutationState<TData>;\n notifyObservers();\n },\n\n /**\n * A `SyncStore` view of the mutation state — identical to `{ peek, subscribe }` on this object.\n * Provided for framework integrations that accept a `SyncStore` directly:\n * - React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n * - Svelte: `readable(mutation.peek(), mutation.subscribe)`\n */\n get store(): SyncStore<MutationState<TData>> {\n return (cachedStore ??= {\n peek: () => snap,\n subscribe: (cb) => {\n if (disposed) return () => {};\n\n observers.add(cb);\n\n return () => observers.delete(cb);\n },\n });\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n if (disposed) return () => {};\n\n observers.add(onStoreChange);\n\n return () => observers.delete(onStoreChange);\n },\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n };\n}\n\nexport interface Mutation<TData, TVariables = void> {\n [Symbol.dispose](): void;\n cancel(): Promise<void>;\n dispose(): void;\n get disposed(): boolean;\n mutate(variables: TVariables, callOpts?: { signal?: AbortSignal }): Promise<TData>;\n peek(): MutationState<TData>;\n reset(): void;\n /**\n * `SyncStore` adapter — equivalent to `{ peek, subscribe }` on this object.\n * For React: `useSyncExternalStore(mutation.subscribe, mutation.peek)`\n */\n get store(): SyncStore<MutationState<TData>>;\n subscribe(onStoreChange: () => void): Unsubscribe;\n}\n"],"mappings":"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"}
|
package/dist/query-observe.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./query-cache.cjs");var t=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!0,status:`loading`,updatedAt:void 0});function n(e){return e.status===`loading`?{data:void 0,error:null,isFetching:e.isFetching,isLoading:!0,status:`loading`,updatedAt:void 0}:e.status===`success`?{data:e.data,error:null,isFetching:e.isFetching,isLoading:!1,status:`success`,updatedAt:e.updatedAt}:{data:e.data,error:e.error,isFetching:e.isFetching,isLoading:!1,status:`error`,updatedAt:e.updatedAt}}function r(t,r){let i=n(t);if(i.status===`loading`){let t=e.resolveValue(r.placeholderData);return{...i,data:t}}let a=r.select?r.select(i.data):i.data;return{...i,data:a}}function i(e){for(let t of e.observers){let n=t,i=r(e,n),a=n.previous,o=Object.is(a?.data,i.data),s=!!a&&a.status===i.status&&a.isFetching===i.isFetching&&Object.is(a.error,i.error);(n.select?s&&o:s&&a?.updatedAt===i.updatedAt&&o)||(n.previous=i,n.listener())}}function a(n,i,a){let o={listener:()=>{},...a};return{peek(){let a=n.entries.get(e.hashKey(i));return a?r(a,o):t},subscribe(t){let s=e.ensureEntry(n,i);e.cancelGc(n,s.hash);let c={...a,listener:t,previous:r(s,o)};return s.observers.add(c),()=>{s.observers.delete(c),s.observers.size===0&&e.scheduleGc(n,s,s.lastConfig?.gcTime??n.gcTimeDefault)}}}}exports.notify=i,exports.toBaseState=n,exports.toObserverState=r,exports.watchInternal=a;
|
|
1
|
+
const e=require("./query-cache.cjs");var t=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!0,status:`loading`,updatedAt:void 0});function n(e){return e.status===`loading`?{data:void 0,error:null,isFetching:e.isFetching,isLoading:!0,status:`loading`,updatedAt:void 0}:e.status===`success`?{data:e.data,error:null,isFetching:e.isFetching,isLoading:!1,status:`success`,updatedAt:e.updatedAt}:{data:e.data,error:e.error,isFetching:e.isFetching,isLoading:!1,status:`error`,updatedAt:e.updatedAt}}function r(t,r){let i=n(t);if(i.status===`loading`){let t=e.resolveValue(r.placeholderData);return{...i,data:t}}let a=r.select?r.select(i.data):i.data;return{...i,data:a}}function i(e){for(let t of e.observers){let n=t,i=r(e,n),a=n.previous,o=Object.is(a?.data,i.data),s=!!a&&a.status===i.status&&a.isFetching===i.isFetching&&Object.is(a.error,i.error);(n.select?s&&o:s&&a?.updatedAt===i.updatedAt&&o)||(n.previous=i,n.listener())}}function a(n,i,a){let o={listener:()=>{},...a};return{peek(){let a=n.entries.get(e.hashKey(i));return a?r(a,o):t},subscribe(t){if(n.disposed)return()=>{};let s=e.ensureEntry(n,i);e.cancelGc(n,s.hash);let c={...a,listener:t,previous:r(s,o)};return s.observers.add(c),()=>{s.observers.delete(c),s.observers.size===0&&e.scheduleGc(n,s,s.lastConfig?.gcTime??n.gcTimeDefault)}}}}exports.notify=i,exports.toBaseState=n,exports.toObserverState=r,exports.watchInternal=a;
|
|
2
2
|
//# sourceMappingURL=query-observe.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-observe.cjs","names":[],"sources":["../src/query-observe.ts"],"sourcesContent":["import type { CacheContext, CacheEntry } from './query-cache';\nimport type { AsyncState, QueryState, SyncStore, Unsubscribe } from './types';\n\nimport { cancelGc, ensureEntry, hashKey, resolveValue, scheduleGc } from './query-cache';\n\nexport type QueryObserver<T, S> = {\n listener: () => void;\n placeholderData?: S | (() => S | undefined);\n previous?: QueryState<S>;\n select?: (data: T | undefined) => S | undefined;\n};\n\nconst LOADING_STATE: AsyncState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n});\n\nexport function toBaseState<T>(entry: CacheEntry<T>): QueryState<T> {\n if (entry.status === 'loading') {\n return {\n data: undefined,\n error: null,\n isFetching: entry.isFetching,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n } as QueryState<T>;\n }\n\n if (entry.status === 'success') {\n return {\n data: entry.data as T,\n error: null,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'success',\n updatedAt: entry.updatedAt as number,\n };\n }\n\n return {\n data: entry.data,\n error: entry.error as Error,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'error',\n updatedAt: entry.updatedAt as number,\n };\n}\n\nexport function toObserverState<T, S>(entry: CacheEntry<T>, observer: QueryObserver<T, S>): QueryState<S> {\n const base = toBaseState(entry);\n\n if (base.status === 'loading') {\n const placeholder = resolveValue(observer.placeholderData as S | (() => S | undefined) | undefined);\n\n return { ...base, data: placeholder } as QueryState<S>;\n }\n\n const selected = observer.select ? observer.select(base.data as T | undefined) : (base.data as S | undefined);\n\n return { ...base, data: selected } as QueryState<S>;\n}\n\nexport function notify<T>(entry: CacheEntry<T>): void {\n for (const observer of entry.observers) {\n const typed = observer as QueryObserver<T, unknown>;\n const next = toObserverState(entry, typed);\n const prev = typed.previous;\n\n const dataUnchanged = Object.is(prev?.data, next.data);\n const metaUnchanged =\n !!prev && prev.status === next.status && prev.isFetching === next.isFetching && Object.is(prev.error, next.error);\n\n const shouldSkip = typed.select\n ? metaUnchanged && dataUnchanged\n : metaUnchanged && prev?.updatedAt === next.updatedAt && dataUnchanged;\n\n if (shouldSkip) continue;\n\n typed.previous = next;\n typed.listener();\n }\n}\n\nexport function watchInternal<T = unknown, S = T>(\n ctx: CacheContext,\n key: Parameters<typeof ensureEntry>[1],\n opts?: { placeholderData?: S | (() => S | undefined); select?: (data: T | undefined) => S | undefined },\n): SyncStore<QueryState<S>> {\n const peekObserver: QueryObserver<T, S> = { listener: () => {}, ...opts };\n\n return {\n peek(): QueryState<S> {\n const entry = ctx.entries.get(hashKey(key)) as CacheEntry<T> | undefined;\n\n if (!entry) return LOADING_STATE as QueryState<S>;\n\n return toObserverState(entry, peekObserver);\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n const entry = ensureEntry<T>(ctx, key);\n\n cancelGc(ctx, entry.hash);\n\n const observer: QueryObserver<T, S> = {\n ...opts,\n listener: onStoreChange,\n previous: toObserverState(entry, peekObserver),\n };\n\n entry.observers.add(observer as QueryObserver<unknown, unknown>);\n\n return () => {\n entry.observers.delete(observer as QueryObserver<unknown, unknown>);\n\n if (entry.observers.size === 0) {\n scheduleGc(ctx, entry, entry.lastConfig?.gcTime ?? ctx.gcTimeDefault);\n }\n };\n },\n };\n}\n"],"mappings":"qCAYA,IAAM,EAAqC,OAAO,OAAO,CACvD,KAAM,IAAA,GACN,MAAO,KACP,WAAY,GACZ,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,CAAC,EAED,SAAgB,EAAe,EAAqC,CAuBlE,OAtBI,EAAM,SAAW,UACZ,CACL,KAAM,IAAA,GACN,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,EAGE,EAAM,SAAW,UACZ,CACL,KAAM,EAAM,KACZ,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,EAAM,SACnB,EAGK,CACL,KAAM,EAAM,KACZ,MAAO,EAAM,MACb,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,QACR,UAAW,EAAM,SACnB,CACF,CAEA,SAAgB,EAAsB,EAAsB,EAA8C,CACxG,IAAM,EAAO,EAAY,CAAK,EAE9B,GAAI,EAAK,SAAW,UAAW,CAC7B,IAAM,EAAc,EAAA,aAAa,EAAS,eAAwD,EAElG,MAAO,CAAE,GAAG,EAAM,KAAM,CAAY,CACtC,CAEA,IAAM,EAAW,EAAS,OAAS,EAAS,OAAO,EAAK,IAAqB,EAAK,EAAK,KAEvF,MAAO,CAAE,GAAG,EAAM,KAAM,CAAS,CACnC,CAEA,SAAgB,EAAU,EAA4B,CACpD,IAAK,IAAM,KAAY,EAAM,UAAW,CACtC,IAAM,EAAQ,EACR,EAAO,EAAgB,EAAO,CAAK,EACnC,EAAO,EAAM,SAEb,EAAgB,OAAO,GAAG,GAAM,KAAM,EAAK,IAAI,EAC/C,EACJ,CAAC,CAAC,GAAQ,EAAK,SAAW,EAAK,QAAU,EAAK,aAAe,EAAK,YAAc,OAAO,GAAG,EAAK,MAAO,EAAK,KAAK,GAE/F,EAAM,OACrB,GAAiB,EACjB,GAAiB,GAAM,YAAc,EAAK,WAAa,KAI3D,EAAM,SAAW,EACjB,EAAM,SAAS,EACjB,CACF,CAEA,SAAgB,EACd,EACA,EACA,EAC0B,CAC1B,IAAM,EAAoC,CAAE,aAAgB,CAAC,EAAG,GAAG,CAAK,EAExE,MAAO,CACL,MAAsB,CACpB,IAAM,EAAQ,EAAI,QAAQ,IAAI,EAAA,QAAQ,CAAG,CAAC,EAI1C,OAFK,EAEE,EAAgB,EAAO,CAAY,EAFvB,CAGrB,EAEA,UAAU,EAAwC,CAChD,IAAM,EAAQ,EAAA,YAAe,EAAK,CAAG,EAErC,EAAA,SAAS,EAAK,EAAM,IAAI,EAExB,IAAM,EAAgC,CACpC,GAAG,EACH,SAAU,EACV,SAAU,EAAgB,EAAO,CAAY,CAC/C,EAIA,OAFA,EAAM,UAAU,IAAI,CAA2C,MAElD,CACX,EAAM,UAAU,OAAO,CAA2C,EAE9D,EAAM,UAAU,OAAS,GAC3B,EAAA,WAAW,EAAK,EAAO,EAAM,YAAY,QAAU,EAAI,aAAa,CAExE,CACF,CACF,CACF"}
|
|
1
|
+
{"version":3,"file":"query-observe.cjs","names":[],"sources":["../src/query-observe.ts"],"sourcesContent":["import type { CacheContext, CacheEntry } from './query-cache';\nimport type { AsyncState, QueryState, SyncStore, Unsubscribe } from './types';\n\nimport { cancelGc, ensureEntry, hashKey, resolveValue, scheduleGc } from './query-cache';\n\nexport type QueryObserver<T, S> = {\n listener: () => void;\n placeholderData?: S | (() => S | undefined);\n previous?: QueryState<S>;\n select?: (data: T | undefined) => S | undefined;\n};\n\nconst LOADING_STATE: AsyncState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n});\n\nexport function toBaseState<T>(entry: CacheEntry<T>): QueryState<T> {\n if (entry.status === 'loading') {\n return {\n data: undefined,\n error: null,\n isFetching: entry.isFetching,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n } as QueryState<T>;\n }\n\n if (entry.status === 'success') {\n return {\n data: entry.data as T,\n error: null,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'success',\n updatedAt: entry.updatedAt as number,\n };\n }\n\n return {\n data: entry.data,\n error: entry.error as Error,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'error',\n updatedAt: entry.updatedAt as number,\n };\n}\n\nexport function toObserverState<T, S>(entry: CacheEntry<T>, observer: QueryObserver<T, S>): QueryState<S> {\n const base = toBaseState(entry);\n\n if (base.status === 'loading') {\n const placeholder = resolveValue(observer.placeholderData as S | (() => S | undefined) | undefined);\n\n return { ...base, data: placeholder } as QueryState<S>;\n }\n\n const selected = observer.select ? observer.select(base.data as T | undefined) : (base.data as S | undefined);\n\n return { ...base, data: selected } as QueryState<S>;\n}\n\nexport function notify<T>(entry: CacheEntry<T>): void {\n for (const observer of entry.observers) {\n const typed = observer as QueryObserver<T, unknown>;\n const next = toObserverState(entry, typed);\n const prev = typed.previous;\n\n const dataUnchanged = Object.is(prev?.data, next.data);\n const metaUnchanged =\n !!prev && prev.status === next.status && prev.isFetching === next.isFetching && Object.is(prev.error, next.error);\n\n const shouldSkip = typed.select\n ? metaUnchanged && dataUnchanged\n : metaUnchanged && prev?.updatedAt === next.updatedAt && dataUnchanged;\n\n if (shouldSkip) continue;\n\n typed.previous = next;\n typed.listener();\n }\n}\n\nexport function watchInternal<T = unknown, S = T>(\n ctx: CacheContext,\n key: Parameters<typeof ensureEntry>[1],\n opts?: { placeholderData?: S | (() => S | undefined); select?: (data: T | undefined) => S | undefined },\n): SyncStore<QueryState<S>> {\n const peekObserver: QueryObserver<T, S> = { listener: () => {}, ...opts };\n\n return {\n peek(): QueryState<S> {\n const entry = ctx.entries.get(hashKey(key)) as CacheEntry<T> | undefined;\n\n if (!entry) return LOADING_STATE as QueryState<S>;\n\n return toObserverState(entry, peekObserver);\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n if (ctx.disposed) return () => {};\n\n const entry = ensureEntry<T>(ctx, key);\n\n cancelGc(ctx, entry.hash);\n\n const observer: QueryObserver<T, S> = {\n ...opts,\n listener: onStoreChange,\n previous: toObserverState(entry, peekObserver),\n };\n\n entry.observers.add(observer as QueryObserver<unknown, unknown>);\n\n return () => {\n entry.observers.delete(observer as QueryObserver<unknown, unknown>);\n\n if (entry.observers.size === 0) {\n scheduleGc(ctx, entry, entry.lastConfig?.gcTime ?? ctx.gcTimeDefault);\n }\n };\n },\n };\n}\n"],"mappings":"qCAYA,IAAM,EAAqC,OAAO,OAAO,CACvD,KAAM,IAAA,GACN,MAAO,KACP,WAAY,GACZ,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,CAAC,EAED,SAAgB,EAAe,EAAqC,CAuBlE,OAtBI,EAAM,SAAW,UACZ,CACL,KAAM,IAAA,GACN,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,EAGE,EAAM,SAAW,UACZ,CACL,KAAM,EAAM,KACZ,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,EAAM,SACnB,EAGK,CACL,KAAM,EAAM,KACZ,MAAO,EAAM,MACb,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,QACR,UAAW,EAAM,SACnB,CACF,CAEA,SAAgB,EAAsB,EAAsB,EAA8C,CACxG,IAAM,EAAO,EAAY,CAAK,EAE9B,GAAI,EAAK,SAAW,UAAW,CAC7B,IAAM,EAAc,EAAA,aAAa,EAAS,eAAwD,EAElG,MAAO,CAAE,GAAG,EAAM,KAAM,CAAY,CACtC,CAEA,IAAM,EAAW,EAAS,OAAS,EAAS,OAAO,EAAK,IAAqB,EAAK,EAAK,KAEvF,MAAO,CAAE,GAAG,EAAM,KAAM,CAAS,CACnC,CAEA,SAAgB,EAAU,EAA4B,CACpD,IAAK,IAAM,KAAY,EAAM,UAAW,CACtC,IAAM,EAAQ,EACR,EAAO,EAAgB,EAAO,CAAK,EACnC,EAAO,EAAM,SAEb,EAAgB,OAAO,GAAG,GAAM,KAAM,EAAK,IAAI,EAC/C,EACJ,CAAC,CAAC,GAAQ,EAAK,SAAW,EAAK,QAAU,EAAK,aAAe,EAAK,YAAc,OAAO,GAAG,EAAK,MAAO,EAAK,KAAK,GAE/F,EAAM,OACrB,GAAiB,EACjB,GAAiB,GAAM,YAAc,EAAK,WAAa,KAI3D,EAAM,SAAW,EACjB,EAAM,SAAS,EACjB,CACF,CAEA,SAAgB,EACd,EACA,EACA,EAC0B,CAC1B,IAAM,EAAoC,CAAE,aAAgB,CAAC,EAAG,GAAG,CAAK,EAExE,MAAO,CACL,MAAsB,CACpB,IAAM,EAAQ,EAAI,QAAQ,IAAI,EAAA,QAAQ,CAAG,CAAC,EAI1C,OAFK,EAEE,EAAgB,EAAO,CAAY,EAFvB,CAGrB,EAEA,UAAU,EAAwC,CAChD,GAAI,EAAI,SAAU,UAAa,CAAC,EAEhC,IAAM,EAAQ,EAAA,YAAe,EAAK,CAAG,EAErC,EAAA,SAAS,EAAK,EAAM,IAAI,EAExB,IAAM,EAAgC,CACpC,GAAG,EACH,SAAU,EACV,SAAU,EAAgB,EAAO,CAAY,CAC/C,EAIA,OAFA,EAAM,UAAU,IAAI,CAA2C,MAElD,CACX,EAAM,UAAU,OAAO,CAA2C,EAE9D,EAAM,UAAU,OAAS,GAC3B,EAAA,WAAW,EAAK,EAAO,EAAM,YAAY,QAAU,EAAI,aAAa,CAExE,CACF,CACF,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-observe.d.ts","sourceRoot":"","sources":["../src/query-observe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAc,UAAU,EAAE,SAAS,EAAe,MAAM,SAAS,CAAC;AAE9E,OAAO,EAAY,WAAW,EAAqC,MAAM,eAAe,CAAC;AAEzF,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,SAAS,CAAC;CACjD,CAAC;AAWF,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CA+BlE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAYxG;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAmBpD;AAED,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,CAAC,EAC9C,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EACtC,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,SAAS,CAAA;CAAE,GACtG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"query-observe.d.ts","sourceRoot":"","sources":["../src/query-observe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,KAAK,EAAc,UAAU,EAAE,SAAS,EAAe,MAAM,SAAS,CAAC;AAE9E,OAAO,EAAY,WAAW,EAAqC,MAAM,eAAe,CAAC;AAEzF,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IAC5C,QAAQ,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,SAAS,CAAC;CACjD,CAAC;AAWF,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CA+BlE;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAYxG;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAmBpD;AAED,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,CAAC,EAC9C,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,EACtC,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,SAAS,KAAK,CAAC,GAAG,SAAS,CAAA;CAAE,GACtG,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAoC1B"}
|
package/dist/query-observe.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{cancelGc as e,ensureEntry as t,hashKey as n,resolveValue as r,scheduleGc as i}from"./query-cache.js";var a=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!0,status:`loading`,updatedAt:void 0});function o(e){return e.status===`loading`?{data:void 0,error:null,isFetching:e.isFetching,isLoading:!0,status:`loading`,updatedAt:void 0}:e.status===`success`?{data:e.data,error:null,isFetching:e.isFetching,isLoading:!1,status:`success`,updatedAt:e.updatedAt}:{data:e.data,error:e.error,isFetching:e.isFetching,isLoading:!1,status:`error`,updatedAt:e.updatedAt}}function s(e,t){let n=o(e);if(n.status===`loading`){let e=r(t.placeholderData);return{...n,data:e}}let i=t.select?t.select(n.data):n.data;return{...n,data:i}}function c(e){for(let t of e.observers){let n=t,r=s(e,n),i=n.previous,a=Object.is(i?.data,r.data),o=!!i&&i.status===r.status&&i.isFetching===r.isFetching&&Object.is(i.error,r.error);(n.select?o&&a:o&&i?.updatedAt===r.updatedAt&&a)||(n.previous=r,n.listener())}}function l(r,o,c){let l={listener:()=>{},...c};return{peek(){let e=r.entries.get(n(o));return e?s(e,l):a},subscribe(n){let a=t(r,o);e(r,a.hash);let u={...c,listener:n,previous:s(a,l)};return a.observers.add(u),()=>{a.observers.delete(u),a.observers.size===0&&i(r,a,a.lastConfig?.gcTime??r.gcTimeDefault)}}}}export{c as notify,o as toBaseState,s as toObserverState,l as watchInternal};
|
|
1
|
+
import{cancelGc as e,ensureEntry as t,hashKey as n,resolveValue as r,scheduleGc as i}from"./query-cache.js";var a=Object.freeze({data:void 0,error:null,isFetching:!1,isLoading:!0,status:`loading`,updatedAt:void 0});function o(e){return e.status===`loading`?{data:void 0,error:null,isFetching:e.isFetching,isLoading:!0,status:`loading`,updatedAt:void 0}:e.status===`success`?{data:e.data,error:null,isFetching:e.isFetching,isLoading:!1,status:`success`,updatedAt:e.updatedAt}:{data:e.data,error:e.error,isFetching:e.isFetching,isLoading:!1,status:`error`,updatedAt:e.updatedAt}}function s(e,t){let n=o(e);if(n.status===`loading`){let e=r(t.placeholderData);return{...n,data:e}}let i=t.select?t.select(n.data):n.data;return{...n,data:i}}function c(e){for(let t of e.observers){let n=t,r=s(e,n),i=n.previous,a=Object.is(i?.data,r.data),o=!!i&&i.status===r.status&&i.isFetching===r.isFetching&&Object.is(i.error,r.error);(n.select?o&&a:o&&i?.updatedAt===r.updatedAt&&a)||(n.previous=r,n.listener())}}function l(r,o,c){let l={listener:()=>{},...c};return{peek(){let e=r.entries.get(n(o));return e?s(e,l):a},subscribe(n){if(r.disposed)return()=>{};let a=t(r,o);e(r,a.hash);let u={...c,listener:n,previous:s(a,l)};return a.observers.add(u),()=>{a.observers.delete(u),a.observers.size===0&&i(r,a,a.lastConfig?.gcTime??r.gcTimeDefault)}}}}export{c as notify,o as toBaseState,s as toObserverState,l as watchInternal};
|
|
2
2
|
//# sourceMappingURL=query-observe.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-observe.js","names":[],"sources":["../src/query-observe.ts"],"sourcesContent":["import type { CacheContext, CacheEntry } from './query-cache';\nimport type { AsyncState, QueryState, SyncStore, Unsubscribe } from './types';\n\nimport { cancelGc, ensureEntry, hashKey, resolveValue, scheduleGc } from './query-cache';\n\nexport type QueryObserver<T, S> = {\n listener: () => void;\n placeholderData?: S | (() => S | undefined);\n previous?: QueryState<S>;\n select?: (data: T | undefined) => S | undefined;\n};\n\nconst LOADING_STATE: AsyncState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n});\n\nexport function toBaseState<T>(entry: CacheEntry<T>): QueryState<T> {\n if (entry.status === 'loading') {\n return {\n data: undefined,\n error: null,\n isFetching: entry.isFetching,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n } as QueryState<T>;\n }\n\n if (entry.status === 'success') {\n return {\n data: entry.data as T,\n error: null,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'success',\n updatedAt: entry.updatedAt as number,\n };\n }\n\n return {\n data: entry.data,\n error: entry.error as Error,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'error',\n updatedAt: entry.updatedAt as number,\n };\n}\n\nexport function toObserverState<T, S>(entry: CacheEntry<T>, observer: QueryObserver<T, S>): QueryState<S> {\n const base = toBaseState(entry);\n\n if (base.status === 'loading') {\n const placeholder = resolveValue(observer.placeholderData as S | (() => S | undefined) | undefined);\n\n return { ...base, data: placeholder } as QueryState<S>;\n }\n\n const selected = observer.select ? observer.select(base.data as T | undefined) : (base.data as S | undefined);\n\n return { ...base, data: selected } as QueryState<S>;\n}\n\nexport function notify<T>(entry: CacheEntry<T>): void {\n for (const observer of entry.observers) {\n const typed = observer as QueryObserver<T, unknown>;\n const next = toObserverState(entry, typed);\n const prev = typed.previous;\n\n const dataUnchanged = Object.is(prev?.data, next.data);\n const metaUnchanged =\n !!prev && prev.status === next.status && prev.isFetching === next.isFetching && Object.is(prev.error, next.error);\n\n const shouldSkip = typed.select\n ? metaUnchanged && dataUnchanged\n : metaUnchanged && prev?.updatedAt === next.updatedAt && dataUnchanged;\n\n if (shouldSkip) continue;\n\n typed.previous = next;\n typed.listener();\n }\n}\n\nexport function watchInternal<T = unknown, S = T>(\n ctx: CacheContext,\n key: Parameters<typeof ensureEntry>[1],\n opts?: { placeholderData?: S | (() => S | undefined); select?: (data: T | undefined) => S | undefined },\n): SyncStore<QueryState<S>> {\n const peekObserver: QueryObserver<T, S> = { listener: () => {}, ...opts };\n\n return {\n peek(): QueryState<S> {\n const entry = ctx.entries.get(hashKey(key)) as CacheEntry<T> | undefined;\n\n if (!entry) return LOADING_STATE as QueryState<S>;\n\n return toObserverState(entry, peekObserver);\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n const entry = ensureEntry<T>(ctx, key);\n\n cancelGc(ctx, entry.hash);\n\n const observer: QueryObserver<T, S> = {\n ...opts,\n listener: onStoreChange,\n previous: toObserverState(entry, peekObserver),\n };\n\n entry.observers.add(observer as QueryObserver<unknown, unknown>);\n\n return () => {\n entry.observers.delete(observer as QueryObserver<unknown, unknown>);\n\n if (entry.observers.size === 0) {\n scheduleGc(ctx, entry, entry.lastConfig?.gcTime ?? ctx.gcTimeDefault);\n }\n };\n },\n };\n}\n"],"mappings":"4GAYA,IAAM,EAAqC,OAAO,OAAO,CACvD,KAAM,IAAA,GACN,MAAO,KACP,WAAY,GACZ,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,CAAC,EAED,SAAgB,EAAe,EAAqC,CAuBlE,OAtBI,EAAM,SAAW,UACZ,CACL,KAAM,IAAA,GACN,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,EAGE,EAAM,SAAW,UACZ,CACL,KAAM,EAAM,KACZ,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,EAAM,SACnB,EAGK,CACL,KAAM,EAAM,KACZ,MAAO,EAAM,MACb,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,QACR,UAAW,EAAM,SACnB,CACF,CAEA,SAAgB,EAAsB,EAAsB,EAA8C,CACxG,IAAM,EAAO,EAAY,CAAK,EAE9B,GAAI,EAAK,SAAW,UAAW,CAC7B,IAAM,EAAc,EAAa,EAAS,eAAwD,EAElG,MAAO,CAAE,GAAG,EAAM,KAAM,CAAY,CACtC,CAEA,IAAM,EAAW,EAAS,OAAS,EAAS,OAAO,EAAK,IAAqB,EAAK,EAAK,KAEvF,MAAO,CAAE,GAAG,EAAM,KAAM,CAAS,CACnC,CAEA,SAAgB,EAAU,EAA4B,CACpD,IAAK,IAAM,KAAY,EAAM,UAAW,CACtC,IAAM,EAAQ,EACR,EAAO,EAAgB,EAAO,CAAK,EACnC,EAAO,EAAM,SAEb,EAAgB,OAAO,GAAG,GAAM,KAAM,EAAK,IAAI,EAC/C,EACJ,CAAC,CAAC,GAAQ,EAAK,SAAW,EAAK,QAAU,EAAK,aAAe,EAAK,YAAc,OAAO,GAAG,EAAK,MAAO,EAAK,KAAK,GAE/F,EAAM,OACrB,GAAiB,EACjB,GAAiB,GAAM,YAAc,EAAK,WAAa,KAI3D,EAAM,SAAW,EACjB,EAAM,SAAS,EACjB,CACF,CAEA,SAAgB,EACd,EACA,EACA,EAC0B,CAC1B,IAAM,EAAoC,CAAE,aAAgB,CAAC,EAAG,GAAG,CAAK,EAExE,MAAO,CACL,MAAsB,CACpB,IAAM,EAAQ,EAAI,QAAQ,IAAI,EAAQ,CAAG,CAAC,EAI1C,OAFK,EAEE,EAAgB,EAAO,CAAY,EAFvB,CAGrB,EAEA,UAAU,EAAwC,CAChD,IAAM,EAAQ,EAAe,EAAK,CAAG,EAErC,EAAS,EAAK,EAAM,IAAI,EAExB,IAAM,EAAgC,CACpC,GAAG,EACH,SAAU,EACV,SAAU,EAAgB,EAAO,CAAY,CAC/C,EAIA,OAFA,EAAM,UAAU,IAAI,CAA2C,MAElD,CACX,EAAM,UAAU,OAAO,CAA2C,EAE9D,EAAM,UAAU,OAAS,GAC3B,EAAW,EAAK,EAAO,EAAM,YAAY,QAAU,EAAI,aAAa,CAExE,CACF,CACF,CACF"}
|
|
1
|
+
{"version":3,"file":"query-observe.js","names":[],"sources":["../src/query-observe.ts"],"sourcesContent":["import type { CacheContext, CacheEntry } from './query-cache';\nimport type { AsyncState, QueryState, SyncStore, Unsubscribe } from './types';\n\nimport { cancelGc, ensureEntry, hashKey, resolveValue, scheduleGc } from './query-cache';\n\nexport type QueryObserver<T, S> = {\n listener: () => void;\n placeholderData?: S | (() => S | undefined);\n previous?: QueryState<S>;\n select?: (data: T | undefined) => S | undefined;\n};\n\nconst LOADING_STATE: AsyncState<unknown> = Object.freeze({\n data: undefined,\n error: null,\n isFetching: false,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n});\n\nexport function toBaseState<T>(entry: CacheEntry<T>): QueryState<T> {\n if (entry.status === 'loading') {\n return {\n data: undefined,\n error: null,\n isFetching: entry.isFetching,\n isLoading: true,\n status: 'loading',\n updatedAt: undefined,\n } as QueryState<T>;\n }\n\n if (entry.status === 'success') {\n return {\n data: entry.data as T,\n error: null,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'success',\n updatedAt: entry.updatedAt as number,\n };\n }\n\n return {\n data: entry.data,\n error: entry.error as Error,\n isFetching: entry.isFetching,\n isLoading: false,\n status: 'error',\n updatedAt: entry.updatedAt as number,\n };\n}\n\nexport function toObserverState<T, S>(entry: CacheEntry<T>, observer: QueryObserver<T, S>): QueryState<S> {\n const base = toBaseState(entry);\n\n if (base.status === 'loading') {\n const placeholder = resolveValue(observer.placeholderData as S | (() => S | undefined) | undefined);\n\n return { ...base, data: placeholder } as QueryState<S>;\n }\n\n const selected = observer.select ? observer.select(base.data as T | undefined) : (base.data as S | undefined);\n\n return { ...base, data: selected } as QueryState<S>;\n}\n\nexport function notify<T>(entry: CacheEntry<T>): void {\n for (const observer of entry.observers) {\n const typed = observer as QueryObserver<T, unknown>;\n const next = toObserverState(entry, typed);\n const prev = typed.previous;\n\n const dataUnchanged = Object.is(prev?.data, next.data);\n const metaUnchanged =\n !!prev && prev.status === next.status && prev.isFetching === next.isFetching && Object.is(prev.error, next.error);\n\n const shouldSkip = typed.select\n ? metaUnchanged && dataUnchanged\n : metaUnchanged && prev?.updatedAt === next.updatedAt && dataUnchanged;\n\n if (shouldSkip) continue;\n\n typed.previous = next;\n typed.listener();\n }\n}\n\nexport function watchInternal<T = unknown, S = T>(\n ctx: CacheContext,\n key: Parameters<typeof ensureEntry>[1],\n opts?: { placeholderData?: S | (() => S | undefined); select?: (data: T | undefined) => S | undefined },\n): SyncStore<QueryState<S>> {\n const peekObserver: QueryObserver<T, S> = { listener: () => {}, ...opts };\n\n return {\n peek(): QueryState<S> {\n const entry = ctx.entries.get(hashKey(key)) as CacheEntry<T> | undefined;\n\n if (!entry) return LOADING_STATE as QueryState<S>;\n\n return toObserverState(entry, peekObserver);\n },\n\n subscribe(onStoreChange: () => void): Unsubscribe {\n if (ctx.disposed) return () => {};\n\n const entry = ensureEntry<T>(ctx, key);\n\n cancelGc(ctx, entry.hash);\n\n const observer: QueryObserver<T, S> = {\n ...opts,\n listener: onStoreChange,\n previous: toObserverState(entry, peekObserver),\n };\n\n entry.observers.add(observer as QueryObserver<unknown, unknown>);\n\n return () => {\n entry.observers.delete(observer as QueryObserver<unknown, unknown>);\n\n if (entry.observers.size === 0) {\n scheduleGc(ctx, entry, entry.lastConfig?.gcTime ?? ctx.gcTimeDefault);\n }\n };\n },\n };\n}\n"],"mappings":"4GAYA,IAAM,EAAqC,OAAO,OAAO,CACvD,KAAM,IAAA,GACN,MAAO,KACP,WAAY,GACZ,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,CAAC,EAED,SAAgB,EAAe,EAAqC,CAuBlE,OAtBI,EAAM,SAAW,UACZ,CACL,KAAM,IAAA,GACN,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,IAAA,EACb,EAGE,EAAM,SAAW,UACZ,CACL,KAAM,EAAM,KACZ,MAAO,KACP,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,UACR,UAAW,EAAM,SACnB,EAGK,CACL,KAAM,EAAM,KACZ,MAAO,EAAM,MACb,WAAY,EAAM,WAClB,UAAW,GACX,OAAQ,QACR,UAAW,EAAM,SACnB,CACF,CAEA,SAAgB,EAAsB,EAAsB,EAA8C,CACxG,IAAM,EAAO,EAAY,CAAK,EAE9B,GAAI,EAAK,SAAW,UAAW,CAC7B,IAAM,EAAc,EAAa,EAAS,eAAwD,EAElG,MAAO,CAAE,GAAG,EAAM,KAAM,CAAY,CACtC,CAEA,IAAM,EAAW,EAAS,OAAS,EAAS,OAAO,EAAK,IAAqB,EAAK,EAAK,KAEvF,MAAO,CAAE,GAAG,EAAM,KAAM,CAAS,CACnC,CAEA,SAAgB,EAAU,EAA4B,CACpD,IAAK,IAAM,KAAY,EAAM,UAAW,CACtC,IAAM,EAAQ,EACR,EAAO,EAAgB,EAAO,CAAK,EACnC,EAAO,EAAM,SAEb,EAAgB,OAAO,GAAG,GAAM,KAAM,EAAK,IAAI,EAC/C,EACJ,CAAC,CAAC,GAAQ,EAAK,SAAW,EAAK,QAAU,EAAK,aAAe,EAAK,YAAc,OAAO,GAAG,EAAK,MAAO,EAAK,KAAK,GAE/F,EAAM,OACrB,GAAiB,EACjB,GAAiB,GAAM,YAAc,EAAK,WAAa,KAI3D,EAAM,SAAW,EACjB,EAAM,SAAS,EACjB,CACF,CAEA,SAAgB,EACd,EACA,EACA,EAC0B,CAC1B,IAAM,EAAoC,CAAE,aAAgB,CAAC,EAAG,GAAG,CAAK,EAExE,MAAO,CACL,MAAsB,CACpB,IAAM,EAAQ,EAAI,QAAQ,IAAI,EAAQ,CAAG,CAAC,EAI1C,OAFK,EAEE,EAAgB,EAAO,CAAY,EAFvB,CAGrB,EAEA,UAAU,EAAwC,CAChD,GAAI,EAAI,SAAU,UAAa,CAAC,EAEhC,IAAM,EAAQ,EAAe,EAAK,CAAG,EAErC,EAAS,EAAK,EAAM,IAAI,EAExB,IAAM,EAAgC,CACpC,GAAG,EACH,SAAU,EACV,SAAU,EAAgB,EAAO,CAAY,CAC/C,EAIA,OAFA,EAAM,UAAU,IAAI,CAA2C,MAElD,CACX,EAAM,UAAU,OAAO,CAA2C,EAE9D,EAAM,UAAU,OAAS,GAC3B,EAAW,EAAK,EAAO,EAAM,YAAY,QAAU,EAAI,aAAa,CAExE,CACF,CACF,CACF"}
|