ngx-signal-query 1.0.0-dev.1

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 ADDED
@@ -0,0 +1,619 @@
1
+ import { Observable } from 'rxjs';
2
+ import * as i0 from '@angular/core';
3
+ import { Signal, Provider, EnvironmentProviders, Injector } from '@angular/core';
4
+
5
+ declare abstract class Cache<TEntry> {
6
+ #private;
7
+ protected readonly entries: i0.Signal<TEntry[]>;
8
+ getAll(): TEntry[];
9
+ clear(): void;
10
+ protected addEntry(key: string, entry: TEntry): TEntry;
11
+ protected getEntry(key: string): TEntry | undefined;
12
+ protected removeEntry(key: string): boolean;
13
+ }
14
+
15
+ /**
16
+ * Uniquely identifies a query and serves as its cache key. Use a serializable
17
+ * array, from broad to specific, e.g. `['todos']` or `['todo', id]`.
18
+ */
19
+ type QueryKey = readonly unknown[];
20
+ /** Lifecycle status of a query: no data yet, resolved, or failed. */
21
+ type QueryStatus = 'pending' | 'success' | 'error';
22
+ /** Full state snapshot of a query (the reactive source behind {@link QueryResult}). */
23
+ interface QueryState<TData, TError = Error> {
24
+ /** Last successfully resolved data, or `undefined` before the first success. */
25
+ data: TData | undefined;
26
+ /** Current {@link QueryStatus}. */
27
+ status: QueryStatus;
28
+ /** Last error, or `null` if the latest attempt did not fail. */
29
+ error: TError | null;
30
+ /** Whether a fetch is currently in flight. */
31
+ isFetching: boolean;
32
+ /** Whether the query has been marked stale via `invalidateQueries`. */
33
+ isInvalidated: boolean;
34
+ /** Number of consecutive failed attempts in the current fetch. */
35
+ failureCount: number;
36
+ /** Error of the most recent failed attempt, or `null`. */
37
+ failureReason: TError | null;
38
+ /** Timestamp (ms) of the last successful update; `0` if never. */
39
+ updatedAt: number;
40
+ }
41
+ /** Selects which queries an operation applies to (e.g. invalidate, cancel). */
42
+ type QueryFilters = {
43
+ /** Match queries whose key starts with (or, with `exact`, equals) this key. */
44
+ queryKey?: QueryKey;
45
+ /** Require an exact key match instead of a prefix match. */
46
+ exact?: boolean;
47
+ };
48
+ /** A new value, or a function deriving it from the previous one. */
49
+ type Updater<TInput, TOutput> = TOutput | ((input: TInput) => TOutput);
50
+ /**
51
+ * Polling interval in ms, `false` to disable, or a function of the current
52
+ * query snapshot returning the next interval (e.g. stop polling on error).
53
+ */
54
+ type RefetchIntervalValue<TData, TError> = number | false | ((query: {
55
+ state: QueryState<TData, TError>;
56
+ }) => number | false | undefined);
57
+ /**
58
+ * Retry policy: `true`/`false` to enable/disable, a max retry count, or a
59
+ * predicate `(failureCount, error) => boolean`.
60
+ */
61
+ type RetryValue<TError> = boolean | number | ((failureCount: number, error: TError) => boolean);
62
+ /** Delay between retries: fixed ms, or a function of the attempt and error. */
63
+ type RetryDelayValue<TError> = number | ((failureCount: number, error: TError) => number);
64
+ /** Configuration for a query, passed to {@link injectQuery} / {@link queryOptions}. */
65
+ type QueryOptions<TData, TError = Error> = {
66
+ /** Unique cache key for this query. See {@link QueryKey}. */
67
+ queryKey: QueryKey;
68
+ /** Fetcher returning the data as an `Observable` or `Promise`. */
69
+ queryFn: () => Observable<TData> | Promise<TData>;
70
+ /** How long fetched data stays fresh before refetching, in ms. Default `0`. */
71
+ staleTime?: number;
72
+ /** How long unused data is kept before garbage collection, in ms. */
73
+ gcTime?: number;
74
+ /** Retry policy on failure. Default `3`. See {@link RetryValue}. */
75
+ retry?: RetryValue<TError>;
76
+ /** Delay between retries. See {@link RetryDelayValue}. */
77
+ retryDelay?: RetryDelayValue<TError>;
78
+ /** Poll on an interval. See {@link RefetchIntervalValue}. */
79
+ refetchInterval?: RefetchIntervalValue<TData, TError>;
80
+ /** Seed data to render immediately (treated as already-resolved). */
81
+ initialData?: TData | (() => TData);
82
+ /** Timestamp (ms) for `initialData`; older data is considered stale. */
83
+ initialDataUpdatedAt?: number | (() => number);
84
+ /** Set `false` to disable fetching (e.g. until a dependency is ready). */
85
+ enabled?: boolean;
86
+ };
87
+ /** {@link QueryOptions} with defaults resolved (internal, set by {@link QueryClient}). */
88
+ type DefaultedQueryOptions<TData, TError = Error> = QueryOptions<TData, TError> & {
89
+ staleTime: number;
90
+ retry: RetryValue<TError>;
91
+ retryDelay: RetryDelayValue<TError>;
92
+ };
93
+ /** Reactive result returned by {@link injectQuery}; every field is a signal. */
94
+ type QueryResult<TData, TError = Error> = {
95
+ /** Last resolved data, or `undefined` before the first success. */
96
+ data: Signal<TData | undefined>;
97
+ /** Current {@link QueryStatus}. */
98
+ status: Signal<QueryStatus>;
99
+ /** Last error, or `null`. */
100
+ error: Signal<TError | null>;
101
+ /** Whether a fetch is in flight (including background refetches). */
102
+ isFetching: Signal<boolean>;
103
+ /** Whether the first fetch is in flight with no data yet (`isFetching && pending`). */
104
+ isLoading: Signal<boolean>;
105
+ /** Whether status is `'pending'` (no data resolved yet). */
106
+ isPending: Signal<boolean>;
107
+ /** Whether status is `'success'`. */
108
+ isSuccess: Signal<boolean>;
109
+ /** Whether status is `'error'`. */
110
+ isError: Signal<boolean>;
111
+ /** Consecutive failures in the current fetch. */
112
+ failureCount: Signal<number>;
113
+ /** Error of the most recent failed attempt, or `null`. */
114
+ failureReason: Signal<TError | null>;
115
+ /** Forces a fresh fetch, cancelling any in-flight request. */
116
+ refetch: () => void;
117
+ };
118
+
119
+ declare class Query<TData, TError = Error> {
120
+ #private;
121
+ readonly key: QueryKey;
122
+ readonly queryHash: string;
123
+ readonly state: i0.Signal<QueryState<TData, TError>>;
124
+ constructor(key: QueryKey, queryHash: string, cache: QueryCache);
125
+ get observerCount(): number;
126
+ setGcTime(ms: number): void;
127
+ addObserver(): void;
128
+ removeObserver(): void;
129
+ fetch(queryFn: () => Observable<TData> | Promise<TData>, retry?: RetryValue<TError>, retryDelay?: RetryDelayValue<TError>, cancelRefetch?: boolean): void;
130
+ setData(data: TData, updatedAt?: number): void;
131
+ invalidate(): void;
132
+ shouldFetch(staleTime: number): boolean;
133
+ cancel(): void;
134
+ destroy(): void;
135
+ }
136
+
137
+ declare class QueryCache extends Cache<Query<unknown, unknown>> {
138
+ getOrCreate<TData, TError = Error>(key: QueryKey): Query<TData, TError>;
139
+ get<TData, TError = Error>(key: QueryKey): Query<TData, TError> | undefined;
140
+ findAll(filters?: QueryFilters): Array<Query<unknown, unknown>>;
141
+ remove(query: Query<unknown, unknown>): void;
142
+ clear(): void;
143
+ static ɵfac: i0.ɵɵFactoryDeclaration<QueryCache, never>;
144
+ static ɵprov: i0.ɵɵInjectableDeclaration<QueryCache>;
145
+ }
146
+
147
+ /** Lifecycle status of a mutation: not yet run, running, succeeded, or failed. */
148
+ type MutationStatus = 'idle' | 'pending' | 'success' | 'error';
149
+ /** Selects which mutations an operation applies to (e.g. `injectIsMutating`). */
150
+ type MutationFilters = {
151
+ /** Match mutations in this status. */
152
+ status?: MutationStatus;
153
+ };
154
+ /** Full state snapshot of a mutation (the reactive source behind {@link MutationResult}). */
155
+ type MutationState<TData, TError, TVariables, TContext> = {
156
+ /** Current {@link MutationStatus}. */
157
+ status: MutationStatus;
158
+ /** Data resolved by the last successful run, or `undefined`. */
159
+ data: TData | undefined;
160
+ /** Error of the last failed run, or `null`. */
161
+ error: TError | null;
162
+ /** Variables passed to the most recent `mutate()` call. */
163
+ variables: TVariables | undefined;
164
+ /** Value returned by `onMutate` for the current run. */
165
+ context: TContext | undefined;
166
+ /** Number of failed attempts in the current run. */
167
+ failureCount: number;
168
+ /** Error of the most recent failed attempt, or `null`. */
169
+ failureReason: TError | null;
170
+ /** Timestamp (ms) when the current run was submitted; `0` if never. */
171
+ submittedAt: number;
172
+ };
173
+ /**
174
+ * Configuration for a mutation, passed to {@link injectMutation} /
175
+ * {@link mutationOptions}. The hooks fire in order: `onMutate` →
176
+ * (`onSuccess` | `onError`) → `onSettled`. The value returned by `onMutate`
177
+ * is passed as `context` to the later hooks — handy for rollback.
178
+ */
179
+ type MutationOptions<TData, TError, TVariables, TContext> = {
180
+ /** Performs the write; receives `mutate()`'s argument. Returns `Observable`/`Promise`. */
181
+ mutationFn: (variables: TVariables) => Observable<TData> | Promise<TData>;
182
+ /** Retry policy. Defaults to no retry (writes are not idempotent). */
183
+ retry?: RetryValue<TError>;
184
+ /** Delay between retries. See {@link RetryDelayValue}. */
185
+ retryDelay?: RetryDelayValue<TError>;
186
+ /** Runs before `mutationFn`; its return value becomes `context` (e.g. for optimistic rollback). */
187
+ onMutate?: (variables: TVariables) => TContext | undefined;
188
+ /** Runs after a successful `mutationFn`. */
189
+ onSuccess?: (data: TData, variables: TVariables, context: TContext | undefined) => void;
190
+ /** Runs after a failed `mutationFn`. */
191
+ onError?: (error: TError, variables: TVariables, context: TContext | undefined) => void;
192
+ /** Runs after success or error — for cleanup that should happen either way. */
193
+ onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, context: TContext | undefined) => void;
194
+ };
195
+ /** Reactive result returned by {@link injectMutation}; state fields are signals. */
196
+ type MutationResult<TData, TError, TVariables> = {
197
+ /** Triggers the mutation with the given variables. */
198
+ mutate: (variables: TVariables) => void;
199
+ /** Resets state back to `idle`, cancelling any in-flight run. */
200
+ reset: () => void;
201
+ /** Data from the last successful run, or `undefined`. */
202
+ data: Signal<TData | undefined>;
203
+ /** Error from the last failed run, or `null`. */
204
+ error: Signal<TError | null>;
205
+ /** Variables from the most recent `mutate()` call. */
206
+ variables: Signal<TVariables | undefined>;
207
+ /** Current {@link MutationStatus}. */
208
+ status: Signal<MutationStatus>;
209
+ /** Whether the mutation has not been run yet. */
210
+ isIdle: Signal<boolean>;
211
+ /** Whether the mutation is currently running. */
212
+ isPending: Signal<boolean>;
213
+ /** Whether the last run succeeded. */
214
+ isSuccess: Signal<boolean>;
215
+ /** Whether the last run failed. */
216
+ isError: Signal<boolean>;
217
+ /** Consecutive failures in the current run. */
218
+ failureCount: Signal<number>;
219
+ /** Error of the most recent failed attempt, or `null`. */
220
+ failureReason: Signal<TError | null>;
221
+ };
222
+ declare class Mutation<TData = unknown, TError = Error, TVariables = void, TContext = unknown> {
223
+ #private;
224
+ readonly mutationId: number;
225
+ readonly state: Signal<MutationState<TData, TError, TVariables, TContext>>;
226
+ constructor(mutationId: number, options: MutationOptions<TData, TError, TVariables, TContext>);
227
+ execute(variables: TVariables): void;
228
+ reset(): void;
229
+ cancel(): void;
230
+ }
231
+
232
+ declare class MutationCache extends Cache<Mutation<unknown, unknown, unknown, unknown>> {
233
+ #private;
234
+ build<TData, TError, TVariables, TContext>(options: MutationOptions<TData, TError, TVariables, TContext>): Mutation<TData, TError, TVariables, TContext>;
235
+ findAll(filters?: MutationFilters): Array<Mutation<unknown, unknown, unknown, unknown>>;
236
+ remove<TData, TError, TVariables, TContext>(mutation: Mutation<TData, TError, TVariables, TContext>): void;
237
+ clear(): void;
238
+ static ɵfac: i0.ɵɵFactoryDeclaration<MutationCache, never>;
239
+ static ɵprov: i0.ɵɵInjectableDeclaration<MutationCache>;
240
+ }
241
+
242
+ /**
243
+ * Central registry and cache for queries and mutations.
244
+ *
245
+ * Provided by {@link provideQueryClient} and retrieved with
246
+ * {@link injectQueryClient}. Offers imperative cache access — reading and
247
+ * writing data, and invalidating, cancelling, or removing queries — that
248
+ * complements the reactive {@link injectQuery} / {@link injectMutation} APIs.
249
+ */
250
+ declare class QueryClient {
251
+ #private;
252
+ /** Returns the underlying query cache. Advanced/internal use. */
253
+ getQueryCache(): QueryCache;
254
+ /** Returns the underlying mutation cache. Advanced/internal use. */
255
+ getMutationCache(): MutationCache;
256
+ /**
257
+ * Merges per-query options with the configured defaults, filling in
258
+ * `staleTime`, `gcTime`, `retry`, and `retryDelay`. Used internally by
259
+ * {@link injectQuery}.
260
+ */
261
+ defaultQueryOptions<TData, TError = Error>(options: QueryOptions<TData, TError>): DefaultedQueryOptions<TData, TError>;
262
+ /**
263
+ * Imperatively fetches and caches a query, unless fresh data already exists
264
+ * (governed by `staleTime`). Prefer {@link injectQuery} in components; use
265
+ * this for prefetching outside the reactive flow.
266
+ *
267
+ * @param key - The query key to fetch and cache under.
268
+ * @param queryFn - Function returning the data as an `Observable` or `Promise`.
269
+ * @param options - Fetch tuning (`staleTime`, `retry`, `retryDelay`,
270
+ * `cancelRefetch`).
271
+ */
272
+ fetchQuery<TData>(key: QueryKey, queryFn: () => Observable<TData> | Promise<TData>, options?: {
273
+ staleTime?: number;
274
+ retry?: RetryValue<any>;
275
+ retryDelay?: RetryDelayValue<any>;
276
+ cancelRefetch?: boolean;
277
+ }): void;
278
+ /**
279
+ * Reads the current cached data for a query key, or `undefined` if the query
280
+ * is not cached yet.
281
+ *
282
+ * @param key - The query key to read.
283
+ * @returns The cached data, or `undefined`.
284
+ */
285
+ getQueryData<TData>(key: QueryKey): TData | undefined;
286
+ /**
287
+ * Writes data into the cache for a query key, creating the entry if needed.
288
+ * The `updater` may be a value or a function of the previous data; returning
289
+ * `undefined` from the function is a no-op. Useful for optimistic updates.
290
+ *
291
+ * @param key - The query key to write.
292
+ * @param updater - The new data, or a function `(prev) => next`.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * client.setQueryData<Todo[]>(['todos'], (prev = []) => [...prev, newTodo])
297
+ * ```
298
+ */
299
+ setQueryData<TData>(key: QueryKey, updater: Updater<TData | undefined, TData>): void;
300
+ /**
301
+ * Marks matching queries as stale and triggers a refetch for those that are
302
+ * actively observed. Commonly called after a mutation succeeds.
303
+ *
304
+ * @param filters - Which queries to invalidate; omit to invalidate all.
305
+ *
306
+ * @example
307
+ * ```ts
308
+ * client.invalidateQueries({ queryKey: ['todos'] })
309
+ * ```
310
+ */
311
+ invalidateQueries(filters?: QueryFilters): void;
312
+ /**
313
+ * Cancels any in-flight fetches for matching queries.
314
+ *
315
+ * @param filters - Which queries to cancel; omit to cancel all.
316
+ */
317
+ cancelQueries(filters?: QueryFilters): void;
318
+ /**
319
+ * Removes matching queries from the cache entirely, discarding their data.
320
+ *
321
+ * @param filters - Which queries to remove; omit to remove all.
322
+ */
323
+ removeQueries(filters?: QueryFilters): void;
324
+ /**
325
+ * Returns the number of matching queries currently fetching. For a reactive
326
+ * count, prefer {@link injectIsFetching}.
327
+ *
328
+ * @param filters - Which queries to count; omit to count all.
329
+ */
330
+ isFetching(filters?: QueryFilters): number;
331
+ /**
332
+ * Returns the number of mutations currently pending. For a reactive count,
333
+ * prefer {@link injectIsMutating}.
334
+ */
335
+ isMutating(): number;
336
+ static ɵfac: i0.ɵɵFactoryDeclaration<QueryClient, never>;
337
+ static ɵprov: i0.ɵɵInjectableDeclaration<QueryClient>;
338
+ }
339
+
340
+ /** Discriminator identifying each kind of {@link QueryClientFeature}. */
341
+ declare enum QueryClientFeatureKind {
342
+ DefaultOptions = 0
343
+ }
344
+ /**
345
+ * An opaque feature passed to {@link provideQueryClient}. Create one with a
346
+ * `with*` helper such as {@link withDefaultOptions} rather than constructing it
347
+ * directly; the `ɵ`-prefixed members are internal.
348
+ */
349
+ interface QueryClientFeature<K extends QueryClientFeatureKind = QueryClientFeatureKind> {
350
+ ɵkind: K;
351
+ ɵproviders: Provider[];
352
+ }
353
+
354
+ /**
355
+ * Registers the {@link QueryClient} and its caches for the application.
356
+ *
357
+ * Call once at the app root (in `ApplicationConfig.providers` or a root
358
+ * `bootstrapApplication`). Pass features such as {@link withDefaultOptions} to
359
+ * configure defaults. Registering the same feature twice throws.
360
+ *
361
+ * @param features - Optional {@link QueryClientFeature}s (e.g.
362
+ * {@link withDefaultOptions}).
363
+ * @returns Environment providers to add to the app's provider list.
364
+ *
365
+ * @example
366
+ * ```ts
367
+ * export const appConfig: ApplicationConfig = {
368
+ * providers: [
369
+ * provideHttpClient(),
370
+ * provideQueryClient(
371
+ * withDefaultOptions({ queries: { staleTime: 30_000 } }),
372
+ * ),
373
+ * ],
374
+ * }
375
+ * ```
376
+ */
377
+ declare function provideQueryClient(...features: QueryClientFeature[]): EnvironmentProviders;
378
+
379
+ /**
380
+ * Returns the application's {@link QueryClient} for imperative cache access.
381
+ *
382
+ * Use it to read or write cached data (`getQueryData`, `setQueryData`) and to
383
+ * invalidate, cancel, or remove queries — typically from mutation hooks or
384
+ * event handlers. Requires {@link provideQueryClient} to be registered.
385
+ *
386
+ * Must run in an injection context, or be given an explicit `injector`.
387
+ *
388
+ * @param options - Optional `injector` to use outside an injection context.
389
+ * @returns The shared {@link QueryClient} instance.
390
+ *
391
+ * @example
392
+ * ```ts
393
+ * const client = injectQueryClient()
394
+ * client.setQueryData<Todo[]>(['todos'], (prev = []) => [...prev, newTodo])
395
+ * client.invalidateQueries({ queryKey: ['todos'] })
396
+ * ```
397
+ */
398
+ declare function injectQueryClient(options?: {
399
+ injector?: Injector;
400
+ }): QueryClient;
401
+
402
+ /**
403
+ * Runs a cached, reactive query and exposes its state as signals.
404
+ *
405
+ * The query is keyed by `queryKey`: calls with the same key share a single
406
+ * cache entry and in-flight request (deduplication). `optionsFn` is read in a
407
+ * reactive context, so when a value it depends on changes (e.g. a route or
408
+ * input signal in the key), the query automatically switches to the new key
409
+ * and fetches. The query is bound to the current injection context and cleans
410
+ * up its cache observer when that context is destroyed.
411
+ *
412
+ * Must run in an injection context, or be given an explicit `injector`.
413
+ *
414
+ * @typeParam TData - Type of the data resolved by `queryFn`.
415
+ * @typeParam TError - Type of the error thrown by `queryFn`.
416
+ * @param optionsFn - Factory returning the {@link QueryOptions}. Re-evaluated
417
+ * reactively, so reading signals inside it makes the query re-run on change.
418
+ * @param options - Optional `injector` to use outside an injection context.
419
+ * @returns A {@link QueryResult} of signals (`data`, `status`, `error`,
420
+ * `isLoading`, `isPending`, …) plus a `refetch()` that forces a fresh fetch.
421
+ *
422
+ * @example
423
+ * ```ts
424
+ * @Component({
425
+ * template: `
426
+ * @if (todo.isPending()) { <p>Loading…</p> }
427
+ * @if (todo.data(); as data) { <p>{{ data.title }}</p> }
428
+ * `,
429
+ * })
430
+ * class TodoComponent {
431
+ * readonly id = input.required<number>()
432
+ * private readonly http = inject(HttpClient)
433
+ *
434
+ * // Refetches automatically whenever `id()` changes.
435
+ * readonly todo = injectQuery(() => ({
436
+ * queryKey: ['todo', this.id()],
437
+ * queryFn: () => this.http.get<Todo>(`/api/todos/${this.id()}`),
438
+ * }))
439
+ * }
440
+ * ```
441
+ */
442
+ declare function injectQuery<TData, TError = Error>(optionsFn: () => QueryOptions<TData, TError>, options?: {
443
+ injector?: Injector;
444
+ }): QueryResult<TData, TError>;
445
+
446
+ /**
447
+ * Creates a mutation for imperative writes (create/update/delete) and exposes
448
+ * its state as signals.
449
+ *
450
+ * Unlike queries, a mutation does not run on its own — call `mutate(variables)`
451
+ * to trigger `mutationFn`. The `onMutate` / `onSuccess` / `onError` /
452
+ * `onSettled` lifecycle hooks make optimistic updates and cache invalidation
453
+ * straightforward. Mutations do not retry by default (a retried write is not
454
+ * idempotent); opt in via `options.retry`. Bound to the current injection
455
+ * context and cancelled when that context is destroyed.
456
+ *
457
+ * Must run in an injection context, or be given an explicit `injector`.
458
+ *
459
+ * @typeParam TData - Type of the data resolved by `mutationFn`.
460
+ * @typeParam TError - Type of the error thrown by `mutationFn`.
461
+ * @typeParam TVariables - Type of the argument passed to `mutate()`.
462
+ * @typeParam TContext - Type returned by `onMutate`, passed to later hooks.
463
+ * @param optionsFn - Factory returning the {@link MutationOptions}.
464
+ * @param options - Optional `injector` to use outside an injection context.
465
+ * @returns A {@link MutationResult}: `mutate()`, `reset()`, and state signals
466
+ * (`status`, `data`, `error`, `isPending`, …).
467
+ *
468
+ * @example
469
+ * ```ts
470
+ * const client = injectQueryClient()
471
+ *
472
+ * const addTodo = injectMutation(() => ({
473
+ * mutationFn: (title: string) => http.post<Todo>('/api/todos', { title }),
474
+ * onSuccess: () => client.invalidateQueries({ queryKey: ['todos'] }),
475
+ * }))
476
+ *
477
+ * // <button (click)="addTodo.mutate('Buy milk')" [disabled]="addTodo.isPending()">Add</button>
478
+ * ```
479
+ */
480
+ declare function injectMutation<TData, TError = Error, TVariables = void, TContext = unknown>(optionsFn: () => MutationOptions<TData, TError, TVariables, TContext>, options?: {
481
+ injector?: Injector;
482
+ }): MutationResult<TData, TError, TVariables>;
483
+
484
+ /**
485
+ * Returns a signal with the number of queries currently fetching — useful for a
486
+ * global loading indicator.
487
+ *
488
+ * Pass {@link QueryFilters} to count only matching queries; omit them to count
489
+ * every fetching query in the cache.
490
+ *
491
+ * Must run in an injection context, or be given an explicit `injector`.
492
+ *
493
+ * @param filters - Optional filters (e.g. `{ queryKey: ['todos'] }`) to narrow
494
+ * the count.
495
+ * @param options - Optional `injector` to use outside an injection context.
496
+ * @returns A `Signal<number>` of active fetches.
497
+ *
498
+ * @example
499
+ * ```ts
500
+ * readonly isFetching = injectIsFetching()
501
+ * // <app-spinner *ngIf="isFetching() > 0" />
502
+ * ```
503
+ */
504
+ declare function injectIsFetching(filters?: QueryFilters, options?: {
505
+ injector?: Injector;
506
+ }): Signal<number>;
507
+
508
+ /**
509
+ * Returns a signal with the number of mutations currently pending — useful for
510
+ * a global "saving…" indicator.
511
+ *
512
+ * Must run in an injection context, or be given an explicit `injector`.
513
+ *
514
+ * @param options - Optional `injector` to use outside an injection context.
515
+ * @returns A `Signal<number>` of in-flight mutations.
516
+ *
517
+ * @example
518
+ * ```ts
519
+ * readonly isMutating = injectIsMutating()
520
+ * // <p *ngIf="isMutating() > 0">Saving…</p>
521
+ * ```
522
+ */
523
+ declare function injectIsMutating(options?: {
524
+ injector?: Injector;
525
+ }): Signal<number>;
526
+
527
+ /**
528
+ * Identity helper that defines a typed, reusable set of {@link QueryOptions}.
529
+ *
530
+ * Returns the options unchanged at runtime, but anchors type inference so the
531
+ * same definition can be shared across {@link injectQuery},
532
+ * {@link QueryClient.setQueryData}, and friends without re-declaring generics.
533
+ * Keeping query definitions in a service (rather than inline) makes them easy
534
+ * to reuse and unit-test.
535
+ *
536
+ * @typeParam TData - Type of the data resolved by `queryFn`.
537
+ * @typeParam TError - Type of the error thrown by `queryFn`.
538
+ * @param options - The {@link QueryOptions} to define.
539
+ * @returns The same `options`, typed.
540
+ *
541
+ * @example
542
+ * ```ts
543
+ * @Injectable({ providedIn: 'root' })
544
+ * class TodoQueries {
545
+ * private readonly http = inject(HttpClient)
546
+ *
547
+ * todos() {
548
+ * return queryOptions({
549
+ * queryKey: ['todos'],
550
+ * queryFn: () => this.http.get<Todo[]>('/api/todos'),
551
+ * })
552
+ * }
553
+ * }
554
+ *
555
+ * // const todos = injectQuery(() => inject(TodoQueries).todos())
556
+ * ```
557
+ */
558
+ declare function queryOptions<TData, TError = Error>(options: QueryOptions<TData, TError>): QueryOptions<TData, TError>;
559
+
560
+ /**
561
+ * Identity helper that defines a typed, reusable set of {@link MutationOptions}.
562
+ *
563
+ * Returns the options unchanged at runtime; its job is to anchor type inference
564
+ * (notably linking `TContext` returned by `onMutate` to the later hooks) so a
565
+ * mutation can be defined once in a service and passed to {@link injectMutation}.
566
+ *
567
+ * @typeParam TData - Type of the data resolved by `mutationFn`.
568
+ * @typeParam TError - Type of the error thrown by `mutationFn`.
569
+ * @typeParam TVariables - Type of the argument passed to `mutate()`.
570
+ * @typeParam TContext - Type returned by `onMutate`, passed to later hooks.
571
+ * @param options - The {@link MutationOptions} to define.
572
+ * @returns The same `options`, typed.
573
+ *
574
+ * @example
575
+ * ```ts
576
+ * addTodo() {
577
+ * return mutationOptions({
578
+ * mutationFn: (title: string) => this.http.post<Todo>('/api/todos', { title }),
579
+ * onSuccess: () => this.client.invalidateQueries({ queryKey: ['todos'] }),
580
+ * })
581
+ * }
582
+ * ```
583
+ */
584
+ declare function mutationOptions<TData, TError = Error, TVariables = void, TContext = unknown>(options: MutationOptions<TData, TError, TVariables, TContext>): MutationOptions<TData, TError, TVariables, TContext>;
585
+
586
+ /** Default query options applied to every query unless overridden per-query. */
587
+ interface DefaultQueryOptions {
588
+ /** How long fetched data is considered fresh, in ms. Defaults to `0`. */
589
+ staleTime?: number;
590
+ /** How long unused (unobserved) data is kept before garbage collection, in ms. */
591
+ gcTime?: number;
592
+ /** Retry policy on failure: a boolean, a count, or a predicate. Defaults to `3`. */
593
+ retry?: RetryValue<unknown>;
594
+ /** Delay between retries, in ms or a function of the attempt. */
595
+ retryDelay?: RetryDelayValue<unknown>;
596
+ }
597
+ /** Application-wide defaults configured via {@link withDefaultOptions}. */
598
+ interface DefaultOptions {
599
+ /** Defaults applied to all queries. */
600
+ queries?: DefaultQueryOptions;
601
+ }
602
+ /**
603
+ * Feature for {@link provideQueryClient} that sets application-wide default
604
+ * query options. Per-query options always take precedence over these defaults.
605
+ *
606
+ * @param options - The {@link DefaultOptions} to apply.
607
+ * @returns A {@link QueryClientFeature} to pass to {@link provideQueryClient}.
608
+ *
609
+ * @example
610
+ * ```ts
611
+ * provideQueryClient(
612
+ * withDefaultOptions({ queries: { staleTime: 60_000, retry: 1 } }),
613
+ * )
614
+ * ```
615
+ */
616
+ declare function withDefaultOptions(options: DefaultOptions): QueryClientFeature<QueryClientFeatureKind.DefaultOptions>;
617
+
618
+ export { QueryClient, QueryClientFeatureKind, injectIsFetching, injectIsMutating, injectMutation, injectQuery, injectQueryClient, mutationOptions, provideQueryClient, queryOptions, withDefaultOptions };
619
+ export type { DefaultOptions, DefaultQueryOptions, DefaultedQueryOptions, MutationFilters, MutationOptions, MutationResult, MutationState, MutationStatus, QueryClientFeature, QueryFilters, QueryKey, QueryOptions, QueryResult, QueryState, QueryStatus, RefetchIntervalValue, RetryDelayValue, RetryValue, Updater };
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "ngx-signal-query",
3
+ "version": "1.0.0-dev.1",
4
+ "description": "Signal-first data fetching, caching, and mutations for Angular — inspired by TanStack Query.",
5
+ "keywords": [
6
+ "angular",
7
+ "signals",
8
+ "query",
9
+ "tanstack",
10
+ "tanstack-query",
11
+ "data-fetching",
12
+ "cache",
13
+ "mutations",
14
+ "async-state"
15
+ ],
16
+ "license": "MIT",
17
+ "author": "Dzmitry Hutaryan",
18
+ "homepage": "https://github.com/dhutaryan/ngx-signal-query#readme",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/dhutaryan/ngx-signal-query.git",
22
+ "directory": "projects/ngx-signal-query"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/dhutaryan/ngx-signal-query/issues"
26
+ },
27
+ "peerDependencies": {
28
+ "@angular/core": ">=19.0.0"
29
+ },
30
+ "dependencies": {
31
+ "tslib": "^2.3.0"
32
+ },
33
+ "sideEffects": false,
34
+ "module": "fesm2022/ngx-signal-query.mjs",
35
+ "typings": "index.d.ts",
36
+ "exports": {
37
+ "./package.json": {
38
+ "default": "./package.json"
39
+ },
40
+ ".": {
41
+ "types": "./index.d.ts",
42
+ "default": "./fesm2022/ngx-signal-query.mjs"
43
+ }
44
+ }
45
+ }