@ethlete/query 6.0.0-next.62 → 6.0.0-next.63

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/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @ethlete/query
2
2
 
3
+ ## 6.0.0-next.63
4
+
5
+ ### Minor Changes
6
+
7
+ - `provideQueryDevtools({ ui: () => import('@ethlete/query-devtools/lazy') })` mounts the devtools once the app has rendered, with no template tag. `@ethlete/query-devtools/lazy` exports `mountQueryDevtools`.
8
+ - The `migrate-from-ngrx-toolkit` generator rewrites `facade.on(x.success)` on a migrated facade to `toolkitOnSuccess(x)`.
9
+ - The ngrx-toolkit interop adds `toolkitOnSuccess(creatorOrCreators)`, which emits the response on every success of a `toolkitCall` handle of those creators - the replacement for `facade.on(action.success)`.
10
+
11
+ ### Patch Changes
12
+
13
+ - `migrate-to-query-v3` writes `provideQueryDevtools({ ui })` and removes the v2 devtools tag and component import. Without a legacy provider call it still switches to the lazy component.
14
+ - The ET800 error names the query's route and says that repeated `execute({ skipCache: true })` calls count, e.g. a test that fakes responses in a tight loop.
15
+ - The v3 migration names every `gqlQuery` and `gqlMutate` call in a task, also on an aliased client, in a class property or
16
+ inside a function, and warns about the implicit-any errors (TS7006) they leave.
17
+ - A legacy `prepare()` on `createLegacyQueryCreator` queries now honours its `mock` argument: the query settles with the mock response or error after the delay and reports its progress.
18
+ - A legacy query from `createLegacyQueryCreator` types `rawState` with the response of the wrapped creator again, not `unknown`. Templates that read it, such as `*etInfinityQuery`, typecheck again.
19
+ - A subscriber that attaches to a legacy query's `state$` right after `execute()` no longer receives the previous `Success` after `Loading`, so `filterSuccess(), take(1)` waits for the new response.
20
+ - The query v3 migration now casts the `responseAdapter` result in the scaffolded `extractTokens`, so the generated code no longer fails with TS2339 on `token`.
21
+ - The `migrate-to-query-v3` report now flags a legacy `<et-query-devtools>`, `QueryDevtoolsComponent` or `provideQueryClientForDevtools` that the migration left behind.
22
+ - The `migrate-from-ngrx-toolkit` generator no longer leaves a whole consumer file on the toolkit when it also names converted creators.
23
+ - `migrate-from-ngrx-toolkit` reuses a creator whose args name the same branded type, and `NTK-DUPLICATE-ROUTE-MISMATCH` names the member that differs and where both types are declared.
24
+ - The `NTK-SERVICE-HEADERS` task of the `migrate-from-ngrx-toolkit` generator now names the headers, the service property they come from, and the condition the service set them under, with the line of the request.
25
+ - The `migrate-from-ngrx-toolkit` generator no longer keeps a whole feature store when code outside the feature uses only its service. It keeps the used file and the store files it imports, converts the rest, and names each kept file in `NTK-STORE-FILE-KEPT`.
26
+ - `migrate-from-ngrx-toolkit`: `NTK-MODULE-RESOLUTION` now also flags a project that resolves modules with `node` and reaches a file importing `@ethlete/query/ngrx-toolkit` through a workspace `paths` alias, and names that alias.
27
+ - `migrate-from-ngrx-toolkit` records an `NTK-MODULE-RESOLUTION` task for each project tsconfig that resolves modules with `node`, which cannot find `@ethlete/query/ngrx-toolkit`.
28
+ - `migrate-to-query-v3` now migrates a creator declared next to its client, adds `destroyOnResponse` to `prepare()` inside async validators returned by a factory, and drops imports the devtools and `queryComputed` rewrites leave unused.
29
+ - `migrate-to-query-v3` reports every tsconfig that resolves modules with `node` while its project imports an `@ethlete/*` subpath such as `@ethlete/query-devtools/lazy`, directly or through a `paths` alias.
30
+
3
31
  ## 6.0.0-next.62
4
32
 
5
33
  ### Patch Changes
@@ -229,7 +229,7 @@ const toQueryArgs = (args) => {
229
229
  if (actionOptions?.headers !== void 0) queryArgs["headers"] = actionOptions.headers;
230
230
  return queryArgs;
231
231
  };
