@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 +28 -0
- package/fesm2022/ethlete-query-ngrx-toolkit.mjs +30 -7
- package/fesm2022/ethlete-query-ngrx-toolkit.mjs.map +1 -1
- package/fesm2022/ethlete-query.mjs +112 -29
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/generators/migrate-from-ngrx-toolkit/args-assignability.js +55 -8
- package/generators/migrate-from-ngrx-toolkit/consumers.js +132 -36
- package/generators/migrate-from-ngrx-toolkit/creators.js +8 -4
- package/generators/migrate-from-ngrx-toolkit/feature.js +31 -4
- package/generators/migrate-from-ngrx-toolkit/migration.js +3 -1
- package/generators/migrate-from-ngrx-toolkit/module-resolution.js +23 -0
- package/generators/migrate-from-ngrx-toolkit/store-removal.js +64 -11
- package/generators/migrate-to-query-v3/auth-provider-scaffold.js +1 -1
- package/generators/migrate-to-query-v3/cleanup-migration.js +73 -12
- package/generators/migrate-to-query-v3/legacy-prepare-migration.js +54 -21
- package/generators/migrate-to-query-v3/legacy-query-creator-migration.js +108 -15
- package/generators/migrate-to-query-v3/migration.js +4 -1
- package/generators/migrate-to-query-v3/module-resolution.js +131 -0
- package/generators/migrate-to-query-v3/rename-symbols.js +16 -11
- package/package.json +1 -1
- package/types/ethlete-query-ngrx-toolkit.d.ts +13 -0
- package/types/ethlete-query.d.ts +23 -4
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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":";;;;AASA,MAAa,8BACX,YACE;CACF,MAAM,MAAM,OAAO,iBAAiB;CACpC,IAAI,eAAe,aAAa;CAChC,IAAI,UAAyB;CAC7B,IAAI,QAAQ,QAAQ;CAEpB,MAAM,gBAAe;EACnB,aAAa,YAAW;EACxB,UAAU;EACV,QAAQ,QAAQ;CAClB;CAEA,MAAM,aAAa,UAAiB;EAClC,UAAU;EACV,eAAe,QAAQ,OAAO,KAAK,CAAC,CAAC,WAAW,SAAQ;GACtD,QAAQ;GACR,IAAI,aAAY;EAClB,CAAC;CACH;CAEA,OAAO,UAAU,CAAC,CAAC,UAAU,OAAO;CAEpC,QAAQ,UAAoC;EAC1C,IAAI,CAAC,WAAW,OAAO,UAAU,KAAK;EAEtC,IAAI,YAAY,OAAO;GACrB,QAAO;GACP,IAAI,OAAO,UAAU,KAAK;EAC5B;EAEA,OAAO;CACT;AACF;ACdA,MAAM,aAAa;AAEnB,MAAM,gBAAkC;CACtC,MAAM;CACN,gBAAgB;CAChB,WAAW;CACX,OAAO;CACP,SAAS;CACT,QAAQ;CACR,WAAW;CACX,WAAW;CACX,UAAU;CACV,WAAW;CACX,SAAS;CACT,QAAQ;CACR,cAAc;CACd,aAAa;AACd;AAED,MAAa,kBAAkB,WAC7B,cAAc;CACZ,MAAM,OAAO;CACb,gBAAgB,OAAO,gBAAgB,KAAK,UAAU,IAAI,CAAC;CAC3D,WAAW,OAAO;CAClB,OAAO,OAAO;CACd,SAAS,OAAO;CAChB,QAAQ,OAAO;CACf,WAAW,OAAO;CAClB,WAAW,OAAO;CAClB,UAAU,OAAO;CACjB,WAAW,OAAO;AACnB,CAAA,CAAC,CAAC,KACD,KAAK,YAAY;CACf,GAAG;CACH,SAAS,OAAO;CAChB,QAAQ,OAAO;CACf,cAAc,OAAO;CACrB,aAAa,OAAO;AACrB,EAAC,CAAC;AAKP,IAAa,eAAb,MAAa,aAAY;CADzB,cAAA;EAEE,KAAA,YAAY,2BAA0E;GACpF,cAAc;GACd,eAAe;GACf,QAAQ;EACT,CAAA;CACF;CANY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAY,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAZ;EAAA,KAAA,QAAA,GAAA,gBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAY,cAAA;GAAA,MAAA;GAAA,MAAA;EAAA,CAAA;CAAA;;AAAZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EADxB,MAAA;EAAK,MAAA,CAAA;GAAE,MAAM;GAAY,MAAM;EAAK,CAAE;;;AC3DvC,MAAM,uBAAuB,YAC3B,cACE,OAAO,QAAQ,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,YACrC,SAAS,CAAC,eAAe,MAAM,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,KAAK,KAAK,CAAU,CAAC,CAAC,IAAI,CAAA,CAAE,CACnF,CACF,CAAC,KAAK,KAAK,WAAW,OAAO,YAAY,MAAM,CAAC,CAAC;AAOpD,IAAa,oBAAb,MAAa,kBAAiB;CAD9B,cAAA;EAEE,KAAA,YAAY,2BAAqE;GAC/E,cAAc,CAAA;GACd,eAAe,CAAA;GACf,QAAQ;EACT,CAAA;CACF;CANY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAjB;EAAA,KAAA,QAAA,GAAA,gBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,cAAA;GAAA,MAAA;GAAA,MAAA;EAAA,CAAA;CAAA;;AAAjB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAD7B,MAAA;EAAK,MAAA,CAAA;GAAE,MAAM;GAAiB,MAAM;EAAK,CAAE;;;ACd5C,IAAa,oBAAb,MAAa,kBAAiB;CAAjB;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAjB;EAAA,KAAA,OAAA,GAAA,oBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,SAAA,CAHlB,cAAc,iBAAiB;GAAA,SAAA,CAC/B,cAAc,iBAAiB;EAAA,CAAA;CAAA;CAE9B;EAAA,KAAA,OAAA,GAAA,oBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;EAAiB,CAAA;CAAA;;AAAjB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAJ7B,MAAA;EAAS,MAAA,CAAA;GACR,SAAS,CAAC,cAAc,iBAAiB;GACzC,SAAS,CAAC,cAAc,iBAAiB;EAC1C,CAAA;;;ACJD,MAAa,YAAY;CACvB,MAAM;CACN,SAAS;CACT,SAAS;CACT,OAAO;AACC;ACsCV,MAAM,iBAAwC;CAC5C,MAAM;CACN,WAAW;CACX,UAAU;CACV,OAAO;CACP,WAAW;AACZ;AAED,MAAM,eAAe,UAAuD;CAC1E,QAAQ,OAAO,MAAf;EACE,KAAK,WACH,OAAO,UAAU;EACnB,KAAK,WACH,OAAO,UAAU;EACnB,SACE,OAAO,UAAU;CACrB;AACF;AAEA,MAAM,kBAAkB,WAA6C;CACnE,QAAQ,MAAM,IAAI;CAClB,SAAS,MAAM,IAAI;CACnB,MAAM,MAAM,IAAI,SAAS;AAC1B;AAED,MAAM,yBAAyB,WAC7B,GAAG,OAAM;AAKX,MAAa,eAAe,SAAiC;CAC3D,MAAM,gBAAgB,KAAK;CAC3B,MAAM,YAAqC,CAAA;CAE3C,IAAI,KAAK,mBAAmB,QAAW,UAAU,gBAAgB,KAAK;CACtE,IAAI,KAAK,cAAc,QAAW,UAAU,iBAAiB,KAAK;CAClE,IAAI,KAAK,YAAY,QAAW,UAAU,UAAU,KAAK;CACzD,IAAI,eAAe,YAAY,QAAW,UAAU,aAAa,cAAc;CAE/E,OAAO;AACT;AAEA,MAAa,uBACX,SACA,aACsB;CACtB,MAAM,QAAQ,QAAQ;EAAE;EAAU,qBAAqB;EAAM,oCAAoC;CAAI,CAAE;CAEvG,MAAM,aAAa,OAAwC,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAChE,MAAM,eAAe,eAAc;EACjC,MAAM,QAAQ,MAAM,MAAK;EAEzB,OAAO,QAAQ,eAAe,KAAK,IAAI;CACzC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CACF,MAAM,WAAW,eAAqC;EACpD,MAAM,cAAc,WAAU;EAE9B,IAAI,CAAC,aAAa,OAAO;EAEzB,MAAM,QAAQ,MAAM,eAAc;EAClC,MAAM,YAAY,YAAY,KAAK;EAEnC,OAAO;GACL,MAAM;GACN;GACA,UAAU,OAAO,SAAS,YAAY,MAAM,WAAW;GACvD,OAAO,cAAc,UAAU,QAAQ,aAAY,IAAK;GACxD,WAAW,KAAK,IAAG;EACpB;CACH,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEF,MAAM,UAAU,IAAI,QAAO;CAE3B,MAAM,gBAAgB,aACf;EACH,MAAM,UAAU,SAAQ;EACxB,gBAAgB,QAAQ,KAAK,OAAO,CAAC;CACvC,GAAC;EAAA,GAAA,YAAA,EAAA,WAAA,gBAAA,+BAAA,CAAA;EACC;CAAQ,CAAA;CAGZ,IAAI,mBAAiD;CACrD,IAAI,qBAAqB;CAEzB,MAAM,uBAAuB,WAAsC;EACjE,IAAI,CAAC,kBAAkB,OAAO;EAE9B,IAAI,UAAS,KAAM,CAAC,oBAAoB;GACtC,qBAAqB;GACrB,QAAQ,KAAK,sBAAsB,MAAM,CAAC;EAC5C;EAEA,OAAO;CACT;CAEA,MAAM,UAAa,SACjB,YAAa,mBAAmB,GAAG,gBAAgB,IAAI,QAAQ,KAAK,UAAU,UAAU,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,KACpG,IAAI,IAAI,GACR,qBAAoB,CAAE;CAG1B,MAAM,QAAQ,SAAkC;EAC9C,WAAW,IAAI,IAAI;EACnB,MAAM,QAAQ,EAAE,MAAM,YAAY,IAA+B,EAAC,CAAE;CACtE;CAEA,MAAM,gBAAe;EACnB,IAAI,oBAAoB,SAAS,GAAG;EAEpC,MAAM,WAAW,UAAU,UAAU;EAErC,IAAI,UAAU,KAAK,QAAQ;CAC7B;CAEA,IAAI,sBAAsB,aAAa;CAEvC,MAAM,oBAAoB,oBAAoB,YAAW;CAEzD,MAAM,gBAAgB,EAAE,kBAAkB,iBAAuC;EAC/E,IAAI,oBAAoB,cAAc,KAAK,CAAC,oBAAoB,QAAQ;EAExE,sBAAsB,SAAS,gBAAgB,CAAC,CAC7C,KACC,UAAU,UAAU,GACpB,eAAgB,sBAAsB,aAAa,KAAM,CAAC,CAC3D,CACA,gBAAgB,QAAO,CAAE;CAC9B;CAEA,MAAM,eAAc;EAClB,YAAW;EACX,WAAW,IAAI,IAAI;EACnB,MAAM,MAAK;CACb;CAEA,MAAM,wBAAwB,SAAS,IAAI,UAAU,CAAC,CAAC,gBAAe;EACpE,YAAW;EACX,QAAQ,SAAQ;CAClB,CAAC;CAED,MAAM,gBAAe;EACnB,mBAAmB,UAAU,QAAQ;EACrC,YAAW;EACX,cAAc,QAAO;EACrB,sBAAqB;EACrB,QAAQ,SAAQ;EAChB,MAAM,OAAO,QAAO;CACtB;CAEA,MAAM,2BAA0B;EAC9B,MAAM,gBAAgB,aACf;GACH,IAAI,SAAQ,CAAE,CAAC,cAAc,UAAU,SAAS;GAEhD,cAAc,QAAO;GACrB,UAAU,OAAO;EACnB,GAAC;GAAA,GAAA,YAAA,EAAA,WAAA,gBAAA,+BAAA,CAAA;GACC;EAAQ,CAAA;CAEd;CAIA,MAAM,YAAY,QAAQ,YAAY,QAAQ,QAA4B;CAmB1E,OAAO;EAAE;GAhBP;GACA,iBAAiB,UAAU,KAAK,QAAQ,aAAoC,CAAC,CAAC,QAAQ,CAAC;GACvF,QAAQ,QAAQ,YAAY,QAAQ,KAAK;GACzC,OAAO,QAAQ,YAAY,QAAQ,IAAuC;GAC1E,SAAS,QAAQ,YAAY,QAAQ,cAAc,UAAU,IAAI;GACjE,YAAY,QAAQ,YAAY,QAAQ,cAAc,UAAU,OAAO;GACvE,YAAY,QAAQ,YAAY,QAAQ,cAAc,UAAU,OAAO;GACvE,UAAU,QAAQ,YAAY,QAAQ,cAAc,UAAU,KAAK;GACnE,YAAY,QAAQ,YAAY,QAAQ,SAAS;GACjD,YAAY,QAAQ,YAAY,QAAQ,SAAS;GACjD;GACA;GACA;GACA;EAGO;EAAQ;EAAM;CAAkB;AAC3C;ACrNA,MAAM,6BAA6B,IAAI,QAAO;AAE9C,IAAM,uBAAN,cAAmC,MAAK,CAAG;AAE3C,MAAM,iBAAiB,UAAiB;CACtC,MAAM,YAAY,OAAO,eAAe,KAAK;CAE7C,OAAO,cAAc,OAAO,aAAa,cAAc;AACzD;AAEA,MAAM,iBAAiB,UAA2B;CAChD,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,MAAM,IAAI,aAAa;CACxD,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,IAAI,iBAAiB,MAAM,OAAO,EAAE,UAAc,MAAM,QAAO,EAAE;CACjE,IAAI,CAAC,cAAc,KAAK,GAAG,MAAM,IAAI,qBAAoB;CAEzD,OAAO,OAAO,YACZ,OAAO,KAAK,KAAK,CAAC,CACf,KAAI,CAAE,CACN,KAAK,QAAQ,CAAC,KAAK,cAAe,MAAkC,IAAI,CAAC,CAAC,CAAC;AAElF;AAEA,MAAM,mBAAmB,YAAqC;CAC5D,MAAM,WAAW,oBAAoB,OAAO;CAE5C,OAAO,UACH,KAAI,CAAE,CACP,KAAK,SAAS,KAAK,YAAW,CAAE,CAAC,CACjC,KAAI,CAAE,CACN,KAAK,SAAS,CAAC,MAAM,SAAS,OAAO,IAAI,CAAC,CAAC;AAChD;AAMA,MAAM,YAAY,SAA4B;CAC5C,MAAM,EAAE,SAAS,GAAG,SAAS;CAE7B,IAAI;EACF,OAAO,KAAK,UAAU,CAAC,cAAc,IAAI,GAAG,gBAAgB,OAAO,KAAK,IAAI,CAAC;CAC/E,SAAS,OAAO;EACd,IAAI,iBAAiB,sBAAsB,OAAO;EAElD,MAAM;CACR;AACF;AAEA,MAAM,8BAA8B,IAAmC,YAAgC;CACrG,IAAI,SAAS,UAAU,OAAO,QAAQ,SAAS,IAAI,mBAAmB;CAEtE,yBAAyB,EAAE;CAE3B,OAAO,OAAO,mBAAmB;AACnC;AAEA,MAAM,gBACJ,SACA,MACA,aACE;CACF,IAAI,WAAW,WAAW,IAAI,QAAQ;CAEtC,IAAI,CAAC,UAAU;EACb,WAAW;GAAE,wBAAQ,IAAI,QAAO;GAAI,gCAAgB,IAAI,QAAO;EAAE;EACjE,WAAW,IAAI,UAAU,QAAQ;CACnC;CAEA,MAAM,MAAM,SAAS,YAAY,IAA+B,CAAC;CAEjE,IAAI,QAAQ,MAAM;EAChB,MAAM,QAAQ,oBAAoB,SAAS,QAAQ;EAEnD,SAAS,eAAe,IAAI,OAAO,CAAC,EAAE,mBAAkB;EACxD,SAAS,eAAe,IAAI,SAAS,KAAK;EAE1C,OAAO;CACT;CAEA,IAAI,UAAU,SAAS,OAAO,IAAI,OAAO;CAEzC,IAAI,CAAC,SAAS;EACZ,0BAAU,IAAI,IAAG;EACjB,SAAS,OAAO,IAAI,SAAS,OAAO;CACtC;CAEA,IAAI,QAAQ,QAAQ,IAAI,GAAG;CAE3B,IAAI,CAAC,OAAO;EACV,QAAQ,oBAAoB,SAAS,QAAQ;EAC7C,QAAQ,IAAI,KAAK,KAAK;CACxB;CAEA,OAAO;AACT;AAQA,MAAa,iBACX,SACA,MACA,YAEA,aAAa,SAAS,MAAM,2BAA2B,eAAe,OAAO,CAAC,CAAC,CAAC;AAmBlF,MAAa,eACX,SACA,MACA,YAC+B;CAC/B,MAAM,QAAQ,aAAa,SAAS,MAAM,2BAA2B,aAAa,OAAO,CAAC;CAE1F,MAAM,KAAK,IAAI;CAEf,OAAO,MAAM;AACf;ACvJA,MAAa,eAAe,gBAC1B,cAAc,YAAY,QAAQ,MAAuC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAC7E,KAAK,WAAW,OAAO,MAAM,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC;AAIpD,MAAa,cACX,gBAEA,cAAc,YAAY,QAAQ,MAA4C,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAClF,KAAK,WAAU;CACb,MAAM,SAAS,OAAO,QAAQ,UAAiC,CAAC,CAAC,KAAK;CAEtE,OAAO,OAAO,SAAS,SAAS;AAClC,CAAC,CAAC"}
|
|
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":";;;;AASA,MAAa,8BACX,YACE;CACF,MAAM,MAAM,OAAO,iBAAiB;CACpC,IAAI,eAAe,aAAa;CAChC,IAAI,UAAyB;CAC7B,IAAI,QAAQ,QAAQ;CAEpB,MAAM,gBAAe;EACnB,aAAa,YAAW;EACxB,UAAU;EACV,QAAQ,QAAQ;CAClB;CAEA,MAAM,aAAa,UAAiB;EAClC,UAAU;EACV,eAAe,QAAQ,OAAO,KAAK,CAAC,CAAC,WAAW,SAAQ;GACtD,QAAQ;GACR,IAAI,aAAY;EAClB,CAAC;CACH;CAEA,OAAO,UAAU,CAAC,CAAC,UAAU,OAAO;CAEpC,QAAQ,UAAoC;EAC1C,IAAI,CAAC,WAAW,OAAO,UAAU,KAAK;EAEtC,IAAI,YAAY,OAAO;GACrB,QAAO;GACP,IAAI,OAAO,UAAU,KAAK;EAC5B;EAEA,OAAO;CACT;AACF;ACdA,MAAM,aAAa;AAEnB,MAAM,gBAAkC;CACtC,MAAM;CACN,gBAAgB;CAChB,WAAW;CACX,OAAO;CACP,SAAS;CACT,QAAQ;CACR,WAAW;CACX,WAAW;CACX,UAAU;CACV,WAAW;CACX,SAAS;CACT,QAAQ;CACR,cAAc;CACd,aAAa;AACd;AAED,MAAa,kBAAkB,WAC7B,cAAc;CACZ,MAAM,OAAO;CACb,gBAAgB,OAAO,gBAAgB,KAAK,UAAU,IAAI,CAAC;CAC3D,WAAW,OAAO;CAClB,OAAO,OAAO;CACd,SAAS,OAAO;CAChB,QAAQ,OAAO;CACf,WAAW,OAAO;CAClB,WAAW,OAAO;CAClB,UAAU,OAAO;CACjB,WAAW,OAAO;AACnB,CAAA,CAAC,CAAC,KACD,KAAK,YAAY;CACf,GAAG;CACH,SAAS,OAAO;CAChB,QAAQ,OAAO;CACf,cAAc,OAAO;CACrB,aAAa,OAAO;AACrB,EAAC,CAAC;AAKP,IAAa,eAAb,MAAa,aAAY;CADzB,cAAA;EAEE,KAAA,YAAY,2BAA0E;GACpF,cAAc;GACd,eAAe;GACf,QAAQ;EACT,CAAA;CACF;CANY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAY,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAZ;EAAA,KAAA,QAAA,GAAA,gBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAY,cAAA;GAAA,MAAA;GAAA,MAAA;EAAA,CAAA;CAAA;;AAAZ,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EADxB,MAAA;EAAK,MAAA,CAAA;GAAE,MAAM;GAAY,MAAM;EAAK,CAAE;;;AC3DvC,MAAM,uBAAuB,YAC3B,cACE,OAAO,QAAQ,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,YACrC,SAAS,CAAC,eAAe,MAAM,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,KAAK,KAAK,CAAU,CAAC,CAAC,IAAI,CAAA,CAAE,CACnF,CACF,CAAC,KAAK,KAAK,WAAW,OAAO,YAAY,MAAM,CAAC,CAAC;AAOpD,IAAa,oBAAb,MAAa,kBAAiB;CAD9B,cAAA;EAEE,KAAA,YAAY,2BAAqE;GAC/E,cAAc,CAAA;GACd,eAAe,CAAA;GACf,QAAQ;EACT,CAAA;CACF;CANY;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAjB;EAAA,KAAA,QAAA,GAAA,gBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,cAAA;GAAA,MAAA;GAAA,MAAA;EAAA,CAAA;CAAA;;AAAjB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAD7B,MAAA;EAAK,MAAA,CAAA;GAAE,MAAM;GAAiB,MAAM;EAAK,CAAE;;;ACd5C,IAAa,oBAAb,MAAa,kBAAiB;CAAjB;EAAA,KAAA,OAAA,GAAA,mBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,MAAA,CAAA;GAAA,QAAA,GAAA,gBAAA;EAAA,CAAA;CAAA;CAAjB;EAAA,KAAA,OAAA,GAAA,oBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;GAAiB,SAAA,CAHlB,cAAc,iBAAiB;GAAA,SAAA,CAC/B,cAAc,iBAAiB;EAAA,CAAA;CAAA;CAE9B;EAAA,KAAA,OAAA,GAAA,oBAAA;GAAA,YAAA;GAAA,SAAA;GAAA,UAAA;GAAA,MAAA;EAAiB,CAAA;CAAA;;AAAjB,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAJ7B,MAAA;EAAS,MAAA,CAAA;GACR,SAAS,CAAC,cAAc,iBAAiB;GACzC,SAAS,CAAC,cAAc,iBAAiB;EAC1C,CAAA;;;ACJD,MAAa,YAAY;CACvB,MAAM;CACN,SAAS;CACT,SAAS;CACT,OAAO;AACC;ACsCV,MAAM,iBAAwC;CAC5C,MAAM;CACN,WAAW;CACX,UAAU;CACV,OAAO;CACP,WAAW;AACZ;AAED,MAAM,eAAe,UAAuD;CAC1E,QAAQ,OAAO,MAAf;EACE,KAAK,WACH,OAAO,UAAU;EACnB,KAAK,WACH,OAAO,UAAU;EACnB,SACE,OAAO,UAAU;CACrB;AACF;AAEA,MAAM,kBAAkB,WAA6C;CACnE,QAAQ,MAAM,IAAI;CAClB,SAAS,MAAM,IAAI;CACnB,MAAM,MAAM,IAAI,SAAS;AAC1B;AAED,MAAM,yBAAyB,WAC7B,GAAG,OAAM;AAKX,MAAa,eAAe,SAAiC;CAC3D,MAAM,gBAAgB,KAAK;CAC3B,MAAM,YAAqC,CAAA;CAE3C,IAAI,KAAK,mBAAmB,QAAW,UAAU,gBAAgB,KAAK;CACtE,IAAI,KAAK,cAAc,QAAW,UAAU,iBAAiB,KAAK;CAClE,IAAI,KAAK,YAAY,QAAW,UAAU,UAAU,KAAK;CACzD,IAAI,eAAe,YAAY,QAAW,UAAU,aAAa,cAAc;CAE/E,OAAO;AACT;AAEA,MAAa,uBACX,SACA,UACA,cACsB;CACtB,MAAM,QAAQ,QAAQ;EAAE;EAAU,qBAAqB;EAAM,oCAAoC;CAAI,CAAE;CAEvG,MAAM,aAAa,OAAwC,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAChE,MAAM,eAAe,eAAc;EACjC,MAAM,QAAQ,MAAM,MAAK;EAEzB,OAAO,QAAQ,eAAe,KAAK,IAAI;CACzC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CACF,MAAM,WAAW,eAAqC;EACpD,MAAM,cAAc,WAAU;EAE9B,IAAI,CAAC,aAAa,OAAO;EAEzB,MAAM,QAAQ,MAAM,eAAc;EAClC,MAAM,YAAY,YAAY,KAAK;EAEnC,OAAO;GACL,MAAM;GACN;GACA,UAAU,OAAO,SAAS,YAAY,MAAM,WAAW;GACvD,OAAO,cAAc,UAAU,QAAQ,aAAY,IAAK;GACxD,WAAW,KAAK,IAAG;EACpB;CACH,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEF,MAAM,UAAU,IAAI,QAAO;CAE3B,IAAI,cAAiD;CAErD,MAAM,gBAAgB,aACf;EACH,MAAM,UAAU,SAAQ;EACxB,MAAM,QAAQ,MAAM,eAAc;EAElC,gBAAe;GACb,QAAQ,KAAK,OAAO;GAEpB,IAAI,QAAQ,cAAc,UAAU,WAAW,UAAU,aAAa;IACpE,cAAc;IACd,UAAU,QAAQ,QAAQ;GAC5B;EACF,CAAC;CACH,GAAC;EAAA,GAAA,YAAA,EAAA,WAAA,gBAAA,+BAAA,CAAA;EACC;CAAQ,CAAA;CAGZ,IAAI,mBAAiD;CACrD,IAAI,qBAAqB;CAEzB,MAAM,uBAAuB,WAAsC;EACjE,IAAI,CAAC,kBAAkB,OAAO;EAE9B,IAAI,UAAS,KAAM,CAAC,oBAAoB;GACtC,qBAAqB;GACrB,QAAQ,KAAK,sBAAsB,MAAM,CAAC;EAC5C;EAEA,OAAO;CACT;CAEA,MAAM,UAAa,SACjB,YAAa,mBAAmB,GAAG,gBAAgB,IAAI,QAAQ,KAAK,UAAU,UAAU,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,KACpG,IAAI,IAAI,GACR,qBAAoB,CAAE;CAG1B,MAAM,QAAQ,SAAkC;EAC9C,WAAW,IAAI,IAAI;EACnB,MAAM,QAAQ,EAAE,MAAM,YAAY,IAA+B,EAAC,CAAE;CACtE;CAEA,MAAM,gBAAe;EACnB,IAAI,oBAAoB,SAAS,GAAG;EAEpC,MAAM,WAAW,UAAU,UAAU;EAErC,IAAI,UAAU,KAAK,QAAQ;CAC7B;CAEA,IAAI,sBAAsB,aAAa;CAEvC,MAAM,oBAAoB,oBAAoB,YAAW;CAEzD,MAAM,gBAAgB,EAAE,kBAAkB,iBAAuC;EAC/E,IAAI,oBAAoB,cAAc,KAAK,CAAC,oBAAoB,QAAQ;EAExE,sBAAsB,SAAS,gBAAgB,CAAC,CAC7C,KACC,UAAU,UAAU,GACpB,eAAgB,sBAAsB,aAAa,KAAM,CAAC,CAC3D,CACA,gBAAgB,QAAO,CAAE;CAC9B;CAEA,MAAM,eAAc;EAClB,YAAW;EACX,WAAW,IAAI,IAAI;EACnB,MAAM,MAAK;CACb;CAEA,MAAM,wBAAwB,SAAS,IAAI,UAAU,CAAC,CAAC,gBAAe;EACpE,YAAW;EACX,QAAQ,SAAQ;CAClB,CAAC;CAED,MAAM,gBAAe;EACnB,mBAAmB,UAAU,QAAQ;EACrC,YAAW;EACX,cAAc,QAAO;EACrB,sBAAqB;EACrB,QAAQ,SAAQ;EAChB,MAAM,OAAO,QAAO;CACtB;CAEA,MAAM,2BAA0B;EAC9B,MAAM,gBAAgB,aACf;GACH,IAAI,SAAQ,CAAE,CAAC,cAAc,UAAU,SAAS;GAEhD,cAAc,QAAO;GACrB,UAAU,OAAO;EACnB,GAAC;GAAA,GAAA,YAAA,EAAA,WAAA,gBAAA,+BAAA,CAAA;GACC;EAAQ,CAAA;CAEd;CAIA,MAAM,YAAY,QAAQ,YAAY,QAAQ,QAA4B;CAmB1E,OAAO;EAAE;GAhBP;GACA,iBAAiB,UAAU,KAAK,QAAQ,aAAoC,CAAC,CAAC,QAAQ,CAAC;GACvF,QAAQ,QAAQ,YAAY,QAAQ,KAAK;GACzC,OAAO,QAAQ,YAAY,QAAQ,IAAuC;GAC1E,SAAS,QAAQ,YAAY,QAAQ,cAAc,UAAU,IAAI;GACjE,YAAY,QAAQ,YAAY,QAAQ,cAAc,UAAU,OAAO;GACvE,YAAY,QAAQ,YAAY,QAAQ,cAAc,UAAU,OAAO;GACvE,UAAU,QAAQ,YAAY,QAAQ,cAAc,UAAU,KAAK;GACnE,YAAY,QAAQ,YAAY,QAAQ,SAAS;GACjD,YAAY,QAAQ,YAAY,QAAQ,SAAS;GACjD;GACA;GACA;GACA;EAGO;EAAQ;EAAM;CAAkB;AAC3C;ACxNA,MAAM,6BAA6B,IAAI,QAAO;AAE9C,IAAM,uBAAN,cAAmC,MAAK,CAAG;AAE3C,MAAM,iBAAiB,UAAiB;CACtC,MAAM,YAAY,OAAO,eAAe,KAAK;CAE7C,OAAO,cAAc,OAAO,aAAa,cAAc;AACzD;AAEA,MAAM,iBAAiB,UAA2B;CAChD,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,MAAM,IAAI,aAAa;CACxD,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,IAAI,iBAAiB,MAAM,OAAO,EAAE,UAAc,MAAM,QAAO,EAAE;CACjE,IAAI,CAAC,cAAc,KAAK,GAAG,MAAM,IAAI,qBAAoB;CAEzD,OAAO,OAAO,YACZ,OAAO,KAAK,KAAK,CAAC,CACf,KAAI,CAAE,CACN,KAAK,QAAQ,CAAC,KAAK,cAAe,MAAkC,IAAI,CAAC,CAAC,CAAC;AAElF;AAEA,MAAM,mBAAmB,YAAqC;CAC5D,MAAM,WAAW,oBAAoB,OAAO;CAE5C,OAAO,UACH,KAAI,CAAE,CACP,KAAK,SAAS,KAAK,YAAW,CAAE,CAAC,CACjC,KAAI,CAAE,CACN,KAAK,SAAS,CAAC,MAAM,SAAS,OAAO,IAAI,CAAC,CAAC;AAChD;AAMA,MAAM,YAAY,SAA4B;CAC5C,MAAM,EAAE,SAAS,GAAG,SAAS;CAE7B,IAAI;EACF,OAAO,KAAK,UAAU,CAAC,cAAc,IAAI,GAAG,gBAAgB,OAAO,KAAK,IAAI,CAAC;CAC/E,SAAS,OAAO;EACd,IAAI,iBAAiB,sBAAsB,OAAO;EAElD,MAAM;CACR;AACF;AAEA,MAAM,8BAA8B,IAAmC,YAAgC;CACrG,IAAI,SAAS,UAAU,OAAO,QAAQ,SAAS,IAAI,mBAAmB;CAEtE,yBAAyB,EAAE;CAE3B,OAAO,OAAO,mBAAmB;AACnC;AAEA,MAAM,cAAc,aAAiC;CACnD,IAAI,WAAW,WAAW,IAAI,QAAQ;CAEtC,IAAI,CAAC,UAAU;EACb,MAAM,YAAY,IAAI,QAAO;EAE7B,WAAW;GAAE,wBAAQ,IAAI,QAAO;GAAI,gCAAgB,IAAI,QAAO;GAAI;EAAS;EAC5E,WAAW,IAAI,UAAU,QAAQ;EACjC,SAAS,IAAI,UAAU,CAAC,CAAC,gBAAgB,UAAU,SAAQ,CAAE;CAC/D;CAEA,OAAO;AACT;AAEA,MAAM,aACJ,SACA,UACA,aACG,oBAAoB,SAAS,WAAW,aAAa,SAAS,UAAU,KAAK;CAAE;CAAS;AAAQ,CAAE,CAAC;AAExG,MAAM,gBACJ,SACA,MACA,aACE;CACF,MAAM,WAAW,WAAW,QAAQ;CAEpC,MAAM,MAAM,SAAS,YAAY,IAA+B,CAAC;CAEjE,IAAI,QAAQ,MAAM;EAChB,MAAM,QAAQ,UAAU,SAAS,UAAU,QAAQ;EAEnD,SAAS,eAAe,IAAI,OAAO,CAAC,EAAE,mBAAkB;EACxD,SAAS,eAAe,IAAI,SAAS,KAAK;EAE1C,OAAO;CACT;CAEA,IAAI,UAAU,SAAS,OAAO,IAAI,OAAO;CAEzC,IAAI,CAAC,SAAS;EACZ,0BAAU,IAAI,IAAG;EACjB,SAAS,OAAO,IAAI,SAAS,OAAO;CACtC;CAEA,IAAI,QAAQ,QAAQ,IAAI,GAAG;CAE3B,IAAI,CAAC,OAAO;EACV,QAAQ,UAAU,SAAS,UAAU,QAAQ;EAC7C,QAAQ,IAAI,KAAK,KAAK;CACxB;CAEA,OAAO;AACT;AAQA,MAAa,iBACX,SACA,MACA,YAEA,aAAa,SAAS,MAAM,2BAA2B,eAAe,OAAO,CAAC,CAAC,CAAC;AAmBlF,MAAa,eACX,SACA,MACA,YAC+B;CAC/B,MAAM,QAAQ,aAAa,SAAS,MAAM,2BAA2B,aAAa,OAAO,CAAC;CAE1F,MAAM,KAAK,IAAI;CAEf,OAAO,MAAM;AACf;AAeA,MAAa,oBACX,UACA,YAC+G;CAC/G,MAAM,UAAU,IAAI,IAAqB,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAA2B,CAAC;CAE3G,OAAO,WAAW,2BAA2B,kBAAkB,OAAO,CAAC,CAAC,CAAC,UAAU,KACjF,QAAQ,YAAY,QAAQ,IAAI,QAAQ,OAAO,CAAC,GAChD,KAAK,YAAY,QAAQ,QAAiB,CAAC;AAE/C;ACxMA,MAAa,eAAe,gBAC1B,cAAc,YAAY,QAAQ,MAAuC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAC7E,KAAK,WAAW,OAAO,MAAM,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC;AAIpD,MAAa,cACX,gBAEA,cAAc,YAAY,QAAQ,MAA4C,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAClF,KAAK,WAAU;CACb,MAAM,SAAS,OAAO,QAAQ,UAAiC,CAAC,CAAC,KAAK;CAEtE,OAAO,OAAO,SAAS,SAAS;AAClC,CAAC,CAAC"}
|
|
@@ -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
|
|
702
|
-
|
|
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 `${
|
|
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 `${
|
|
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.
|
|
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
|
|
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$ =
|
|
10934
|
-
|
|
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
|
|
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)) {
|