ngx-signal-query 1.5.0-dev.2 → 1.5.0-dev.4

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/index.d.ts CHANGED
@@ -18,7 +18,10 @@ declare abstract class Cache<TEntry> {
18
18
  * array, from broad to specific, e.g. `['todos']` or `['todo', id]`.
19
19
  */
20
20
  type QueryKey = readonly unknown[];
21
- /** Lifecycle status of a query: no data yet, resolved, or failed. */
21
+ /**
22
+ * Lifecycle status of a query: no data yet (the first load, or a new attempt
23
+ * after a failure), resolved, or failed.
24
+ */
22
25
  type QueryStatus = 'pending' | 'success' | 'error';
23
26
  /** Full state snapshot of a query (the reactive source behind {@link QueryResult}). */
24
27
  interface QueryState<TData, TError = Error> {
@@ -26,7 +29,11 @@ interface QueryState<TData, TError = Error> {
26
29
  data: TData | undefined;
27
30
  /** Current {@link QueryStatus}. */
28
31
  status: QueryStatus;
29
- /** Last error, or `null` if the latest attempt did not fail. */
32
+ /**
33
+ * The error the last fetch failed with, or `null`. A query with no data
34
+ * clears it when it fetches again; one with data keeps it until the next
35
+ * response.
36
+ */
30
37
  error: TError | null;
31
38
  /** Whether a fetch is currently in flight. */
32
39
  isFetching: boolean;
@@ -46,6 +53,16 @@ type QueryFilters = {
46
53
  /** Require an exact key match instead of a prefix match. */
47
54
  exact?: boolean;
48
55
  };
56
+ /** Selects which queries `invalidateQueries` marks stale, and what it refetches. */
57
+ type InvalidateQueryFilters = QueryFilters & {
58
+ /**
59
+ * Which of the marked queries to refetch now: `'active'`, the default,
60
+ * refetches those a component shows; `'none'` refetches none, so each one
61
+ * refetches when stale data next would, e.g. as a component starts showing
62
+ * it. Queries nobody shows are only marked either way.
63
+ */
64
+ refetchType?: 'active' | 'none';
65
+ };
49
66
  /** A new value, or a function deriving it from the previous one. */
50
67
  type Updater<TInput, TOutput> = TOutput | ((input: TInput) => TOutput);
51
68
  /**
@@ -166,11 +183,18 @@ type QueryResult<TData, TError = Error> = {
166
183
  data: Signal<TData | undefined>;
167
184
  /** Current {@link QueryStatus}. */
168
185
  status: Signal<QueryStatus>;
169
- /** Last error, or `null`. */
186
+ /**
187
+ * The error the last fetch failed with, or `null`. It's cleared while a
188
+ * query with no data is tried again, and kept while one with data
189
+ * refetches.
190
+ */
170
191
  error: Signal<TError | null>;
171
192
  /** Whether a fetch is in flight (including background refetches). */
172
193
  isFetching: Signal<boolean>;
173
- /** Whether the first fetch is in flight with no data yet (`isFetching && pending`). */
194
+ /**
195
+ * Whether a fetch is in flight with no data to show: the first one, or a
196
+ * new attempt after a failure (`isFetching && pending`).
197
+ */
174
198
  isLoading: Signal<boolean>;
175
199
  /** Whether status is `'pending'` (no data resolved yet). */
176
200
  isPending: Signal<boolean>;
@@ -184,8 +208,16 @@ type QueryResult<TData, TError = Error> = {
184
208
  failureCount: Signal<number>;
185
209
  /** Error of the most recent failed attempt, or `null`. */
186
210
  failureReason: Signal<TError | null>;
187
- /** Forces a fresh fetch, cancelling any in-flight request. */
188
- refetch: () => void;
211
+ /**
212
+ * Forces a fresh fetch, cancelling any in-flight request. Resolves once the
213
+ * fetch has settled, or the fetch that replaced it has, with `data` and
214
+ * `error` as the signals above hold them then. It never rejects: a failure
215
+ * shows in `error`.
216
+ */
217
+ refetch: () => Promise<{
218
+ data: TData | undefined;
219
+ error: TError | null;
220
+ }>;
189
221
  };
190
222
  /** Default query options applied to every query unless overridden per-query. */
191
223
  interface DefaultQueryOptions {
@@ -265,7 +297,7 @@ declare class Query<TData, TError = Error> {
265
297
  setGcTime(ms: number): void;
266
298
  addObserver(observer: QuerySubscriber<TData, TError>): void;
267
299
  removeObserver(observer: QuerySubscriber<TData, TError>): void;
268
- activeFetchOptions(): ReturnType<QuerySubscriber<TData, TError>['fetchOptions']>;
300
+ refetchIfActive(): Promise<TData> | undefined;
269
301
  onFocus(): void;
270
302
  onOnline(): void;
271
303
  structuralSharing(): StructuralSharingValue<TData> | undefined;
@@ -364,6 +396,14 @@ type MutationOptions<TData, TError, TVariables, TContext> = {
364
396
  type MutationResult<TData, TError, TVariables> = {
365
397
  /** Triggers the mutation with the given variables. */
366
398
  mutate: (variables: TVariables) => void;
399
+ /**
400
+ * Triggers the mutation as `mutate()` does, and returns a promise of that
401
+ * run: it resolves with the data once the last hook is done, or rejects
402
+ * with the error once `onError` and `onSettled` are. Unlike `mutate()`, a
403
+ * failure nobody catches surfaces as an unhandled rejection, as with any
404
+ * async call.
405
+ */
406
+ mutateAsync: (variables: TVariables) => Promise<TData>;
367
407
  /**
368
408
  * Resets the state to `idle`. It forgets the result and doesn't stop the
369
409
  * request: a run in flight finishes and fires its hooks.
@@ -405,8 +445,12 @@ declare class Mutation<TData = unknown, TError = Error, TVariables = void, TCont
405
445
  * settled and been abandoned — whichever of the two happens last.
406
446
  */
407
447
  removeObserver(): void;
408
- /** Runs the mutation once. `variables` are passed straight to `mutationFn`. */
409
- execute(variables: TVariables): void;
448
+ /**
449
+ * Runs the mutation once. `variables` are passed straight to `mutationFn`.
450
+ * Returns a promise of the run, settled as the state is, once its last hook
451
+ * is done: with the data, or with the error.
452
+ */
453
+ execute(variables: TVariables): Promise<TData>;
410
454
  cancel(): void;
411
455
  }
412
456
 
@@ -463,12 +507,38 @@ declare class QueryClient {
463
507
  /**
464
508
  * Imperatively fetches and caches a query, unless fresh data already exists
465
509
  * (governed by `staleTime`). Prefer {@link injectQuery} in components; use
466
- * this to prefetch, from an event handler or an effect.
510
+ * this to prefetch, from an event handler or an effect, or to wait for the
511
+ * data, e.g. in a route resolver.
512
+ *
513
+ * Resolves with the data as the cache holds it: at once if it's fresh,
514
+ * otherwise once the fetch lands. A key already fetching is waited for,
515
+ * not fetched again, unless `cancelRefetch` is set. Rejects with the error
516
+ * if the fetch fails. A cancelled fetch resolves with the data the cache
517
+ * holds, or rejects with a {@link CancelledError} if it holds none; a
518
+ * removed query always rejects with one. Nothing has to wait for the
519
+ * promise: a prefetch that fails only leaves the query in `'error'`.
520
+ *
521
+ * Unlike a component's query, it doesn't retry a failure unless `retry` is
522
+ * set here or in {@link withDefaultOptions}, so whoever waits for the data
523
+ * hears of the failure at once.
467
524
  *
468
525
  * @param key - The query key to fetch and cache under.
469
526
  * @param queryFn - Function returning the data as an `Observable` or `Promise`.
470
527
  * @param options - Fetch tuning (`staleTime`, `retry`, `retryDelay`,
471
528
  * `structuralSharing`, `cancelRefetch`).
529
+ * @returns A promise of the data.
530
+ *
531
+ * @example
532
+ * ```ts
533
+ * export const todoResolver: ResolveFn<Todo> = (route) => {
534
+ * const http = inject(HttpClient)
535
+ * const id = Number(route.paramMap.get('id'))
536
+ *
537
+ * return injectQueryClient().fetchQuery(['todos', id], () =>
538
+ * http.get<Todo>(`/api/todos/${id}`),
539
+ * )
540
+ * }
541
+ * ```
472
542
  */
473
543
  fetchQuery<TData>(key: QueryKey, queryFn: () => Observable<TData> | Promise<TData>, options?: {
474
544
  staleTime?: number;
@@ -476,7 +546,7 @@ declare class QueryClient {
476
546
  retryDelay?: RetryDelayValue<any>;
477
547
  structuralSharing?: StructuralSharingValue<TData>;
478
548
  cancelRefetch?: boolean;
479
- }): void;
549
+ }): Promise<TData>;
480
550
  /**
481
551
  * Reads the current cached data for a query key, or `undefined` if the query
482
552
  * is not cached yet. A snapshot: it doesn't update a template, a `computed`
@@ -510,20 +580,46 @@ declare class QueryClient {
510
580
  * Marks matching queries as stale and refetches the actively observed ones,
511
581
  * once per query however many components observe it. The refetch starts
512
582
  * right away and replaces a fetch already in flight, which may predate the
513
- * change; this method doesn't wait for it. A query with no enabled observer
514
- * keeps the stale mark and refetches as soon as one appears. Commonly called
515
- * after a mutation succeeds.
583
+ * change. A query with no enabled observer keeps the stale mark and
584
+ * refetches as soon as one appears. Commonly called after a mutation
585
+ * succeeds.
586
+ *
587
+ * Resolves once those refetches have settled, so a mutation hook that
588
+ * returns it keeps the mutation pending until the data is fresh. It never
589
+ * rejects: a refetch that fails shows in its query's `error`.
516
590
  *
517
591
  * @param filters - Which queries to invalidate; omit to invalidate all.
592
+ * `refetchType: 'none'` only marks them, and resolves at once.
518
593
  *
519
594
  * @example
520
595
  * ```ts
521
596
  * client.invalidateQueries({ queryKey: ['todos'] })
522
597
  * ```
523
598
  */
524
- invalidateQueries(filters?: QueryFilters): void;
599
+ invalidateQueries(filters?: InvalidateQueryFilters): Promise<void>;
600
+ /**
601
+ * Refetches the matching queries that a component shows, whether their
602
+ * data is stale or not, once per query however many components show it. A
603
+ * fetch already in flight is replaced. Queries nobody shows are left as
604
+ * they are, not even marked stale: to have them refetch once they're shown,
605
+ * invalidate them with `invalidateQueries()`.
606
+ *
607
+ * Resolves once the refetches have settled. It never rejects: a refetch
608
+ * that fails shows in its query's `error`.
609
+ *
610
+ * @param filters - Which queries to refetch; omit to refetch all.
611
+ *
612
+ * @example
613
+ * ```ts
614
+ * await client.refetchQueries({ queryKey: ['todos'] })
615
+ * ```
616
+ */
617
+ refetchQueries(filters?: QueryFilters): Promise<void>;
525
618
  /**
526
- * Cancels any in-flight fetches for matching queries.
619
+ * Cancels any in-flight fetches for matching queries. Each query goes back
620
+ * to how it was before its fetch: one that failed and was being tried
621
+ * again shows its error again. Data written meanwhile stays, and so does a
622
+ * stale mark from `invalidateQueries()`.
527
623
  *
528
624
  * @param filters - Which queries to cancel; omit to cancel all.
529
625
  */
@@ -737,9 +833,11 @@ declare function injectQueries<TData, TError = Error>(optionsFn: () => InjectQue
737
833
  * until it settles. Mutations do not retry by default (a retried write is not
738
834
  * idempotent); opt in via `options.retry`. Whatever of `retry`, `retryDelay`
739
835
  * and the `onSuccess` / `onError` / `onSettled` hooks a mutation leaves unset
740
- * comes from {@link withDefaultOptions}. `mutate()` and `reset()` are safe
741
- * to call from an effect: neither makes the effect depend on what it reads,
742
- * such as the options or the previous run. Bound to the current injection
836
+ * comes from {@link withDefaultOptions}. `mutateAsync(variables)` runs it
837
+ * the same way and returns a promise of the run's data. `mutate()`,
838
+ * `mutateAsync()` and `reset()` are safe to call from an effect: none makes
839
+ * the effect depend on what it reads, such as the options or the previous
840
+ * run. Bound to the current injection
743
841
  * context. Destroying it doesn't cancel a run in flight: the write has most
744
842
  * likely reached the server, so the run finishes and fires its hooks.
745
843
  *
@@ -751,8 +849,8 @@ declare function injectQueries<TData, TError = Error>(optionsFn: () => InjectQue
751
849
  * @typeParam TContext - Type returned by `onMutate`, passed to later hooks.
752
850
  * @param optionsFn - Factory returning the {@link MutationOptions}.
753
851
  * @param options - Optional `injector` to use outside an injection context.
754
- * @returns A {@link MutationResult}: `mutate()`, `reset()`, and state signals
755
- * (`status`, `data`, `error`, `isPending`, …).
852
+ * @returns A {@link MutationResult}: `mutate()`, `mutateAsync()`, `reset()`,
853
+ * and state signals (`status`, `data`, `error`, `isPending`, …).
756
854
  *
757
855
  * @example
758
856
  * ```ts
@@ -892,6 +990,20 @@ declare function keepPreviousData<TData>(previousData: TData | undefined): TData
892
990
  */
893
991
  declare function mutationOptions<TData, TError = Error, TVariables = void, TContext = unknown>(options: MutationOptions<TData, TError, TVariables, TContext>): MutationOptions<TData, TError, TVariables, TContext>;
894
992
 
993
+ /**
994
+ * The error a promise of a query's data rejects with when the fetch stops
995
+ * with no data to give: it was cancelled before the query had any
996
+ * (`cancelQueries()`, or the last component showing the query went away), or
997
+ * the query was removed (`removeQueries()`, e.g. on sign-out). The request
998
+ * didn't fail, so tell the two apart with `instanceof CancelledError`.
999
+ *
1000
+ * A mutation's `mutateAsync()` rejects with one too, when the mutation cache
1001
+ * is cleared while its run is in flight.
1002
+ */
1003
+ declare class CancelledError extends Error {
1004
+ constructor(message?: string);
1005
+ }
1006
+
895
1007
  /**
896
1008
  * Feature for {@link provideQueryClient} that sets application-wide default
897
1009
  * query and mutation options. A query's or mutation's own options take
@@ -914,5 +1026,5 @@ declare function mutationOptions<TData, TError = Error, TVariables = void, TCont
914
1026
  */
915
1027
  declare function withDefaultOptions(options: DefaultOptions): QueryClientFeature<QueryClientFeatureKind.DefaultOptions>;
916
1028
 
917
- export { QueryClient, QueryClientFeatureKind, injectIsFetching, injectIsMutating, injectMutation, injectQueries, injectQuery, injectQueryClient, keepPreviousData, mutationOptions, provideQueryClient, queryOptions, withDefaultOptions };
918
- export type { DefaultMutationOptions, DefaultOptions, DefaultQueryOptions, DefaultedQueryOptions, InjectQueriesOptions, MutationFilters, MutationOptions, MutationResult, MutationState, MutationStatus, PlaceholderDataFunction, QueryClientFeature, QueryFilters, QueryKey, QueryOptions, QueryResult, QueryState, QueryStatus, RefetchIntervalValue, RetryDelayValue, RetryValue, StructuralSharingValue, Updater };
1029
+ export { CancelledError, QueryClient, QueryClientFeatureKind, injectIsFetching, injectIsMutating, injectMutation, injectQueries, injectQuery, injectQueryClient, keepPreviousData, mutationOptions, provideQueryClient, queryOptions, withDefaultOptions };
1030
+ export type { DefaultMutationOptions, DefaultOptions, DefaultQueryOptions, DefaultedQueryOptions, InjectQueriesOptions, InvalidateQueryFilters, MutationFilters, MutationOptions, MutationResult, MutationState, MutationStatus, PlaceholderDataFunction, QueryClientFeature, QueryFilters, QueryKey, QueryOptions, QueryResult, QueryState, QueryStatus, RefetchIntervalValue, RetryDelayValue, RetryValue, StructuralSharingValue, Updater };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-signal-query",
3
- "version": "1.5.0-dev.2",
3
+ "version": "1.5.0-dev.4",
4
4
  "description": "Data fetching, caching and mutations for Angular, built on signals and RxJS. Observables end to end, TanStack Query concepts.",
5
5
  "keywords": [
6
6
  "angular",