232
- const createToolkitHandle = (creator, injector) => {
232
+ const createToolkitHandle = (creator, injector, onSuccess) => {
233
233
  const query = creator({
234
234
  injector,
235
235
  onlyManualExecution: true,
@@ -254,9 +254,17 @@ const createToolkitHandle = (creator, injector) => {
254
254
  };
255
255
  }, ...ngDevMode ? [{ debugName: "snapshot" }] : /* istanbul ignore next */ []);
256
256
  const changes = new Subject();
257
+ let lastSuccess = null;
257
258
  const changesEffect = effect(() => {
258
259
  const current = snapshot();
259
- untracked(() => changes.next(current));
260
+ const state = query.executionState();
261
+ untracked(() => {
262
+ changes.next(current);
263
+ if (current.callState === CallState.SUCCESS && state !== lastSuccess) {
264
+ lastSuccess = state;
265
+ onSuccess(current.response);
266
+ }
267
+ });
260
268
  }, {
261
269
  ...ngDevMode ? { debugName: "changesEffect" } : /* istanbul ignore next */ {},
262
270
  injector
@@ -367,18 +375,29 @@ const resolveEnvironmentInjector = (fn, options) => {
367
375
  assertInInjectionContext(fn);
368
376
  return inject(EnvironmentInjector);
369
377
  };
370
- const resolveEntry = (creator, args, injector) => {
378
+ const registryOf = (injector) => {
371
379
  let registry = registries.get(injector);
372
380
  if (!registry) {
381
+ const successes = new Subject();
373
382
  registry = {
374
383
  shared: /* @__PURE__ */ new WeakMap(),
375
- latestUnshared: /* @__PURE__ */ new WeakMap()
384
+ latestUnshared: /* @__PURE__ */ new WeakMap(),
385
+ successes
376
386
  };
377
387
  registries.set(injector, registry);
388
+ injector.get(DestroyRef).onDestroy(() => successes.complete());
378
389
  }
390
+ return registry;
391
+ };
392
+ const handleFor = (creator, injector, registry) => createToolkitHandle(creator, injector, (response) => registry.successes.next({
393
+ creator,
394
+ response
395
+ }));
396
+ const resolveEntry = (creator, args, injector) => {
397
+ const registry = registryOf(injector);
379
398
  const key = hashArgs(toQueryArgs(args));
380
399
  if (key === null) {
381
- const entry = createToolkitHandle(creator, injector);
400
+ const entry = handleFor(creator, injector, registry);
382
401
  registry.latestUnshared.get(creator)?.releaseWhenSettled();
383
402
  registry.latestUnshared.set(creator, entry);
384
403
  return entry;
@@ -390,7 +409,7 @@ const resolveEntry = (creator, args, injector) => {
390
409
  }
391
410
  let entry = entries.get(key);
392
411
  if (!entry) {
393
- entry = createToolkitHandle(creator, injector);
412
+ entry = handleFor(creator, injector, registry);
394
413
  entries.set(key, entry);
395
414
  }
396
415
  return entry;
@@ -401,11 +420,15 @@ const toolkitCall = (creator, args, options) => {
401
420
  entry.call(args);
402
421
  return entry.handle;
403
422
  };
423
+ const toolkitOnSuccess = (creators, options) => {
424
+ const watched = new Set(Array.isArray(creators) ? creators : [creators]);
425
+ return registryOf(resolveEnvironmentInjector(toolkitOnSuccess, options)).successes.pipe(filter((success) => watched.has(success.creator)), map((success) => success.response));
426
+ };
404
427
  const joinLoading = (observables) => combineLatest(observables.filter((o) => !!o)).pipe(map((values) => values.some((value) => !!value)));
405
428
  const joinErrors = (observables) => combineLatest(observables.filter((o) => !!o)).pipe(map((values) => {
406
429
  const errors = values.filter((value) => !!value);
407
430
  return errors.length ? errors : null;
408
431
  }));
409
- export { CallState, NgRxToolkitModule, SuspenseMultiPipe, SuspensePipe, joinErrors, joinLoading, toolkitCall, toolkitSelect };
432
+ export { CallState, NgRxToolkitModule, SuspenseMultiPipe, SuspensePipe, joinErrors, joinLoading, toolkitCall, toolkitOnSuccess, toolkitSelect };
410
433
 
411
434
  //# sourceMappingURL=ethlete-query-ngrx-toolkit.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ethlete-query-ngrx-toolkit.mjs","names":[],"sources":["../../../../libs/query/ngrx-toolkit/toolkit-pipe-transform.ts","../../../../libs/query/ngrx-toolkit/suspense.pipe.ts","../../../../libs/query/ngrx-toolkit/suspense-multi.pipe.ts","../../../../libs/query/ngrx-toolkit/ngrx-toolkit.module.ts","../../../../libs/query/ngrx-toolkit/toolkit-types.ts","../../../../libs/query/ngrx-toolkit/toolkit-handle.ts","../../../../libs/query/ngrx-toolkit/toolkit-call.ts","../../../../libs/query/ngrx-toolkit/toolkit-join.ts"],"sourcesContent":["import { ChangeDetectorRef, DestroyRef, inject } from '@angular/core';\nimport { Observable, Subscription } from 'rxjs';\n\nexport type CreateToolkitPipeTransformOptions<TValue, TState> = {\n initialState: TState;\n disposedState: TState;\n state$: (value: TValue) => Observable<TState>;\n};\n\nexport const createToolkitPipeTransform = <TValue extends object, TState>(\n options: CreateToolkitPipeTransformOptions<TValue, TState>,\n) => {\n const cdr = inject(ChangeDetectorRef);\n let subscription = Subscription.EMPTY;\n let current: TValue | null = null;\n let state = options.initialState;\n\n const dispose = () => {\n subscription.unsubscribe();\n current = null;\n state = options.disposedState;\n };\n\n const subscribe = (value: TValue) => {\n current = value;\n subscription = options.state$(value).subscribe((next) => {\n state = next;\n cdr.markForCheck();\n });\n };\n\n inject(DestroyRef).onDestroy(dispose);\n\n return (value: TValue | null | undefined) => {\n if (!current && value) subscribe(value);\n\n if (current !== value) {\n dispose();\n if (value) subscribe(value);\n }\n\n return state;\n };\n};\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { combineLatest, map, Observable, startWith } from 'rxjs';\nimport { createToolkitPipeTransform } from './toolkit-pipe-transform';\nimport { AnyMappedEntityState, ToolkitPollingOptions } from './toolkit-types';\n\ntype ExtractFrom<T> = T extends Observable<infer U> ? U : never;\n\n/** What `suspense` and `suspenseMulti` render for a handle: every stream's current value, plus the handle's methods. */\nexport type ToolkitSuspenseState<T extends AnyMappedEntityState | null | undefined> = T extends AnyMappedEntityState\n ? {\n args: ExtractFrom<T['args$']>;\n cachedResponse: ExtractFrom<T['cachedResponse$']> | null;\n callState: ExtractFrom<T['callState$']>;\n error: ExtractFrom<T['error$']>;\n isError: ExtractFrom<T['isError$']>;\n isInit: ExtractFrom<T['isInit$']>;\n isLoading: ExtractFrom<T['isLoading$']>;\n isSuccess: ExtractFrom<T['isSuccess$']>;\n response: ExtractFrom<T['response$']>;\n timestamp: ExtractFrom<T['timestamp$']>;\n refresh: () => void;\n remove: () => void;\n startPolling: (options: ToolkitPollingOptions) => void;\n stopPolling: () => void;\n }\n : T;\n\ntype AnySuspenseState = ToolkitSuspenseState<AnyMappedEntityState>;\n\nconst noop = () => undefined;\n\nconst DEFAULT_STATE: AnySuspenseState = {\n args: null,\n cachedResponse: null,\n callState: null,\n error: null,\n isError: false,\n isInit: false,\n isLoading: false,\n isSuccess: false,\n response: null,\n timestamp: null,\n refresh: noop,\n remove: noop,\n startPolling: noop,\n stopPolling: noop,\n};\n\nexport const suspenseState$ = (handle: AnyMappedEntityState): Observable<AnySuspenseState> =>\n combineLatest({\n args: handle.args$,\n cachedResponse: handle.cachedResponse$.pipe(startWith(null)),\n callState: handle.callState$,\n error: handle.error$,\n isError: handle.isError$,\n isInit: handle.isInit$,\n isLoading: handle.isLoading$,\n isSuccess: handle.isSuccess$,\n response: handle.response$,\n timestamp: handle.timestamp$,\n }).pipe(\n map((values) => ({\n ...values,\n refresh: handle.refresh,\n remove: handle.remove,\n startPolling: handle.startPolling,\n stopPolling: handle.stopPolling,\n })),\n );\n\n/** Subscribes to a toolkit handle and renders its current state, like the `suspense` pipe of `@tomtomb/ngrx-toolkit`. */\n@Pipe({ name: 'suspense', pure: false })\nexport class SuspensePipe implements PipeTransform {\n transform = createToolkitPipeTransform<AnyMappedEntityState, AnySuspenseState | null>({\n initialState: DEFAULT_STATE,\n disposedState: null,\n state$: suspenseState$,\n }) as <T extends AnyMappedEntityState>(value: T | null | undefined) => ToolkitSuspenseState<T>;\n}\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { combineLatest, map } from 'rxjs';\nimport { suspenseState$, ToolkitSuspenseState } from './suspense.pipe';\nimport { createToolkitPipeTransform } from './toolkit-pipe-transform';\nimport { AnyMappedEntityState } from './toolkit-types';\n\ntype AnyHandleRecord = Record<string, AnyMappedEntityState | null | undefined>;\n\nexport type ToolkitSuspenseMultiState<T extends AnyHandleRecord> = {\n [K in keyof T]: ToolkitSuspenseState<T[K]>;\n};\n\nconst suspenseMultiState$ = (handles: AnyHandleRecord) =>\n combineLatest(\n Object.entries(handles).flatMap(([key, handle]) =>\n handle ? [suspenseState$(handle).pipe(map((state) => [key, state] as const))] : [],\n ),\n ).pipe(map((states) => Object.fromEntries(states)));\n\n/**\n * Subscribes to a record of toolkit handles and renders each one's current state, like the `suspenseMulti` pipe of\n * `@tomtomb/ngrx-toolkit`. Nothing renders until every non-null handle has emitted.\n */\n@Pipe({ name: 'suspenseMulti', pure: false })\nexport class SuspenseMultiPipe implements PipeTransform {\n transform = createToolkitPipeTransform<AnyHandleRecord, Record<string, unknown>>({\n initialState: {},\n disposedState: {},\n state$: suspenseMultiState$,\n }) as <T extends AnyHandleRecord>(value: T | null | undefined) => ToolkitSuspenseMultiState<T>;\n}\n","import { NgModule } from '@angular/core';\nimport { SuspenseMultiPipe } from './suspense-multi.pipe';\nimport { SuspensePipe } from './suspense.pipe';\n\n/** Exports the `suspense` and `suspenseMulti` pipes, like the `NgRxToolkitModule` of `@tomtomb/ngrx-toolkit`. */\n@NgModule({\n imports: [SuspensePipe, SuspenseMultiPipe],\n exports: [SuspensePipe, SuspenseMultiPipe],\n})\nexport class NgRxToolkitModule {}\n","import { AnyQueryCreator, QueryArgsOf, QueryHeaders, ResponseType } from '@ethlete/query';\nimport { Observable, Subject } from 'rxjs';\n\n/** The call state of a toolkit handle, as `@tomtomb/ngrx-toolkit` names it. */\nexport const CallState = {\n INIT: 'INIT',\n LOADING: 'LOADING',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n} as const;\n\nexport type CallState = (typeof CallState)[keyof typeof CallState];\n\n/** The error shape of `@tomtomb/ngrx-toolkit`: the HTTP status, the error message and the response body. */\nexport type ToolkitError<T = unknown> = {\n status: number | string;\n message: string;\n data: T | null;\n};\n\nexport type ToolkitActionOptions = {\n headers?: QueryHeaders;\n extras?: { skipCache?: boolean };\n};\n\n/**\n * The toolkit-shaped args of a query creator: `queryParams` holds the path params, `params` the query string and\n * `body` the body, the way `@tomtomb/ngrx-toolkit` action groups named them.\n */\nexport type ActionCallArgs<TCreator extends AnyQueryCreator> = {\n [\n K in keyof QueryArgsOf<TCreator> as K extends 'pathParams'\n ? 'queryParams'\n : K extends 'queryParams'\n ? 'params'\n : K extends 'body'\n ? 'body'\n : never\n ]: QueryArgsOf<TCreator>[K];\n} & { actionOptions?: ToolkitActionOptions };\n\nexport type ToolkitPollingOptions = {\n intervalDuration: number;\n killSwitch: Subject<boolean>;\n};\n\n/** The handle `toolkitCall` returns, shaped like the `MappedEntityState` of `@tomtomb/ngrx-toolkit`. */\nexport type MappedEntityState<TCreator extends AnyQueryCreator> = {\n response$: Observable<ResponseType<QueryArgsOf<TCreator>> | null>;\n cachedResponse$: Observable<ResponseType<QueryArgsOf<TCreator>>>;\n error$: Observable<ToolkitError | null>;\n args$: Observable<ActionCallArgs<TCreator> | null>;\n isInit$: Observable<boolean | null>;\n isLoading$: Observable<boolean | null>;\n isSuccess$: Observable<boolean | null>;\n isError$: Observable<boolean | null>;\n timestamp$: Observable<number | null>;\n callState$: Observable<CallState | null>;\n refresh: () => void;\n remove: () => void;\n startPolling: (options: ToolkitPollingOptions) => void;\n stopPolling: () => void;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyMappedEntityState = MappedEntityState<any>;\n","import { computed, DestroyRef, effect, EnvironmentInjector, isDevMode, signal, untracked } from '@angular/core';\nimport {\n AnyQueryCreator,\n QueryArgsOf,\n QueryErrorResponse,\n QueryExecutionState,\n RequestArgs,\n ResponseType,\n} from '@ethlete/query';\nimport {\n defer,\n distinctUntilChanged,\n filter,\n finalize,\n interval,\n map,\n Observable,\n of,\n startWith,\n Subject,\n Subscription,\n takeUntil,\n} from 'rxjs';\nimport {\n ActionCallArgs,\n AnyMappedEntityState,\n CallState,\n MappedEntityState,\n ToolkitError,\n ToolkitPollingOptions,\n} from './toolkit-types';\n\ntype ToolkitHandleSnapshot = {\n args: unknown;\n callState: CallState | null;\n response: unknown;\n error: ToolkitError | null;\n timestamp: number | null;\n};\n\nexport type ToolkitHandleEntry = {\n handle: AnyMappedEntityState;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n call: (args: ActionCallArgs<any>) => void;\n releaseWhenSettled: () => void;\n};\n\nconst EMPTY_SNAPSHOT: ToolkitHandleSnapshot = {\n args: null,\n callState: null,\n response: null,\n error: null,\n timestamp: null,\n};\n\nconst toCallState = (state: QueryExecutionState<never> | null): CallState => {\n switch (state?.type) {\n case 'success':\n return CallState.SUCCESS;\n case 'failure':\n return CallState.ERROR;\n default:\n return CallState.LOADING;\n }\n};\n\nconst toToolkitError = (error: QueryErrorResponse): ToolkitError => ({\n status: error.raw.status,\n message: error.raw.message,\n data: error.raw.error ?? null,\n});\n\nconst handleReleasedMessage = (method: 'refresh' | 'startPolling') =>\n `${method}() was called on a toolkit handle that a newer toolkitCall() released. Args that cannot be hashed ` +\n `(FormData, Blob, Map, ...) never share a handle, so the next call for the same creator releases the previous ` +\n `handle once its request settles. The call was ignored - call toolkitCall() again with the args instead of ` +\n `reusing the old handle. This warning is shown once per handle.`;\n\nexport const toQueryArgs = (args: Record<string, unknown>) => {\n const actionOptions = args['actionOptions'] as { headers?: unknown } | undefined;\n const queryArgs: Record<string, unknown> = {};\n\n if (args['queryParams'] !== undefined) queryArgs['pathParams'] = args['queryParams'];\n if (args['params'] !== undefined) queryArgs['queryParams'] = args['params'];\n if (args['body'] !== undefined) queryArgs['body'] = args['body'];\n if (actionOptions?.headers !== undefined) queryArgs['headers'] = actionOptions.headers;\n\n return queryArgs as RequestArgs<never>;\n};\n\nexport const createToolkitHandle = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n injector: EnvironmentInjector,\n): ToolkitHandleEntry => {\n const query = creator({ injector, onlyManualExecution: true, silenceMissingWithArgsFeatureError: true });\n\n const calledArgs = signal<ActionCallArgs<TCreator> | null>(null);\n const toolkitError = computed(() => {\n const error = query.error();\n\n return error ? toToolkitError(error) : null;\n });\n const snapshot = computed<ToolkitHandleSnapshot>(() => {\n const currentArgs = calledArgs();\n\n if (!currentArgs) return EMPTY_SNAPSHOT;\n\n const state = query.executionState();\n const callState = toCallState(state);\n\n return {\n args: currentArgs,\n callState,\n response: state?.type === 'success' ? state.response : null,\n error: callState === CallState.ERROR ? toolkitError() : null,\n timestamp: Date.now(),\n };\n });\n\n const changes = new Subject<ToolkitHandleSnapshot>();\n\n const changesEffect = effect(\n () => {\n const current = snapshot();\n untracked(() => changes.next(current));\n },\n { injector },\n );\n\n let releasedSnapshot: ToolkitHandleSnapshot | null = null;\n let warnedAboutRelease = false;\n\n const ignoredAfterRelease = (method: 'refresh' | 'startPolling') => {\n if (!releasedSnapshot) return false;\n\n if (isDevMode() && !warnedAboutRelease) {\n warnedAboutRelease = true;\n console.warn(handleReleasedMessage(method));\n }\n\n return true;\n };\n\n const select = <T>(pick: (current: ToolkitHandleSnapshot) => T): Observable<T> =>\n defer(() => (releasedSnapshot ? of(releasedSnapshot) : changes.pipe(startWith(untracked(snapshot))))).pipe(\n map(pick),\n distinctUntilChanged(),\n );\n\n const call = (args: ActionCallArgs<TCreator>) => {\n calledArgs.set(args);\n query.execute({ args: toQueryArgs(args as Record<string, unknown>) });\n };\n\n const refresh = () => {\n if (ignoredAfterRelease('refresh')) return;\n\n const lastArgs = untracked(calledArgs);\n\n if (lastArgs) call(lastArgs);\n };\n\n let pollingSubscription = Subscription.EMPTY;\n\n const stopPolling = () => pollingSubscription.unsubscribe();\n\n const startPolling = ({ intervalDuration, killSwitch }: ToolkitPollingOptions) => {\n if (ignoredAfterRelease('startPolling') || !pollingSubscription.closed) return;\n\n pollingSubscription = interval(intervalDuration)\n .pipe(\n takeUntil(killSwitch),\n finalize(() => (pollingSubscription = Subscription.EMPTY)),\n )\n .subscribe(() => refresh());\n };\n\n const remove = () => {\n stopPolling();\n calledArgs.set(null);\n query.reset();\n };\n\n const removeDestroyListener = injector.get(DestroyRef).onDestroy(() => {\n stopPolling();\n changes.complete();\n });\n\n const release = () => {\n releasedSnapshot = untracked(snapshot);\n stopPolling();\n changesEffect.destroy();\n removeDestroyListener();\n changes.complete();\n query.subtle.destroy();\n };\n\n const releaseWhenSettled = () => {\n const releaseEffect = effect(\n () => {\n if (snapshot().callState === CallState.LOADING) return;\n\n releaseEffect.destroy();\n untracked(release);\n },\n { injector },\n );\n };\n\n type TResponse = ResponseType<QueryArgsOf<TCreator>>;\n\n const response$ = select((current) => current.response as TResponse | null);\n\n const handle: MappedEntityState<TCreator> = {\n response$,\n cachedResponse$: response$.pipe(filter((response): response is TResponse => !!response)),\n error$: select((current) => current.error),\n args$: select((current) => current.args as ActionCallArgs<TCreator> | null),\n isInit$: select((current) => current.callState === CallState.INIT),\n isLoading$: select((current) => current.callState === CallState.LOADING),\n isSuccess$: select((current) => current.callState === CallState.SUCCESS),\n isError$: select((current) => current.callState === CallState.ERROR),\n timestamp$: select((current) => current.timestamp),\n callState$: select((current) => current.callState),\n refresh,\n remove,\n startPolling,\n stopPolling,\n };\n\n return { handle, call, releaseWhenSettled };\n};\n","import { assertInInjectionContext, EnvironmentInjector, inject, Injector } from '@angular/core';\nimport { AnyQueryCreator, QueryHeaders, RequestArgs, resolveQueryHeaders } from '@ethlete/query';\nimport { createToolkitHandle, ToolkitHandleEntry, toQueryArgs } from './toolkit-handle';\nimport { ActionCallArgs, MappedEntityState } from './toolkit-types';\n\nexport type ToolkitCallOptions = {\n /**\n * The injector the handle's query lives in. Required outside an injection context, which is where a\n * `providedIn: 'root'` facade calls from; pass the facade's `inject(Injector)`.\n */\n injector?: Injector;\n};\n\ntype ToolkitRegistry = {\n shared: WeakMap<AnyQueryCreator, Map<string, ToolkitHandleEntry>>;\n latestUnshared: WeakMap<AnyQueryCreator, ToolkitHandleEntry>;\n};\n\nconst registries = /* @__PURE__ */ new WeakMap<EnvironmentInjector, ToolkitRegistry>();\n\nclass UnhashableValueError extends Error {}\n\nconst isPlainObject = (value: object) => {\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n};\n\nconst hashableValue = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(hashableValue);\n if (typeof value !== 'object' || value === null) return value;\n if (value instanceof Date) return { '\\u0000date': value.getTime() };\n if (!isPlainObject(value)) throw new UnhashableValueError();\n\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, hashableValue((value as Record<string, unknown>)[key])]),\n );\n};\n\nconst hashableHeaders = (headers: QueryHeaders | undefined) => {\n const resolved = resolveQueryHeaders(headers);\n\n return resolved\n ?.keys()\n .map((name) => name.toLowerCase())\n .sort()\n .map((name) => [name, resolved.getAll(name)]);\n};\n\n/**\n * Returns `null` for args holding a value JSON cannot represent (FormData, Blob, Map, ...). Those never share a handle,\n * and each one is released once the next one for the same creator starts and its own call has settled.\n */\nconst hashArgs = (args: RequestArgs<never>) => {\n const { headers, ...rest } = args as { headers?: QueryHeaders };\n\n try {\n return JSON.stringify([hashableValue(rest), hashableHeaders(headers) ?? null]);\n } catch (error) {\n if (error instanceof UnhashableValueError) return null;\n\n throw error;\n }\n};\n\nconst resolveEnvironmentInjector = (fn: (...args: never[]) => unknown, options?: ToolkitCallOptions) => {\n if (options?.injector) return options.injector.get(EnvironmentInjector);\n\n assertInInjectionContext(fn);\n\n return inject(EnvironmentInjector);\n};\n\nconst resolveEntry = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n args: ActionCallArgs<TCreator>,\n injector: EnvironmentInjector,\n) => {\n let registry = registries.get(injector);\n\n if (!registry) {\n registry = { shared: new WeakMap(), latestUnshared: new WeakMap() };\n registries.set(injector, registry);\n }\n\n const key = hashArgs(toQueryArgs(args as Record<string, unknown>));\n\n if (key === null) {\n const entry = createToolkitHandle(creator, injector);\n\n registry.latestUnshared.get(creator)?.releaseWhenSettled();\n registry.latestUnshared.set(creator, entry);\n\n return entry;\n }\n\n let entries = registry.shared.get(creator);\n\n if (!entries) {\n entries = new Map();\n registry.shared.set(creator, entries);\n }\n\n let entry = entries.get(key);\n\n if (!entry) {\n entry = createToolkitHandle(creator, injector);\n entries.set(key, entry);\n }\n\n return entry;\n};\n\n/**\n * Returns the handle for a creator and args without executing it - the `FacadeBase.select(group, actionId)` of\n * `@tomtomb/ngrx-toolkit`. Args that build the same request (in any key order, other keys ignored) give the same\n * handle `toolkitCall` returns, so `toolkitSelect(getTeam, args, { injector }).refresh()` re-runs a request another\n * component started.\n */\nexport const toolkitSelect = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n args: ActionCallArgs<TCreator>,\n options?: ToolkitCallOptions,\n): MappedEntityState<TCreator> =>\n resolveEntry(creator, args, resolveEnvironmentInjector(toolkitSelect, options)).handle;\n\n/**\n * Executes a query creator with toolkit-shaped args and returns its handle - the `FacadeBase.call(group, args)` of\n * `@tomtomb/ngrx-toolkit`. Every call sends the request again, unless one with equal args is still in flight, which it\n * joins; equal args return the same handle, which lives as long as the injector.\n *\n * @example\n * ```ts\n * @Injectable({ providedIn: 'root' })\n * export class TeamFacade {\n * private injector = inject(Injector);\n *\n * getTeam(args: ActionCallArgs<typeof getTeam>) {\n * return toolkitCall(getTeam, args, { injector: this.injector });\n * }\n * }\n * ```\n */\nexport const toolkitCall = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n args: ActionCallArgs<TCreator>,\n options?: ToolkitCallOptions,\n): MappedEntityState<TCreator> => {\n const entry = resolveEntry(creator, args, resolveEnvironmentInjector(toolkitCall, options));\n\n entry.call(args);\n\n return entry.handle;\n};\n","import { combineLatest, map, Observable } from 'rxjs';\nimport { ToolkitError } from './toolkit-types';\n\n/** Emits `true` while any of the given loading streams is `true`. Nullish entries are skipped. */\nexport const joinLoading = (observables: (Observable<boolean | null> | null | undefined)[]): Observable<boolean> =>\n combineLatest(observables.filter((o): o is Observable<boolean | null> => !!o)).pipe(\n map((values) => values.some((value) => !!value)),\n );\n\n/** Emits every non-null error of the given error streams, or `null` when there is none. Nullish entries are skipped. */\nexport const joinErrors = (\n observables: (Observable<ToolkitError | null> | null | undefined)[],\n): Observable<ToolkitError[] | null> =>\n combineLatest(observables.filter((o): o is Observable<ToolkitError | null> => !!o)).pipe(\n map((values) => {\n const errors = values.filter((value): value is ToolkitError => !!value);\n\n return errors.length ? errors : null;\n }),\n );\n"],"mappings":"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"}
1
+ {"version":3,"file":"ethlete-query-ngrx-toolkit.mjs","names":[],"sources":["../../../../libs/query/ngrx-toolkit/toolkit-pipe-transform.ts","../../../../libs/query/ngrx-toolkit/suspense.pipe.ts","../../../../libs/query/ngrx-toolkit/suspense-multi.pipe.ts","../../../../libs/query/ngrx-toolkit/ngrx-toolkit.module.ts","../../../../libs/query/ngrx-toolkit/toolkit-types.ts","../../../../libs/query/ngrx-toolkit/toolkit-handle.ts","../../../../libs/query/ngrx-toolkit/toolkit-call.ts","../../../../libs/query/ngrx-toolkit/toolkit-join.ts"],"sourcesContent":["import { ChangeDetectorRef, DestroyRef, inject } from '@angular/core';\nimport { Observable, Subscription } from 'rxjs';\n\nexport type CreateToolkitPipeTransformOptions<TValue, TState> = {\n initialState: TState;\n disposedState: TState;\n state$: (value: TValue) => Observable<TState>;\n};\n\nexport const createToolkitPipeTransform = <TValue extends object, TState>(\n options: CreateToolkitPipeTransformOptions<TValue, TState>,\n) => {\n const cdr = inject(ChangeDetectorRef);\n let subscription = Subscription.EMPTY;\n let current: TValue | null = null;\n let state = options.initialState;\n\n const dispose = () => {\n subscription.unsubscribe();\n current = null;\n state = options.disposedState;\n };\n\n const subscribe = (value: TValue) => {\n current = value;\n subscription = options.state$(value).subscribe((next) => {\n state = next;\n cdr.markForCheck();\n });\n };\n\n inject(DestroyRef).onDestroy(dispose);\n\n return (value: TValue | null | undefined) => {\n if (!current && value) subscribe(value);\n\n if (current !== value) {\n dispose();\n if (value) subscribe(value);\n }\n\n return state;\n };\n};\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { combineLatest, map, Observable, startWith } from 'rxjs';\nimport { createToolkitPipeTransform } from './toolkit-pipe-transform';\nimport { AnyMappedEntityState, ToolkitPollingOptions } from './toolkit-types';\n\ntype ExtractFrom<T> = T extends Observable<infer U> ? U : never;\n\n/** What `suspense` and `suspenseMulti` render for a handle: every stream's current value, plus the handle's methods. */\nexport type ToolkitSuspenseState<T extends AnyMappedEntityState | null | undefined> = T extends AnyMappedEntityState\n ? {\n args: ExtractFrom<T['args$']>;\n cachedResponse: ExtractFrom<T['cachedResponse$']> | null;\n callState: ExtractFrom<T['callState$']>;\n error: ExtractFrom<T['error$']>;\n isError: ExtractFrom<T['isError$']>;\n isInit: ExtractFrom<T['isInit$']>;\n isLoading: ExtractFrom<T['isLoading$']>;\n isSuccess: ExtractFrom<T['isSuccess$']>;\n response: ExtractFrom<T['response$']>;\n timestamp: ExtractFrom<T['timestamp$']>;\n refresh: () => void;\n remove: () => void;\n startPolling: (options: ToolkitPollingOptions) => void;\n stopPolling: () => void;\n }\n : T;\n\ntype AnySuspenseState = ToolkitSuspenseState<AnyMappedEntityState>;\n\nconst noop = () => undefined;\n\nconst DEFAULT_STATE: AnySuspenseState = {\n args: null,\n cachedResponse: null,\n callState: null,\n error: null,\n isError: false,\n isInit: false,\n isLoading: false,\n isSuccess: false,\n response: null,\n timestamp: null,\n refresh: noop,\n remove: noop,\n startPolling: noop,\n stopPolling: noop,\n};\n\nexport const suspenseState$ = (handle: AnyMappedEntityState): Observable<AnySuspenseState> =>\n combineLatest({\n args: handle.args$,\n cachedResponse: handle.cachedResponse$.pipe(startWith(null)),\n callState: handle.callState$,\n error: handle.error$,\n isError: handle.isError$,\n isInit: handle.isInit$,\n isLoading: handle.isLoading$,\n isSuccess: handle.isSuccess$,\n response: handle.response$,\n timestamp: handle.timestamp$,\n }).pipe(\n map((values) => ({\n ...values,\n refresh: handle.refresh,\n remove: handle.remove,\n startPolling: handle.startPolling,\n stopPolling: handle.stopPolling,\n })),\n );\n\n/** Subscribes to a toolkit handle and renders its current state, like the `suspense` pipe of `@tomtomb/ngrx-toolkit`. */\n@Pipe({ name: 'suspense', pure: false })\nexport class SuspensePipe implements PipeTransform {\n transform = createToolkitPipeTransform<AnyMappedEntityState, AnySuspenseState | null>({\n initialState: DEFAULT_STATE,\n disposedState: null,\n state$: suspenseState$,\n }) as <T extends AnyMappedEntityState>(value: T | null | undefined) => ToolkitSuspenseState<T>;\n}\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { combineLatest, map } from 'rxjs';\nimport { suspenseState$, ToolkitSuspenseState } from './suspense.pipe';\nimport { createToolkitPipeTransform } from './toolkit-pipe-transform';\nimport { AnyMappedEntityState } from './toolkit-types';\n\ntype AnyHandleRecord = Record<string, AnyMappedEntityState | null | undefined>;\n\nexport type ToolkitSuspenseMultiState<T extends AnyHandleRecord> = {\n [K in keyof T]: ToolkitSuspenseState<T[K]>;\n};\n\nconst suspenseMultiState$ = (handles: AnyHandleRecord) =>\n combineLatest(\n Object.entries(handles).flatMap(([key, handle]) =>\n handle ? [suspenseState$(handle).pipe(map((state) => [key, state] as const))] : [],\n ),\n ).pipe(map((states) => Object.fromEntries(states)));\n\n/**\n * Subscribes to a record of toolkit handles and renders each one's current state, like the `suspenseMulti` pipe of\n * `@tomtomb/ngrx-toolkit`. Nothing renders until every non-null handle has emitted.\n */\n@Pipe({ name: 'suspenseMulti', pure: false })\nexport class SuspenseMultiPipe implements PipeTransform {\n transform = createToolkitPipeTransform<AnyHandleRecord, Record<string, unknown>>({\n initialState: {},\n disposedState: {},\n state$: suspenseMultiState$,\n }) as <T extends AnyHandleRecord>(value: T | null | undefined) => ToolkitSuspenseMultiState<T>;\n}\n","import { NgModule } from '@angular/core';\nimport { SuspenseMultiPipe } from './suspense-multi.pipe';\nimport { SuspensePipe } from './suspense.pipe';\n\n/** Exports the `suspense` and `suspenseMulti` pipes, like the `NgRxToolkitModule` of `@tomtomb/ngrx-toolkit`. */\n@NgModule({\n imports: [SuspensePipe, SuspenseMultiPipe],\n exports: [SuspensePipe, SuspenseMultiPipe],\n})\nexport class NgRxToolkitModule {}\n","import { AnyQueryCreator, QueryArgsOf, QueryHeaders, ResponseType } from '@ethlete/query';\nimport { Observable, Subject } from 'rxjs';\n\n/** The call state of a toolkit handle, as `@tomtomb/ngrx-toolkit` names it. */\nexport const CallState = {\n INIT: 'INIT',\n LOADING: 'LOADING',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n} as const;\n\nexport type CallState = (typeof CallState)[keyof typeof CallState];\n\n/** The error shape of `@tomtomb/ngrx-toolkit`: the HTTP status, the error message and the response body. */\nexport type ToolkitError<T = unknown> = {\n status: number | string;\n message: string;\n data: T | null;\n};\n\nexport type ToolkitActionOptions = {\n headers?: QueryHeaders;\n extras?: { skipCache?: boolean };\n};\n\n/**\n * The toolkit-shaped args of a query creator: `queryParams` holds the path params, `params` the query string and\n * `body` the body, the way `@tomtomb/ngrx-toolkit` action groups named them.\n */\nexport type ActionCallArgs<TCreator extends AnyQueryCreator> = {\n [\n K in keyof QueryArgsOf<TCreator> as K extends 'pathParams'\n ? 'queryParams'\n : K extends 'queryParams'\n ? 'params'\n : K extends 'body'\n ? 'body'\n : never\n ]: QueryArgsOf<TCreator>[K];\n} & { actionOptions?: ToolkitActionOptions };\n\nexport type ToolkitPollingOptions = {\n intervalDuration: number;\n killSwitch: Subject<boolean>;\n};\n\n/** The handle `toolkitCall` returns, shaped like the `MappedEntityState` of `@tomtomb/ngrx-toolkit`. */\nexport type MappedEntityState<TCreator extends AnyQueryCreator> = {\n response$: Observable<ResponseType<QueryArgsOf<TCreator>> | null>;\n cachedResponse$: Observable<ResponseType<QueryArgsOf<TCreator>>>;\n error$: Observable<ToolkitError | null>;\n args$: Observable<ActionCallArgs<TCreator> | null>;\n isInit$: Observable<boolean | null>;\n isLoading$: Observable<boolean | null>;\n isSuccess$: Observable<boolean | null>;\n isError$: Observable<boolean | null>;\n timestamp$: Observable<number | null>;\n callState$: Observable<CallState | null>;\n refresh: () => void;\n remove: () => void;\n startPolling: (options: ToolkitPollingOptions) => void;\n stopPolling: () => void;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type AnyMappedEntityState = MappedEntityState<any>;\n","import { computed, DestroyRef, effect, EnvironmentInjector, isDevMode, signal, untracked } from '@angular/core';\nimport {\n AnyQueryCreator,\n QueryArgsOf,\n QueryErrorResponse,\n QueryExecutionState,\n RequestArgs,\n ResponseType,\n} from '@ethlete/query';\nimport {\n defer,\n distinctUntilChanged,\n filter,\n finalize,\n interval,\n map,\n Observable,\n of,\n startWith,\n Subject,\n Subscription,\n takeUntil,\n} from 'rxjs';\nimport {\n ActionCallArgs,\n AnyMappedEntityState,\n CallState,\n MappedEntityState,\n ToolkitError,\n ToolkitPollingOptions,\n} from './toolkit-types';\n\ntype ToolkitHandleSnapshot = {\n args: unknown;\n callState: CallState | null;\n response: unknown;\n error: ToolkitError | null;\n timestamp: number | null;\n};\n\nexport type ToolkitHandleEntry = {\n handle: AnyMappedEntityState;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n call: (args: ActionCallArgs<any>) => void;\n releaseWhenSettled: () => void;\n};\n\nconst EMPTY_SNAPSHOT: ToolkitHandleSnapshot = {\n args: null,\n callState: null,\n response: null,\n error: null,\n timestamp: null,\n};\n\nconst toCallState = (state: QueryExecutionState<never> | null): CallState => {\n switch (state?.type) {\n case 'success':\n return CallState.SUCCESS;\n case 'failure':\n return CallState.ERROR;\n default:\n return CallState.LOADING;\n }\n};\n\nconst toToolkitError = (error: QueryErrorResponse): ToolkitError => ({\n status: error.raw.status,\n message: error.raw.message,\n data: error.raw.error ?? null,\n});\n\nconst handleReleasedMessage = (method: 'refresh' | 'startPolling') =>\n `${method}() was called on a toolkit handle that a newer toolkitCall() released. Args that cannot be hashed ` +\n `(FormData, Blob, Map, ...) never share a handle, so the next call for the same creator releases the previous ` +\n `handle once its request settles. The call was ignored - call toolkitCall() again with the args instead of ` +\n `reusing the old handle. This warning is shown once per handle.`;\n\nexport const toQueryArgs = (args: Record<string, unknown>) => {\n const actionOptions = args['actionOptions'] as { headers?: unknown } | undefined;\n const queryArgs: Record<string, unknown> = {};\n\n if (args['queryParams'] !== undefined) queryArgs['pathParams'] = args['queryParams'];\n if (args['params'] !== undefined) queryArgs['queryParams'] = args['params'];\n if (args['body'] !== undefined) queryArgs['body'] = args['body'];\n if (actionOptions?.headers !== undefined) queryArgs['headers'] = actionOptions.headers;\n\n return queryArgs as RequestArgs<never>;\n};\n\nexport const createToolkitHandle = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n injector: EnvironmentInjector,\n onSuccess: (response: unknown) => void,\n): ToolkitHandleEntry => {\n const query = creator({ injector, onlyManualExecution: true, silenceMissingWithArgsFeatureError: true });\n\n const calledArgs = signal<ActionCallArgs<TCreator> | null>(null);\n const toolkitError = computed(() => {\n const error = query.error();\n\n return error ? toToolkitError(error) : null;\n });\n const snapshot = computed<ToolkitHandleSnapshot>(() => {\n const currentArgs = calledArgs();\n\n if (!currentArgs) return EMPTY_SNAPSHOT;\n\n const state = query.executionState();\n const callState = toCallState(state);\n\n return {\n args: currentArgs,\n callState,\n response: state?.type === 'success' ? state.response : null,\n error: callState === CallState.ERROR ? toolkitError() : null,\n timestamp: Date.now(),\n };\n });\n\n const changes = new Subject<ToolkitHandleSnapshot>();\n\n let lastSuccess: QueryExecutionState<never> | null = null;\n\n const changesEffect = effect(\n () => {\n const current = snapshot();\n const state = query.executionState();\n\n untracked(() => {\n changes.next(current);\n\n if (current.callState === CallState.SUCCESS && state !== lastSuccess) {\n lastSuccess = state;\n onSuccess(current.response);\n }\n });\n },\n { injector },\n );\n\n let releasedSnapshot: ToolkitHandleSnapshot | null = null;\n let warnedAboutRelease = false;\n\n const ignoredAfterRelease = (method: 'refresh' | 'startPolling') => {\n if (!releasedSnapshot) return false;\n\n if (isDevMode() && !warnedAboutRelease) {\n warnedAboutRelease = true;\n console.warn(handleReleasedMessage(method));\n }\n\n return true;\n };\n\n const select = <T>(pick: (current: ToolkitHandleSnapshot) => T): Observable<T> =>\n defer(() => (releasedSnapshot ? of(releasedSnapshot) : changes.pipe(startWith(untracked(snapshot))))).pipe(\n map(pick),\n distinctUntilChanged(),\n );\n\n const call = (args: ActionCallArgs<TCreator>) => {\n calledArgs.set(args);\n query.execute({ args: toQueryArgs(args as Record<string, unknown>) });\n };\n\n const refresh = () => {\n if (ignoredAfterRelease('refresh')) return;\n\n const lastArgs = untracked(calledArgs);\n\n if (lastArgs) call(lastArgs);\n };\n\n let pollingSubscription = Subscription.EMPTY;\n\n const stopPolling = () => pollingSubscription.unsubscribe();\n\n const startPolling = ({ intervalDuration, killSwitch }: ToolkitPollingOptions) => {\n if (ignoredAfterRelease('startPolling') || !pollingSubscription.closed) return;\n\n pollingSubscription = interval(intervalDuration)\n .pipe(\n takeUntil(killSwitch),\n finalize(() => (pollingSubscription = Subscription.EMPTY)),\n )\n .subscribe(() => refresh());\n };\n\n const remove = () => {\n stopPolling();\n calledArgs.set(null);\n query.reset();\n };\n\n const removeDestroyListener = injector.get(DestroyRef).onDestroy(() => {\n stopPolling();\n changes.complete();\n });\n\n const release = () => {\n releasedSnapshot = untracked(snapshot);\n stopPolling();\n changesEffect.destroy();\n removeDestroyListener();\n changes.complete();\n query.subtle.destroy();\n };\n\n const releaseWhenSettled = () => {\n const releaseEffect = effect(\n () => {\n if (snapshot().callState === CallState.LOADING) return;\n\n releaseEffect.destroy();\n untracked(release);\n },\n { injector },\n );\n };\n\n type TResponse = ResponseType<QueryArgsOf<TCreator>>;\n\n const response$ = select((current) => current.response as TResponse | null);\n\n const handle: MappedEntityState<TCreator> = {\n response$,\n cachedResponse$: response$.pipe(filter((response): response is TResponse => !!response)),\n error$: select((current) => current.error),\n args$: select((current) => current.args as ActionCallArgs<TCreator> | null),\n isInit$: select((current) => current.callState === CallState.INIT),\n isLoading$: select((current) => current.callState === CallState.LOADING),\n isSuccess$: select((current) => current.callState === CallState.SUCCESS),\n isError$: select((current) => current.callState === CallState.ERROR),\n timestamp$: select((current) => current.timestamp),\n callState$: select((current) => current.callState),\n refresh,\n remove,\n startPolling,\n stopPolling,\n };\n\n return { handle, call, releaseWhenSettled };\n};\n","import { assertInInjectionContext, DestroyRef, EnvironmentInjector, inject, Injector } from '@angular/core';\nimport {\n AnyQueryCreator,\n QueryArgsOf,\n QueryHeaders,\n RequestArgs,\n ResponseType,\n resolveQueryHeaders,\n} from '@ethlete/query';\nimport { filter, map, Observable, Subject } from 'rxjs';\nimport { createToolkitHandle, ToolkitHandleEntry, toQueryArgs } from './toolkit-handle';\nimport { ActionCallArgs, MappedEntityState } from './toolkit-types';\n\nexport type ToolkitCallOptions = {\n /**\n * The injector the handle's query lives in. Required outside an injection context, which is where a\n * `providedIn: 'root'` facade calls from; pass the facade's `inject(Injector)`.\n */\n injector?: Injector;\n};\n\ntype ToolkitRegistry = {\n shared: WeakMap<AnyQueryCreator, Map<string, ToolkitHandleEntry>>;\n latestUnshared: WeakMap<AnyQueryCreator, ToolkitHandleEntry>;\n successes: Subject<{ creator: AnyQueryCreator; response: unknown }>;\n};\n\nconst registries = /* @__PURE__ */ new WeakMap<EnvironmentInjector, ToolkitRegistry>();\n\nclass UnhashableValueError extends Error {}\n\nconst isPlainObject = (value: object) => {\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n};\n\nconst hashableValue = (value: unknown): unknown => {\n if (Array.isArray(value)) return value.map(hashableValue);\n if (typeof value !== 'object' || value === null) return value;\n if (value instanceof Date) return { '\\u0000date': value.getTime() };\n if (!isPlainObject(value)) throw new UnhashableValueError();\n\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, hashableValue((value as Record<string, unknown>)[key])]),\n );\n};\n\nconst hashableHeaders = (headers: QueryHeaders | undefined) => {\n const resolved = resolveQueryHeaders(headers);\n\n return resolved\n ?.keys()\n .map((name) => name.toLowerCase())\n .sort()\n .map((name) => [name, resolved.getAll(name)]);\n};\n\n/**\n * Returns `null` for args holding a value JSON cannot represent (FormData, Blob, Map, ...). Those never share a handle,\n * and each one is released once the next one for the same creator starts and its own call has settled.\n */\nconst hashArgs = (args: RequestArgs<never>) => {\n const { headers, ...rest } = args as { headers?: QueryHeaders };\n\n try {\n return JSON.stringify([hashableValue(rest), hashableHeaders(headers) ?? null]);\n } catch (error) {\n if (error instanceof UnhashableValueError) return null;\n\n throw error;\n }\n};\n\nconst resolveEnvironmentInjector = (fn: (...args: never[]) => unknown, options?: ToolkitCallOptions) => {\n if (options?.injector) return options.injector.get(EnvironmentInjector);\n\n assertInInjectionContext(fn);\n\n return inject(EnvironmentInjector);\n};\n\nconst registryOf = (injector: EnvironmentInjector) => {\n let registry = registries.get(injector);\n\n if (!registry) {\n const successes = new Subject<{ creator: AnyQueryCreator; response: unknown }>();\n\n registry = { shared: new WeakMap(), latestUnshared: new WeakMap(), successes };\n registries.set(injector, registry);\n injector.get(DestroyRef).onDestroy(() => successes.complete());\n }\n\n return registry;\n};\n\nconst handleFor = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n injector: EnvironmentInjector,\n registry: ToolkitRegistry,\n) => createToolkitHandle(creator, injector, (response) => registry.successes.next({ creator, response }));\n\nconst resolveEntry = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n args: ActionCallArgs<TCreator>,\n injector: EnvironmentInjector,\n) => {\n const registry = registryOf(injector);\n\n const key = hashArgs(toQueryArgs(args as Record<string, unknown>));\n\n if (key === null) {\n const entry = handleFor(creator, injector, registry);\n\n registry.latestUnshared.get(creator)?.releaseWhenSettled();\n registry.latestUnshared.set(creator, entry);\n\n return entry;\n }\n\n let entries = registry.shared.get(creator);\n\n if (!entries) {\n entries = new Map();\n registry.shared.set(creator, entries);\n }\n\n let entry = entries.get(key);\n\n if (!entry) {\n entry = handleFor(creator, injector, registry);\n entries.set(key, entry);\n }\n\n return entry;\n};\n\n/**\n * Returns the handle for a creator and args without executing it - the `FacadeBase.select(group, actionId)` of\n * `@tomtomb/ngrx-toolkit`. Args that build the same request (in any key order, other keys ignored) give the same\n * handle `toolkitCall` returns, so `toolkitSelect(getTeam, args, { injector }).refresh()` re-runs a request another\n * component started.\n */\nexport const toolkitSelect = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n args: ActionCallArgs<TCreator>,\n options?: ToolkitCallOptions,\n): MappedEntityState<TCreator> =>\n resolveEntry(creator, args, resolveEnvironmentInjector(toolkitSelect, options)).handle;\n\n/**\n * Executes a query creator with toolkit-shaped args and returns its handle - the `FacadeBase.call(group, args)` of\n * `@tomtomb/ngrx-toolkit`. Every call sends the request again, unless one with equal args is still in flight, which it\n * joins; equal args return the same handle, which lives as long as the injector.\n *\n * @example\n * ```ts\n * @Injectable({ providedIn: 'root' })\n * export class TeamFacade {\n * private injector = inject(Injector);\n *\n * getTeam(args: ActionCallArgs<typeof getTeam>) {\n * return toolkitCall(getTeam, args, { injector: this.injector });\n * }\n * }\n * ```\n */\nexport const toolkitCall = <TCreator extends AnyQueryCreator>(\n creator: TCreator,\n args: ActionCallArgs<TCreator>,\n options?: ToolkitCallOptions,\n): MappedEntityState<TCreator> => {\n const entry = resolveEntry(creator, args, resolveEnvironmentInjector(toolkitCall, options));\n\n entry.call(args);\n\n return entry.handle;\n};\n\ntype SuccessResponseOf<TCreator> = TCreator extends AnyQueryCreator ? ResponseType<QueryArgsOf<TCreator>> : never;\n\n/**\n * Emits the response every time a `toolkitCall` handle of one of the creators succeeds - the\n * `facade.on(action.success)` of `@tomtomb/ngrx-toolkit`. Only handles of the same environment injector count.\n *\n * @example\n * ```ts\n * toolkitOnSuccess([postAcceptClaim, postDeclineClaim])\n * .pipe(takeUntilDestroyed())\n * .subscribe(() => this.reloadRoster());\n * ```\n */\nexport const toolkitOnSuccess = <const TCreators extends AnyQueryCreator | readonly AnyQueryCreator[]>(\n creators: TCreators,\n options?: ToolkitCallOptions,\n): Observable<SuccessResponseOf<TCreators extends readonly AnyQueryCreator[] ? TCreators[number] : TCreators>> => {\n const watched = new Set<AnyQueryCreator>(Array.isArray(creators) ? creators : [creators as AnyQueryCreator]);\n\n return registryOf(resolveEnvironmentInjector(toolkitOnSuccess, options)).successes.pipe(\n filter((success) => watched.has(success.creator)),\n map((success) => success.response as never),\n );\n};\n","import { combineLatest, map, Observable } from 'rxjs';\nimport { ToolkitError } from './toolkit-types';\n\n/** Emits `true` while any of the given loading streams is `true`. Nullish entries are skipped. */\nexport const joinLoading = (observables: (Observable<boolean | null> | null | undefined)[]): Observable<boolean> =>\n combineLatest(observables.filter((o): o is Observable<boolean | null> => !!o)).pipe(\n map((values) => values.some((value) => !!value)),\n );\n\n/** Emits every non-null error of the given error streams, or `null` when there is none. Nullish entries are skipped. */\nexport const joinErrors = (\n observables: (Observable<ToolkitError | null> | null | undefined)[],\n): Observable<ToolkitError[] | null> =>\n combineLatest(observables.filter((o): o is Observable<ToolkitError | null> => !!o)).pipe(\n map((values) => {\n const errors = values.filter((value): value is ToolkitError => !!value);\n\n return errors.length ? errors : null;\n }),\n );\n"],"mappings":"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"}
@@ -698,14 +698,15 @@ const tokensNotAvailableInsideAuthAndExec = () => {
698
698
  const invalidStateInsideSecureExecuteFactory = () => {
699
699
  return new RuntimeError(QueryRuntimeErrorCode.INVALID_STATE_INSIDE_SECURE_EXECUTE_FACTORY, `An invalid state occurred inside the secure execute factory.`);
700
700
  };
701
- const circularQueryDependency = () => {
702
- return new RuntimeError(QueryRuntimeErrorCode.CIRCULAR_QUERY_DEPENDENCY, `The same query was executed with identical args more than 5 times in a row, less than 100ms apart. This is usually a sign of a circular dependency.`);
701
+ const describeQuery = (route) => typeof route === "string" ? `The query for "${route}"` : "A query with a function route";
702
+ const circularQueryDependency = (route) => {
703
+ return new RuntimeError(QueryRuntimeErrorCode.CIRCULAR_QUERY_DEPENDENCY, `${describeQuery(route)} was executed with identical args more than 5 times in a row, less than 100ms apart. This is usually a sign of a circular dependency. Repeated execute({ skipCache: true }) calls count too, e.g. a test that fakes responses in a tight loop.`);
703
704
  };
704
705
  const queryExecutedAfterDestroyMessage = (route) => {
705
- return `${typeof route === "string" ? `The query for "${route}"` : "A query with a function route"} was executed after the scope that created it was destroyed. The call was ignored - drop the reference to the query when its component or injector goes away.`;
706
+ return `${describeQuery(route)} was executed after the scope that created it was destroyed. The call was ignored - drop the reference to the query when its component or injector goes away.`;
706
707
  };
707
708
  const queryExecutedWhileParkedMessage = (route) => {
708
- return `${typeof route === "string" ? `The query for "${route}"` : "A query with a function route"} was executed while its withArgs source returned null (parked). The call was ignored - pass args to execute(), or let the source return them.`;
709
+ return `${describeQuery(route)} was executed while its withArgs source returned null (parked). The call was ignored - pass args to execute(), or let the source return them.`;
709
710
  };
710
711
  const legacyPrepareWithoutInjectionContext = (creatorName, method = "prepare") => {
711
712
  const label = creatorName ? `"${creatorName}"` : "A legacy query creator";
@@ -2375,7 +2376,7 @@ const LONG_POLLING_TRIGGER = "long-polling";
2375
2376
  const FEATURE_TRIGGERS = ["polling", "auto-refresh"];
2376
2377
  const CIRCULAR_DEPENDENCY_WINDOW_MS = 100;
2377
2378
  const CIRCULAR_DEPENDENCY_MAX_REPEATS = 5;
2378
- const circularQueryDependencyChecker = () => {
2379
+ const circularQueryDependencyChecker = (route) => {
2379
2380
  const recent = /* @__PURE__ */ new Map();
2380
2381
  const check = (args) => {
2381
2382
  const now = Date.now();
@@ -2385,7 +2386,7 @@ const circularQueryDependencyChecker = () => {
2385
2386
  const repeats = entry ? entry.repeats + 1 : 1;
2386
2387
  if (repeats > CIRCULAR_DEPENDENCY_MAX_REPEATS) {
2387
2388
  recent.delete(signature);
2388
- throw circularQueryDependency();
2389
+ throw circularQueryDependency(route);
2389
2390
  }
2390
2391
  recent.set(signature, {
2391
2392
  lastTs: now,
@@ -2396,7 +2397,7 @@ const circularQueryDependencyChecker = () => {
2396
2397
  };
2397
2398
  const createExecuteFn = (executeOptions) => {
2398
2399
  const executeState = setupQueryExecuteState();
2399
- const circularChecker = circularQueryDependencyChecker();
2400
+ const circularChecker = circularQueryDependencyChecker(executeOptions.creatorInternals.route);
2400
2401
  const aborter = createQueryExecutionAborter(executeOptions.state);
2401
2402
  const reset = () => untracked(() => resetExecuteState({
2402
2403
  executeState,
@@ -4581,7 +4582,7 @@ const AUTH_HEADER$1 = "Authorization";
4581
4582
  const EXPIRED_TOKEN_WAIT_MS = 5e3;
4582
4583
  const createSecureExecuteFactory = (options) => {
4583
4584
  const executeState = setupQueryExecuteState();
4584
- const circularChecker = circularQueryDependencyChecker();
4585
+ const circularChecker = circularQueryDependencyChecker(options.route);
4585
4586
  const aborter = createQueryExecutionAborter(options.state);
4586
4587
  let authQuerySubscription = Subscription.EMPTY;
4587
4588
  let tokenRefreshSubscription = Subscription.EMPTY;
@@ -6637,7 +6638,7 @@ const buildTrackingFeature = (context, config) => {
6637
6638
  };
6638
6639
  };
6639
6640
  const createTrackingFeature = (context, config) => runInInjectionContext(context.injector, () => buildTrackingFeature(context, config));
6640
- const QUERY_VERSION = "6.0.0-next.62";
6641
+ const QUERY_VERSION = "6.0.0-next.63";
6641
6642
  const ethlete = {};
6642
6643
  let app = null;
6643
6644
  const publish = () => {
@@ -6665,6 +6666,7 @@ const setQueryDevtoolsUiMounted = (isMounted) => {
6665
6666
  mounted = Math.max(0, mounted + (isMounted ? 1 : -1));
6666
6667
  notify?.();
6667
6668
  };
6669
+ const isQueryDevtoolsUiMounted = () => mounted > 0;
6668
6670
  const markQueryDevtoolsAppSettled = () => {
6669
6671
  settled = true;
6670
6672
  notify?.();
@@ -9792,10 +9794,12 @@ const ONE_TIME_OPTIONS = [
9792
9794
  "schema",
9793
9795
  "showInAutomation"
9794
9796
  ];
9795
- const settleThePillsOnFirstRender = () => provideEnvironmentInitializer(() => {
9797
+ const settleThePillsOnFirstRender = (ui) => provideEnvironmentInitializer(() => {
9796
9798
  const destroyRef = inject(DestroyRef);
9797
9799
  setQueryDevtoolsPillNonce(inject(CSP_NONCE, { optional: true }));
9800
+ const injector = inject(EnvironmentInjector);
9798
9801
  afterNextRender(() => {
9802
+ if (ui && !isQueryDevtoolsUiMounted()) ui().then((m) => m.mountQueryDevtools(injector));
9799
9803
  const settle = setTimeout(markQueryDevtoolsAppSettled, PILL_SETTLE_GRACE_MS);
9800
9804
  destroyRef.onDestroy(() => clearTimeout(settle));
9801
9805
  });
@@ -9813,7 +9817,7 @@ const ɵresetQueryDevtoolsForTesting = () => {
9813
9817
  const provideQueryDevtools = (options) => {
9814
9818
  if (queryDevtoolsInitialized) {
9815
9819
  warnAboutIgnoredOptions(options);
9816
- return makeEnvironmentProviders([settleThePillsOnFirstRender()]);
9820
+ return makeEnvironmentProviders([settleThePillsOnFirstRender(options?.ui)]);
9817
9821
  }
9818
9822
  queryDevtoolsInitialized = true;
9819
9823
  initQueryDevtoolsSettings();
@@ -9838,7 +9842,7 @@ const provideQueryDevtools = (options) => {
9838
9842
  setQueryDevtoolsMockResolver(resolveQueryDevtoolsMockForAttempt);
9839
9843
  setQueryDevtoolsTokenPayloadPatcher(applyQueryDevtoolsTokenTtl);
9840
9844
  if (!isDevMode()) console.warn("You are using the Query Devtools in production mode. This increases the size of your bundle and should only be used for development purposes.");
9841
- return makeEnvironmentProviders([settleThePillsOnFirstRender()]);
9845
+ return makeEnvironmentProviders([settleThePillsOnFirstRender(options?.ui)]);
9842
9846
  };
9843
9847
  const getOpName = /\b(?:query|mutation)\s+([\w-]+)(?:\s*\([^)]*\))?(?:\s*@\w+(?:\s*\([^)]*\))?)*\s*\{/;
9844
9848
  const STRING_LITERAL = "\"\"\"[\\s\\S]*?\"\"\"|\"(?:[^\"\\\\\\n]|\\\\.)*\"";
@@ -9882,7 +9886,7 @@ const gql = (strings, ...values) => {
9882
9886
  };
9883
9887
  const createGqlExecuteFn = (executeOptions) => {
9884
9888
  const executeState = setupQueryExecuteState();
9885
- const circularChecker = circularQueryDependencyChecker();
9889
+ const circularChecker = circularQueryDependencyChecker(executeOptions.creator?.route);
9886
9890
  const aborter = createQueryExecutionAborter(executeOptions.state);
9887
9891
  const reset = () => untracked(() => resetExecuteState({
9888
9892
  executeState,
@@ -10879,6 +10883,15 @@ const transformExecStateToQueryState = (execState, triggeredVia = "program") =>
10879
10883
  };
10880
10884
  }
10881
10885
  };
10886
+ const signalChanges = (source, injector) => {
10887
+ const changes = new Subject();
10888
+ effect(() => {
10889
+ const value = source();
10890
+ untracked(() => changes.next(value));
10891
+ }, { injector });
10892
+ injector.get(DestroyRef).onDestroy(() => changes.complete());
10893
+ return changes.asObservable();
10894
+ };
10882
10895
  const isLegacyQuery = (query) => {
10883
10896
  if (!query || typeof query !== "object" || Array.isArray(query)) return false;
10884
10897
  if (!("newQuery" in query)) return false;
@@ -10905,6 +10918,8 @@ var LegacyQuery = class {
10905
10918
  this._errorAtExecute = null;
10906
10919
  this._ownLoadSettled = false;
10907
10920
  this._wasAborted = false;
10921
+ this._mockState = signal(null, ...ngDevMode ? [{ debugName: "_mockState" }] : /* istanbul ignore next */ []);
10922
+ this._mockSubscription = null;
10908
10923
  if (this._isInert) {
10909
10924
  this.state$ = of(transformExecStateToQueryState(null));
10910
10925
  this.isDestroyed = true;
@@ -10913,32 +10928,35 @@ var LegacyQuery = class {
10913
10928
  this.storeSyncEffect = effect(() => {
10914
10929
  const execState = this.newQuery.executionState();
10915
10930
  untracked(() => {
10916
- if (execState?.type !== "success" || !this.entity?.set) return;
10917
- const res = execState.response;
10918
- const id = this.entity.id({
10919
- args: this._arguments,
10920
- response: res
10921
- });
10922
- this.entity.set({
10923
- args: this._arguments,
10924
- response: res,
10925
- id,
10926
- store: this.entity.store
10927
- });
10931
+ if (execState?.type === "success") this.syncEntity(execState.response);
10928
10932
  });
10929
10933
  }, {
10930
10934
  ...ngDevMode ? { debugName: "storeSyncEffect" } : /* istanbul ignore next */ {},
10931
10935
  injector: this.newQuery.subtle.injector
10932
10936
  });
10933
- const executionState$ = toObservable(this.newQuery.executionState, { injector: this.newQuery.subtle.injector });
10934
- this.state$ = defer(() => executionState$.pipe(startWith(untracked(this.newQuery.executionState)))).pipe(distinctUntilChanged(), map((execState) => this.toQueryState(execState)), switchMap((s) => this._transformState(s)));
10937
+ const executionState$ = signalChanges(this.newQuery.executionState, this.newQuery.subtle.injector);
10938
+ const mockState$ = signalChanges(this._mockState, this.newQuery.subtle.injector);
10939
+ this.state$ = defer(() => combineLatest([mockState$.pipe(startWith(untracked(this._mockState)), distinctUntilChanged()), executionState$.pipe(startWith(untracked(this.newQuery.executionState)), distinctUntilChanged())])).pipe(map(([mock, execState]) => mock ?? this.toQueryState(execState)), switchMap((s) => this._transformState(s)));
10935
10940
  this.newQuery.subtle.destroyRef.onDestroy(() => this.teardown());
10936
10941
  }
10937
10942
  get url() {
10938
10943
  return this.newQuery.url();
10939
10944
  }
10940
10945
  get rawState() {
10941
- return this.toQueryState(this.newQuery.executionState());
10946
+ return this._mockState() ?? this.toQueryState(this.newQuery.executionState());
10947
+ }
10948
+ syncEntity(response) {
10949
+ if (!this.entity?.set) return;
10950
+ const id = this.entity.id({
10951
+ args: this._arguments,
10952
+ response
10953
+ });
10954
+ this.entity.set({
10955
+ args: this._arguments,
10956
+ response,
10957
+ id,
10958
+ store: this.entity.store
10959
+ });
10942
10960
  }
10943
10961
  toQueryState(execState) {
10944
10962
  const state = transformExecStateToQueryState(execState, this.triggerOf(execState));
@@ -10993,7 +11011,10 @@ var LegacyQuery = class {
10993
11011
  return this._canBeCached;
10994
11012
  }
10995
11013
  get _isInMockMode() {
10996
- return false;
11014
+ return !!this.mockConfig;
11015
+ }
11016
+ get mockConfig() {
11017
+ return this._arguments?.mock;
10997
11018
  }
10998
11019
  destroy() {
10999
11020
  if (this.isDestroyed) return;
@@ -11012,6 +11033,10 @@ var LegacyQuery = class {
11012
11033
  this._ownLoadSettled = false;
11013
11034
  this._responseAtExecute = untracked(this.newQuery.response);
11014
11035
  this._errorAtExecute = untracked(this.newQuery.error);
11036
+ if (this.mockConfig) {
11037
+ this.startMock(this.mockConfig);
11038
+ return this;
11039
+ }
11015
11040
  untracked(() => this.newQuery.execute({
11016
11041
  args: this._arguments,
11017
11042
  options: { allowCache: options.skipCache !== true }
@@ -11023,9 +11048,63 @@ var LegacyQuery = class {
11023
11048
  abort() {
11024
11049
  if (!isQueryStateLoading(untracked(() => this.rawState))) return this;
11025
11050
  this._wasAborted = true;
11051
+ this._mockSubscription?.unsubscribe();
11052
+ this._mockSubscription = null;
11053
+ untracked(() => this._mockState.set(null));
11026
11054
  this.newQuery.reset();
11027
11055
  return this;
11028
11056
  }
11057
+ startMock({ delay = 200, error, response, retryIntoResponse = false, progress }) {
11058
+ this._mockSubscription?.unsubscribe();
11059
+ const meta = {
11060
+ id: -1,
11061
+ triggeredVia: this._triggeredVia
11062
+ };
11063
+ const loading = (extra = {}) => this._mockState.set({
11064
+ type: QueryStateType.Loading,
11065
+ meta,
11066
+ ...extra
11067
+ });
11068
+ const settle = () => {
11069
+ if (error) {
11070
+ this._mockState.set({
11071
+ type: QueryStateType.Failure,
11072
+ meta,
11073
+ error
11074
+ });
11075
+ return;
11076
+ }
11077
+ this.syncEntity(response);
11078
+ this._mockState.set({
11079
+ type: QueryStateType.Success,
11080
+ meta,
11081
+ headers: {},
11082
+ response
11083
+ });
11084
+ };
11085
+ untracked(() => {
11086
+ loading();
11087
+ if (progress) {
11088
+ const fileSize = progress.fileSize ?? 1e6;
11089
+ const eventCount = progress.eventCount ?? 5;
11090
+ this._mockSubscription = interval(delay).pipe(takeWhile((a) => a < eventCount + 1, true)).subscribe((a) => {
11091
+ if (a === eventCount + 1) return settle();
11092
+ const current = Math.min(fileSize * a, fileSize * eventCount);
11093
+ loading({
11094
+ progress: {
11095
+ current,
11096
+ ...progress.omitTotal ? {} : {
11097
+ percentage: current / (fileSize * eventCount) * 100,
11098
+ total: fileSize
11099
+ }
11100
+ },
11101
+ ...progress.omitPartialText ? {} : { partialText: `Partial text ${a}` }
11102
+ });
11103
+ });
11104
+ } else if (retryIntoResponse) this._mockSubscription = interval(delay).pipe(takeWhile((a) => a < 3, true)).subscribe((a) => a === 3 ? settle() : loading());
11105
+ else this._mockSubscription = timer(delay).subscribe(() => settle());
11106
+ });
11107
+ }
11029
11108
  poll(config) {
11030
11109
  if (this._pollingSubscription || this.isDestroyed) return this;
11031
11110
  this._currentPollConfig = config;
@@ -11104,6 +11183,8 @@ var LegacyQuery = class {
11104
11183
  this.isDestroyed = true;
11105
11184
  this._pollingSubscription?.unsubscribe();
11106
11185
  this._pollingSubscription = null;
11186
+ this._mockSubscription?.unsubscribe();
11187
+ this._mockSubscription = null;
11107
11188
  this._dependentsChanged$.complete();
11108
11189
  this.storeSyncEffect?.destroy();
11109
11190
  }
@@ -11213,11 +11294,13 @@ var LegacyQueryCreator = class {
11213
11294
  headers = headers.set(key, value);
11214
11295
  }
11215
11296
  const variables = args?.variables;
11297
+ const mock = args?.mock;
11216
11298
  const queryArgs = {
11217
11299
  ...args?.body !== void 0 ? { body: args.body } : {},
11218
11300
  ...args?.pathParams ? { pathParams: args.pathParams } : {},
11219
11301
  ...args?.queryParams ? { queryParams: args.queryParams } : {},
11220
11302
  ...variables !== void 0 ? { variables } : {},
11303
+ ...mock ? { mock } : {},
11221
11304
  headers
11222
11305
  };
11223
11306
  if (!isInjectorUsable(injector)) {