@mmstack/resource 22.1.1 → 22.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -15
- package/fesm2022/mmstack-resource.mjs +801 -195
- package/fesm2022/mmstack-resource.mjs.map +1 -1
- package/package.json +1 -1
- package/types/mmstack-resource.d.ts +297 -56
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { HttpResponse, HttpInterceptorFn, HttpRequest, HttpContext,
|
|
1
|
+
import { HttpResponse, HttpInterceptorFn, HttpRequest, HttpContext, HttpResourceRequest, HttpResourceOptions, HttpResourceRef, HttpHeaders } from '@angular/common/http';
|
|
2
2
|
import { Signal, Injector, Provider, ResourceRef, InjectionToken, WritableSignal, ValueEqualityFn } from '@angular/core';
|
|
3
|
+
import { PauseOption } from '@mmstack/primitives';
|
|
3
4
|
|
|
4
5
|
type StoredEntry<T> = Omit<CacheEntry<T>, 'timeout'>;
|
|
5
6
|
type CacheDB<T> = {
|
|
@@ -50,8 +51,11 @@ type CacheEntry<T> = {
|
|
|
50
51
|
updated: number;
|
|
51
52
|
stale: number;
|
|
52
53
|
useCount: number;
|
|
54
|
+
/** Timestamp of the last read/write — drives LRU eviction. */
|
|
55
|
+
lastAccessed: number;
|
|
53
56
|
expiresAt: number;
|
|
54
|
-
|
|
57
|
+
/** Absent for non-finite/over-int32 TTLs — those rely on lazy expiry instead. */
|
|
58
|
+
timeout?: ReturnType<typeof setTimeout>;
|
|
55
59
|
key: string;
|
|
56
60
|
};
|
|
57
61
|
/**
|
|
@@ -72,9 +76,27 @@ declare class Cache<T> {
|
|
|
72
76
|
private readonly internal;
|
|
73
77
|
private readonly cleanupOpt;
|
|
74
78
|
private readonly id;
|
|
79
|
+
/** True once async hydration from the persistence layer has completed (or was empty). */
|
|
80
|
+
private hydrated;
|
|
81
|
+
/** Keys invalidated while hydration was still in flight — must not be resurrected by it. */
|
|
82
|
+
private readonly hydrationTombstones;
|
|
83
|
+
private readonly hitCount;
|
|
84
|
+
private readonly missCount;
|
|
75
85
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
86
|
+
* Read-only cache statistics for debugging/observability — entry count plus
|
|
87
|
+
* request-level hit/miss counters (counted on direct lookups, e.g. the cache
|
|
88
|
+
* interceptor's, not on every reactive signal read). Render it in a debug
|
|
89
|
+
* panel; it intentionally exposes no way to mutate the cache.
|
|
90
|
+
*/
|
|
91
|
+
readonly stats: Signal<{
|
|
92
|
+
size: number;
|
|
93
|
+
hits: number;
|
|
94
|
+
misses: number;
|
|
95
|
+
}>;
|
|
96
|
+
/**
|
|
97
|
+
* Destroys the cache instance, clearing the cleanup interval and closing the
|
|
98
|
+
* cross-tab channel. Called automatically when the providing injector is destroyed
|
|
99
|
+
* (wired up by `provideQueryCache`); call it manually for caches you construct yourself.
|
|
78
100
|
*/
|
|
79
101
|
readonly destroy: () => void;
|
|
80
102
|
private readonly broadcast;
|
|
@@ -96,9 +118,11 @@ declare class Cache<T> {
|
|
|
96
118
|
}, db?: Promise<CacheDB<T>>);
|
|
97
119
|
/** @internal */
|
|
98
120
|
private getInternal;
|
|
121
|
+
/** @internal Imperative access bookkeeping for LRU eviction. */
|
|
122
|
+
private touch;
|
|
99
123
|
/**
|
|
100
|
-
* Retrieves a cache entry
|
|
101
|
-
* for
|
|
124
|
+
* Retrieves a cache entry directly (non-reactively), updating its access bookkeeping
|
|
125
|
+
* for LRU eviction.
|
|
102
126
|
* @internal
|
|
103
127
|
* @param key - The key of the entry to retrieve.
|
|
104
128
|
* @returns The cache entry, or `null` if not found or expired.
|
|
@@ -129,13 +153,27 @@ declare class Cache<T> {
|
|
|
129
153
|
/**
|
|
130
154
|
* Stores a value in the cache.
|
|
131
155
|
*
|
|
156
|
+
* NOTE: cached values are shared by reference across all consumers (current and
|
|
157
|
+
* future cache hits, persistence, cross-tab sync) — do not mutate a value after
|
|
158
|
+
* storing it or after reading it from the cache.
|
|
159
|
+
*
|
|
132
160
|
* @param key - The key under which to store the value.
|
|
133
161
|
* @param value - The value to store.
|
|
134
162
|
* @param staleTime - (Optional) The stale time for this entry, in milliseconds. Overrides the default `staleTime`.
|
|
135
163
|
* @param ttl - (Optional) The TTL for this entry, in milliseconds. Overrides the default `ttl`.
|
|
164
|
+
* @param persist - (Optional) Whether to also write the entry to the persistence layer (IndexedDB). Defaults to `false`.
|
|
136
165
|
*/
|
|
137
166
|
store(key: string, value: T, staleTime?: number, ttl?: number, persist?: boolean): void;
|
|
138
167
|
private storeInternal;
|
|
168
|
+
/**
|
|
169
|
+
* @internal
|
|
170
|
+
* Inserts an entry that already carries ABSOLUTE timestamps — hydration from the
|
|
171
|
+
* persistence layer and cross-tab sync messages. Never re-anchors freshness to
|
|
172
|
+
* `Date.now()`, never persists, never broadcasts.
|
|
173
|
+
*/
|
|
174
|
+
private restoreInternal;
|
|
175
|
+
/** @internal Shared writer: arms the expiry timer only within the safe delay range. */
|
|
176
|
+
private setEntry;
|
|
139
177
|
/**
|
|
140
178
|
* Invalidates (removes) a cache entry.
|
|
141
179
|
*
|
|
@@ -161,7 +199,12 @@ declare class Cache<T> {
|
|
|
161
199
|
*/
|
|
162
200
|
invalidateWhere(predicate: (key: string) => boolean): number;
|
|
163
201
|
private invalidateInternal;
|
|
164
|
-
/**
|
|
202
|
+
/**
|
|
203
|
+
* Removes EVERY entry — memory, persisted rows, and (via broadcast) other tabs.
|
|
204
|
+
* Call on logout/auth changes so no prior user's responses survive.
|
|
205
|
+
*/
|
|
206
|
+
clear(): void;
|
|
207
|
+
/** @internal Drops expired entries, then enforces `maxSize` by the configured strategy. */
|
|
165
208
|
private cleanup;
|
|
166
209
|
}
|
|
167
210
|
/**
|
|
@@ -255,6 +298,10 @@ declare function injectQueryCache<TRaw = unknown>(injector?: Injector): Cache<Ht
|
|
|
255
298
|
* is made to the server, and the response is cached according to the configured TTL and staleness.
|
|
256
299
|
* The interceptor also respects `Cache-Control` headers from the server.
|
|
257
300
|
*
|
|
301
|
+
* Cache-enabled requests are single-flighted per cache key: N concurrent consumers of
|
|
302
|
+
* the same missing/stale entry share ONE network request. Non-cached requests are not
|
|
303
|
+
* touched — pair with `createDedupeRequestsInterceptor` to coalesce those as well.
|
|
304
|
+
*
|
|
258
305
|
* @param allowedMethods - An array of HTTP methods for which caching should be enabled.
|
|
259
306
|
* Defaults to `['GET', 'HEAD', 'OPTIONS']`.
|
|
260
307
|
*
|
|
@@ -435,6 +482,12 @@ declare function noDedupe(ctx?: HttpContext): HttpContext;
|
|
|
435
482
|
* only the first request will be sent to the server. Subsequent requests will
|
|
436
483
|
* receive the response from the first request.
|
|
437
484
|
*
|
|
485
|
+
* Relationship to `createCacheInterceptor`: the cache interceptor has built-in
|
|
486
|
+
* single-flight for CACHE-ENABLED requests (keyed by the cache key). This interceptor
|
|
487
|
+
* covers everything the cache doesn't see — non-cached resources, plain HttpClient
|
|
488
|
+
* calls, DELETEs — keyed by the request hash. Installing both is the recommended
|
|
489
|
+
* setup; where they overlap, this one degrades to a no-op passthrough.
|
|
490
|
+
*
|
|
438
491
|
* @param allowed - An array of HTTP methods for which deduplication should be enabled.
|
|
439
492
|
* Defaults to `['GET', 'DELETE', 'HEAD', 'OPTIONS']`.
|
|
440
493
|
* @param keyFn - Optional function to compute the dedupe key from a request.
|
|
@@ -465,11 +518,114 @@ declare function noDedupe(ctx?: HttpContext): HttpContext;
|
|
|
465
518
|
*/
|
|
466
519
|
declare function createDedupeRequestsInterceptor(allowed?: string[], keyFn?: (req: HttpRequest<unknown>) => string): HttpInterceptorFn;
|
|
467
520
|
|
|
521
|
+
type HashableRequest = {
|
|
522
|
+
method?: string;
|
|
523
|
+
url: string;
|
|
524
|
+
responseType?: string;
|
|
525
|
+
params?: HttpResourceRequest['params'] | HttpRequest<unknown>['params'];
|
|
526
|
+
body?: unknown;
|
|
527
|
+
headers?: HttpResourceRequest['headers'] | HttpRequest<unknown>['headers'];
|
|
528
|
+
};
|
|
529
|
+
/**
|
|
530
|
+
* Builds a stable cache/dedupe key from an HTTP request shape (accepts both
|
|
531
|
+
* `HttpRequest` and `HttpResourceRequest`).
|
|
532
|
+
*
|
|
533
|
+
* Key composition: `${method}:${url}:${responseType}[:${params}][:${body}][:${vary}]`
|
|
534
|
+
* - `method` defaults to `'GET'`, `responseType` to `'json'` (Angular defaults).
|
|
535
|
+
* - Query params are sorted alphabetically and URL-encoded for stability.
|
|
536
|
+
* - Body hashing handles `File`/`Blob`/`FormData`/`URLSearchParams`/`ArrayBuffer`
|
|
537
|
+
* and typed arrays explicitly; everything else flows through key-sorted
|
|
538
|
+
* `JSON.stringify` via `hash()`.
|
|
539
|
+
* - `varyHeaders` (opt-in) mixes the named request headers into the key so responses
|
|
540
|
+
* that differ per header (e.g. `Authorization` → per-user, `Accept-Language`) get
|
|
541
|
+
* separate entries. Known-safe content-negotiation headers (`Accept`,
|
|
542
|
+
* `Accept-Language`, `Content-Language`, `Content-Type`) embed their value raw for
|
|
543
|
+
* readable keys; all other header VALUES are one-way digested, never embedded raw —
|
|
544
|
+
* keys are persisted to IndexedDB and broadcast across tabs.
|
|
545
|
+
*/
|
|
546
|
+
declare function hashRequest(req: HashableRequest, varyHeaders?: readonly string[]): string;
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Refresh configuration for a query resource.
|
|
550
|
+
* - a `number` is shorthand for `{ interval: number }` (poll every n milliseconds)
|
|
551
|
+
* - the object form composes polling with event-driven refresh triggers
|
|
552
|
+
*/
|
|
553
|
+
type RefreshOptions = number | {
|
|
554
|
+
/**
|
|
555
|
+
* Poll interval in milliseconds. Omit (or 0) for no polling — useful when only
|
|
556
|
+
* the event-driven triggers below are wanted.
|
|
557
|
+
*/
|
|
558
|
+
interval?: number;
|
|
559
|
+
/**
|
|
560
|
+
* Reload when the page becomes visible again (tab refocused, window restored).
|
|
561
|
+
* @default false
|
|
562
|
+
*/
|
|
563
|
+
onFocus?: boolean;
|
|
564
|
+
/**
|
|
565
|
+
* Reload when the browser comes back online.
|
|
566
|
+
* @default false
|
|
567
|
+
*/
|
|
568
|
+
onReconnect?: boolean;
|
|
569
|
+
};
|
|
570
|
+
|
|
468
571
|
type RetryOptions = number | {
|
|
469
572
|
max?: number;
|
|
470
573
|
backoff?: number;
|
|
471
574
|
};
|
|
472
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Options for enabling and configuring caching for a resource.
|
|
578
|
+
*
|
|
579
|
+
* - `true`: Enables caching with default settings.
|
|
580
|
+
* - `{ ttl?: number; staleTime?: number; hash?: (req: HttpResourceRequest) => string; }`: Configures caching with custom settings.
|
|
581
|
+
*/
|
|
582
|
+
type ResourceCacheOptions = true | {
|
|
583
|
+
/**
|
|
584
|
+
* The time-to-live for the cached value in milliseconds.
|
|
585
|
+
* After this time, the value is removed from the cache entirely.
|
|
586
|
+
* Defaults to 5 minutes (`300_000`).
|
|
587
|
+
*/
|
|
588
|
+
ttl?: number;
|
|
589
|
+
/**
|
|
590
|
+
* The time in milliseconds during which the cached value is considered "fresh".
|
|
591
|
+
* If a request is made within this time, the cached value is returned immediately without a background fetch.
|
|
592
|
+
* Defaults to 0 (always stale, triggering a background fetch).
|
|
593
|
+
*/
|
|
594
|
+
staleTime?: number;
|
|
595
|
+
/**
|
|
596
|
+
* A custom function to generate the cache key from the HTTP request.
|
|
597
|
+
* By default, it hashes the URL, method, headers (specified by `varyHeaders`), and body.
|
|
598
|
+
*/
|
|
599
|
+
hash?: (req: HttpResourceRequest) => string;
|
|
600
|
+
/**
|
|
601
|
+
* A list of header names to include in the default cache key generation.
|
|
602
|
+
* Ignored if a custom `hash` function is provided.
|
|
603
|
+
*
|
|
604
|
+
* Note: still call `cache.clear()` on logout — the previous user's entries are
|
|
605
|
+
* unreachable under the new key but linger until their TTL.
|
|
606
|
+
*/
|
|
607
|
+
varyHeaders?: string[];
|
|
608
|
+
/**
|
|
609
|
+
* Whether to bust the browser cache by appending a unique query parameter to the request URL.
|
|
610
|
+
* This is useful for ensuring that the latest data is fetched from the server, bypassing any
|
|
611
|
+
* cached responses in the browser. The unique parameter is removed before calling the cache function, so it does not affect the cache key.
|
|
612
|
+
* @default false - By default, the resource will not bust the browser cache.
|
|
613
|
+
*/
|
|
614
|
+
bustBrowserCache?: boolean;
|
|
615
|
+
/**
|
|
616
|
+
* Whether to ignore the `Cache-Control` headers from the server when caching responses.
|
|
617
|
+
* If set to `true`, the resource will not respect any cache directives from the server,
|
|
618
|
+
* allowing you to control caching behavior entirely through the resource options.
|
|
619
|
+
* @default false - By default the resource will respect `Cache-Control` headers.
|
|
620
|
+
*/
|
|
621
|
+
ignoreCacheControl?: boolean;
|
|
622
|
+
/**
|
|
623
|
+
* If true, it saves the cached responses to an indexedDb table, making it available across
|
|
624
|
+
* tabs, sessions and reloads..only valid JSON responses can be persisted (so no Blobs, formData, ArrayBuffers etc.)
|
|
625
|
+
* @default false
|
|
626
|
+
*/
|
|
627
|
+
persist?: boolean;
|
|
628
|
+
};
|
|
473
629
|
/**
|
|
474
630
|
* Auto-registration into the nearest transition scope, as a resource OPTION:
|
|
475
631
|
* - `'suspend'` — register as *suspending*: the boundary holds its placeholder until this
|
|
@@ -506,48 +662,6 @@ declare function provideTypedResourceOptions<T>(token: InjectionToken<T>, valueO
|
|
|
506
662
|
*/
|
|
507
663
|
declare function applyResourceRegistration(ref: ResourceRef<unknown>, register: TransitionRegistration | undefined, injector?: Injector): void;
|
|
508
664
|
|
|
509
|
-
/**
|
|
510
|
-
* Options for configuring caching behavior of a `queryResource`.
|
|
511
|
-
* - `true`: Enables caching with default settings.
|
|
512
|
-
* - `{ ttl?: number; staleTime?: number; hash?: (req: HttpResourceRequest) => string; }`: Configures caching with custom settings.
|
|
513
|
-
*/
|
|
514
|
-
type ResourceCacheOptions = true | {
|
|
515
|
-
/**
|
|
516
|
-
* The Time To Live (TTL) for the cached data, in milliseconds. After this time, the cached data is
|
|
517
|
-
* considered expired and will be refetched.
|
|
518
|
-
*/
|
|
519
|
-
ttl?: number;
|
|
520
|
-
/**
|
|
521
|
-
* The duration, in milliseconds, during which stale data can be served while a revalidation request
|
|
522
|
-
* is made in the background.
|
|
523
|
-
*/
|
|
524
|
-
staleTime?: number;
|
|
525
|
-
/**
|
|
526
|
-
* A custom function to generate the cache key. Defaults to using the request URL with parameters.
|
|
527
|
-
* Provide a custom hash function if you need more control over how cache keys are generated,
|
|
528
|
-
* for instance, to ignore certain query parameters or to use request body for the cache key.
|
|
529
|
-
*/
|
|
530
|
-
hash?: (req: HttpResourceRequest) => string;
|
|
531
|
-
/**
|
|
532
|
-
* Whether to bust the browser cache by appending a unique query parameter to the request URL.
|
|
533
|
-
* This is useful for ensuring that the latest data is fetched from the server, bypassing any
|
|
534
|
-
* cached responses in the browser. The unique parameter is removed before calling the cache function, so it does not affect the cache key.
|
|
535
|
-
* @default false - By default, the resource will not bust the browser cache.
|
|
536
|
-
*/
|
|
537
|
-
bustBrowserCache?: boolean;
|
|
538
|
-
/**
|
|
539
|
-
* Whether to ignore the `Cache-Control` headers from the server when caching responses.
|
|
540
|
-
* If set to `true`, the resource will not respect any cache directives from the server,
|
|
541
|
-
* allowing you to control caching behavior entirely through the resource options.
|
|
542
|
-
* @default false - By default the resource will respect `Cache-Control` headers.
|
|
543
|
-
*/
|
|
544
|
-
ignoreCacheControl?: boolean;
|
|
545
|
-
/**
|
|
546
|
-
* Whether to persist the cache entry in the local DB instance.
|
|
547
|
-
* @default false - By default, the cache entry is not persisted.
|
|
548
|
-
*/
|
|
549
|
-
persist?: boolean;
|
|
550
|
-
};
|
|
551
665
|
/**
|
|
552
666
|
* Options for configuring a `queryResource`. Extends Angular's
|
|
553
667
|
* `HttpResourceOptions` with caching, retries, refresh intervals, circuit
|
|
@@ -573,10 +687,19 @@ type QueryResourceOptions<TResult, TRaw = TResult> = HttpResourceOptions<TResult
|
|
|
573
687
|
*/
|
|
574
688
|
keepPrevious?: boolean;
|
|
575
689
|
/**
|
|
576
|
-
*
|
|
577
|
-
*
|
|
690
|
+
* Automatic refresh behavior. A number polls every n milliseconds; the object form
|
|
691
|
+
* composes polling with event-driven triggers:
|
|
692
|
+
*
|
|
693
|
+
* ```ts
|
|
694
|
+
* refresh: 30_000 // poll every 30s
|
|
695
|
+
* refresh: { onFocus: true, onReconnect: true } // refetch on tab refocus / back-online
|
|
696
|
+
* refresh: { interval: 60_000, onFocus: true } // both
|
|
697
|
+
* ```
|
|
698
|
+
*
|
|
699
|
+
* Triggers respect the resource's disabled/paused state (no refetch while
|
|
700
|
+
* offline, circuit-open, or paused).
|
|
578
701
|
*/
|
|
579
|
-
refresh?:
|
|
702
|
+
refresh?: RefreshOptions;
|
|
580
703
|
/**
|
|
581
704
|
* Called on every failed attempt, including each retry.
|
|
582
705
|
*
|
|
@@ -592,6 +715,20 @@ type QueryResourceOptions<TResult, TRaw = TResult> = HttpResourceOptions<TResult
|
|
|
592
715
|
* Options for enabling and configuring caching for the resource.
|
|
593
716
|
*/
|
|
594
717
|
cache?: ResourceCacheOptions;
|
|
718
|
+
/**
|
|
719
|
+
* Opt-in automatic pausing (off by default — existing behavior unchanged):
|
|
720
|
+
* - `true` — pause whenever the surrounding Activity boundary (`MmActivity` /
|
|
721
|
+
* `providePaused` from `@mmstack/primitives`) is paused. Outside a boundary this
|
|
722
|
+
* is a no-op, so it's safe to set app-wide via `provideQueryResourceOptions`.
|
|
723
|
+
* - a `() => boolean` predicate (a `Signal<boolean>` qualifies) — pause while it
|
|
724
|
+
* returns `true`.
|
|
725
|
+
*
|
|
726
|
+
* Pausing has the same semantics as returning `ctx.paused` from the request fn:
|
|
727
|
+
* the resource HOLDS its current value and last request (no refetch on resume if
|
|
728
|
+
* the request is unchanged) and stops background work (polling, focus/reconnect
|
|
729
|
+
* triggers). The two compose — either source can pause the resource.
|
|
730
|
+
*/
|
|
731
|
+
pause?: PauseOption;
|
|
595
732
|
/**
|
|
596
733
|
* Comparison of request object
|
|
597
734
|
*/
|
|
@@ -618,6 +755,9 @@ declare function provideQueryResourceOptions(valueOrFn: Partial<QueryResourceOpt
|
|
|
618
755
|
* }
|
|
619
756
|
* });
|
|
620
757
|
* ```
|
|
758
|
+
*
|
|
759
|
+
* Note: a PAUSED resource also reports `'no-request'` — it holds its previous value
|
|
760
|
+
* and request, but no request is currently active.
|
|
621
761
|
*/
|
|
622
762
|
type DisabledReason = 'offline' | 'circuit-open' | 'no-request';
|
|
623
763
|
/**
|
|
@@ -676,7 +816,10 @@ type QueryResourceRef<TResult> = Omit<HttpResourceRef<TResult>, 'headers' | 'sta
|
|
|
676
816
|
disabledReason: Signal<DisabledReason | null>;
|
|
677
817
|
/**
|
|
678
818
|
* Prefetches data for the resource, populating the cache if caching is enabled. This can be
|
|
679
|
-
* used to proactively load data before it's needed.
|
|
819
|
+
* used to proactively load data before it's needed.
|
|
820
|
+
*
|
|
821
|
+
* Resolves immediately without fetching when caching is disabled or a slow
|
|
822
|
+
* connection is detected (prefetching would compete with user-initiated requests).
|
|
680
823
|
*
|
|
681
824
|
* @param req - Optional partial request parameters to use for the prefetch. This allows you
|
|
682
825
|
* to prefetch data with different parameters than the main resource request.
|
|
@@ -741,6 +884,85 @@ declare function queryResource<TResult, TRaw = TResult>(request: ResourceRequest
|
|
|
741
884
|
*/
|
|
742
885
|
declare function queryResource<TResult, TRaw = TResult>(request: ResourceRequestFn, options?: QueryResourceOptions<TResult, TRaw>): QueryResourceRef<TResult | undefined>;
|
|
743
886
|
|
|
887
|
+
/**
|
|
888
|
+
* Context passed to an infinite query's request fn: the {@link RequestContext}
|
|
889
|
+
* (so the fn can return `ctx.paused` to pause the resource, exactly like
|
|
890
|
+
* `queryResource`) plus the `pageParam` addressing the page to load.
|
|
891
|
+
*/
|
|
892
|
+
type InfiniteRequestContext<TPageParam> = RequestContext & {
|
|
893
|
+
pageParam: TPageParam;
|
|
894
|
+
};
|
|
895
|
+
/**
|
|
896
|
+
* Options for {@link infiniteQueryResource}. Extends {@link QueryResourceOptions}
|
|
897
|
+
* (minus `defaultValue` — the aggregate value is always the `pages` array) with the
|
|
898
|
+
* pagination contract.
|
|
899
|
+
*/
|
|
900
|
+
type InfiniteQueryResourceOptions<TPage, TRaw = TPage, TPageParam = unknown> = Omit<QueryResourceOptions<TPage, TRaw>, 'defaultValue'> & {
|
|
901
|
+
/** The page param the FIRST page is requested with (e.g. `0`, `1`, or a cursor seed). */
|
|
902
|
+
initialPageParam: TPageParam;
|
|
903
|
+
/**
|
|
904
|
+
* Derives the NEXT page's param from the freshly loaded page (and all pages so far).
|
|
905
|
+
* Return `null`/`undefined` to signal "no more pages" — `hasNextPage` flips false
|
|
906
|
+
* and `fetchNextPage()` becomes a no-op.
|
|
907
|
+
*
|
|
908
|
+
* @example
|
|
909
|
+
* // cursor-based
|
|
910
|
+
* getNextPageParam: (last) => last.nextCursor;
|
|
911
|
+
* // offset-based
|
|
912
|
+
* getNextPageParam: (last, all) => (last.items.length < PAGE_SIZE ? null : all.length);
|
|
913
|
+
*/
|
|
914
|
+
getNextPageParam: (lastPage: NoInfer<TPage>, allPages: NoInfer<TPage>[]) => TPageParam | null | undefined;
|
|
915
|
+
};
|
|
916
|
+
/**
|
|
917
|
+
* A paginated query resource. `pages` accumulates every loaded page in order;
|
|
918
|
+
* `fetchNextPage()` loads the next one (no-op while one is in flight or when
|
|
919
|
+
* exhausted). Inherits the underlying query's `status`/`error`/`isLoading` and
|
|
920
|
+
* its features (cache, retry, circuit breaker, refresh).
|
|
921
|
+
*/
|
|
922
|
+
type InfiniteQueryResourceRef<TPage> = {
|
|
923
|
+
/** Every page loaded so far, in load order. */
|
|
924
|
+
pages: Signal<TPage[]>;
|
|
925
|
+
/** `true` once the first page is in and `getNextPageParam` keeps producing params. */
|
|
926
|
+
hasNextPage: Signal<boolean>;
|
|
927
|
+
/** `true` while a page request beyond the first is in flight. */
|
|
928
|
+
isFetchingNextPage: Signal<boolean>;
|
|
929
|
+
/** The underlying query's loading state (first page + subsequent pages). */
|
|
930
|
+
isLoading: Signal<boolean>;
|
|
931
|
+
status: QueryResourceRef<TPage | undefined>['status'];
|
|
932
|
+
error: QueryResourceRef<TPage | undefined>['error'];
|
|
933
|
+
/** Loads the next page. No-op while loading or when `hasNextPage()` is false. */
|
|
934
|
+
fetchNextPage: () => void;
|
|
935
|
+
/** Reloads the CURRENT page param — the freshly loaded page replaces its slot. */
|
|
936
|
+
reload: () => boolean;
|
|
937
|
+
/** Drops all pages and refetches from `initialPageParam`. */
|
|
938
|
+
reset: () => void;
|
|
939
|
+
destroy: () => void;
|
|
940
|
+
};
|
|
941
|
+
/**
|
|
942
|
+
* Creates a paginated HTTP resource over {@link queryResource}: one page request at a
|
|
943
|
+
* time, accumulated into a `pages` signal — cursor- and offset-based pagination both
|
|
944
|
+
* fit through `getNextPageParam`. Each page request inherits the full queryResource
|
|
945
|
+
* feature set (caching per page, retries, circuit breaker, refresh triggers).
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```ts
|
|
949
|
+
* const posts = infiniteQueryResource<PostPage, PostPage, number>(
|
|
950
|
+
* ({ pageParam }) => ({ url: '/api/posts', params: { page: pageParam } }),
|
|
951
|
+
* {
|
|
952
|
+
* initialPageParam: 0,
|
|
953
|
+
* getNextPageParam: (last, all) => (last.items.length < 20 ? null : all.length),
|
|
954
|
+
* cache: true,
|
|
955
|
+
* },
|
|
956
|
+
* );
|
|
957
|
+
*
|
|
958
|
+
* // template:
|
|
959
|
+
* // @for (page of posts.pages(); track $index) { ... }
|
|
960
|
+
* // <button (click)="posts.fetchNextPage()" [disabled]="!posts.hasNextPage()">More</button>
|
|
961
|
+
* const flat = computed(() => posts.pages().flatMap((p) => p.items));
|
|
962
|
+
* ```
|
|
963
|
+
*/
|
|
964
|
+
declare function infiniteQueryResource<TPage, TRaw = TPage, TPageParam = unknown>(request: (ctx: InfiniteRequestContext<TPageParam>) => HttpResourceRequest | string | undefined | typeof PAUSED, options: InfiniteQueryResourceOptions<TPage, TRaw, TPageParam>): InfiniteQueryResourceRef<TPage>;
|
|
965
|
+
|
|
744
966
|
/**
|
|
745
967
|
* A reference to a manually triggered query resource. Extends
|
|
746
968
|
* {@link QueryResourceRef} with a `trigger()` method that runs the request
|
|
@@ -861,7 +1083,7 @@ type NextRequest<TMethod extends HttpResourceRequest['method'], TMutation> = TMe
|
|
|
861
1083
|
* };
|
|
862
1084
|
* ```
|
|
863
1085
|
*/
|
|
864
|
-
type MutationResourceOptions<TResult, TRaw = TResult, TMutation = TResult, TCTX = void, TICTX = TCTX, TError = unknown> = Omit<QueryResourceOptions<TResult, TRaw>, 'equal' | 'onError' | 'keepPrevious' | 'refresh' | 'cache'> & {
|
|
1086
|
+
type MutationResourceOptions<TResult, TRaw = TResult, TMutation = TResult, TCTX = void, TICTX = TCTX, TError = unknown> = Omit<QueryResourceOptions<TResult, TRaw>, 'equal' | 'onError' | 'keepPrevious' | 'refresh' | 'cache' | 'pause'> & {
|
|
865
1087
|
/**
|
|
866
1088
|
* A callback function that is called before the mutation request is made.
|
|
867
1089
|
* @param value The value being mutated (the `body` of the request).
|
|
@@ -891,6 +1113,25 @@ type MutationResourceOptions<TResult, TRaw = TResult, TMutation = TResult, TCTX
|
|
|
891
1113
|
* @default false
|
|
892
1114
|
*/
|
|
893
1115
|
queue?: boolean;
|
|
1116
|
+
/**
|
|
1117
|
+
* Cache entries to invalidate after a SUCCESSFUL mutation — the declarative
|
|
1118
|
+
* alternative to calling `injectQueryCache().invalidatePrefix(...)` in `onSuccess`.
|
|
1119
|
+
*
|
|
1120
|
+
* Each string is a URL prefix matched against auto-generated `GET` cache keys
|
|
1121
|
+
* (`GET:${url}:...`): `'/api/posts'` invalidates `/api/posts` with any query params,
|
|
1122
|
+
* plus subpaths like `/api/posts/123` — and all `varyHeaders` variants of each.
|
|
1123
|
+
* Note that plain prefix matching also catches sibling paths sharing the prefix
|
|
1124
|
+
* (`/api/posts-archive`); pass `'/api/posts/'` or the exact URL to narrow.
|
|
1125
|
+
*
|
|
1126
|
+
* Entries keyed by a custom `hash` function follow that function's shape, not the
|
|
1127
|
+
* auto-key shape — invalidate those manually via `injectQueryCache().invalidateWhere`.
|
|
1128
|
+
*
|
|
1129
|
+
* The function form receives the mutation result and the mutated value:
|
|
1130
|
+
* ```ts
|
|
1131
|
+
* invalidates: (saved) => [`/api/posts`, `/api/users/${saved.authorId}`]
|
|
1132
|
+
* ```
|
|
1133
|
+
*/
|
|
1134
|
+
invalidates?: string[] | ((value: NoInfer<TResult>, mutation: NoInfer<TMutation>) => string[]);
|
|
894
1135
|
equal?: ValueEqualityFn<TMutation>;
|
|
895
1136
|
};
|
|
896
1137
|
/**
|
|
@@ -983,5 +1224,5 @@ type MutationResourceRef<TResult, TMutation = TResult, TICTX = void> = Omit<Quer
|
|
|
983
1224
|
*/
|
|
984
1225
|
declare function mutationResource<TResult, TRaw = TResult, TMutation = TResult, TCTX = void, TICTX = TCTX, TMethod extends HttpResourceRequest['method'] = HttpResourceRequest['method']>(request: (params: TMutation) => Omit<NextRequest<TMethod, TMutation>, 'body'> | undefined | void, options0?: MutationResourceOptions<TResult, TRaw, TMutation, TCTX, TICTX>): MutationResourceRef<TResult, TMutation, TICTX>;
|
|
985
1226
|
|
|
986
|
-
export { Cache, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
987
|
-
export type { CommonResourceOptions, DisabledReason, ManualQueryResourceRef, MutationResourceOptions, MutationResourceRef, QueryResourceOptions, QueryResourceRef, RequestContext, ResourceRequestFn, TransitionRegistration };
|
|
1227
|
+
export { Cache, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, hashRequest, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
1228
|
+
export type { CacheEntry, CleanupType, CommonResourceOptions, DisabledReason, InfiniteQueryResourceOptions, InfiniteQueryResourceRef, InfiniteRequestContext, ManualQueryResourceRef, MutationResourceOptions, MutationResourceRef, QueryResourceOptions, QueryResourceRef, RefreshOptions, RequestContext, ResourceCacheOptions, ResourceRequestFn, TransitionRegistration };
|