@mmstack/resource 22.1.6 → 22.2.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/README.md +101 -8
- package/fesm2022/mmstack-resource.mjs +499 -380
- package/fesm2022/mmstack-resource.mjs.map +1 -1
- package/package.json +1 -1
- package/types/mmstack-resource.d.ts +91 -7
package/package.json
CHANGED
|
@@ -80,6 +80,8 @@ declare class Cache<T> {
|
|
|
80
80
|
private hydrated;
|
|
81
81
|
/** Keys invalidated while hydration was still in flight — must not be resurrected by it. */
|
|
82
82
|
private readonly hydrationTombstones;
|
|
83
|
+
/** Dev-only: ensures the "foreign keys, no matcher" hint in invalidateUrlPrefix fires at most once. */
|
|
84
|
+
private warnedForeignKeys;
|
|
83
85
|
private readonly hitCount;
|
|
84
86
|
private readonly missCount;
|
|
85
87
|
/**
|
|
@@ -189,6 +191,35 @@ declare class Cache<T> {
|
|
|
189
191
|
* cache.invalidatePrefix('GET https://api.example.com/posts');
|
|
190
192
|
*/
|
|
191
193
|
invalidatePrefix(prefix: string): number;
|
|
194
|
+
/**
|
|
195
|
+
* Invalidates every cache entry whose *request URL* starts with `urlPrefix`,
|
|
196
|
+
* regardless of HTTP method. This is the engine behind `mutationResource`'s
|
|
197
|
+
* `invalidates` option: `'/api/posts'` clears `/api/posts` with any query
|
|
198
|
+
* params, subpaths like `/api/posts/123`, and all `varyHeaders` variants —
|
|
199
|
+
* across GET/HEAD/OPTIONS/POST or any other cached method. Returns the number
|
|
200
|
+
* of entries removed.
|
|
201
|
+
*
|
|
202
|
+
* Unlike {@link invalidatePrefix} (which matches the raw key from its start),
|
|
203
|
+
* this extracts the URL field from the auto-generated key shape, so it is not
|
|
204
|
+
* fooled by the leading method token nor by a namespace a custom `cache.hash`
|
|
205
|
+
* prepends (e.g. `tenant:…`). Plain prefix matching still catches siblings
|
|
206
|
+
* sharing the prefix (`/api/posts-archive`) — pass `'/api/posts/'` to narrow.
|
|
207
|
+
*
|
|
208
|
+
* Keys produced by a custom `hash` that don't follow the auto shape won't be
|
|
209
|
+
* matched by the default; pass `match` to describe how a URL prefix maps onto
|
|
210
|
+
* your key format. In dev mode, if a default-matcher call removes nothing and
|
|
211
|
+
* every cached key is foreign-shaped, this logs a one-time hint pointing at the
|
|
212
|
+
* `match` escape hatch (a likely sign of a custom `hash` with no matcher wired up).
|
|
213
|
+
*
|
|
214
|
+
* @param urlPrefix - URL prefix to match.
|
|
215
|
+
* @param match - Optional custom matcher: given the prefix, returns a key predicate.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* cache.invalidateUrlPrefix('/api/posts');
|
|
219
|
+
* // custom key scheme:
|
|
220
|
+
* cache.invalidateUrlPrefix('/api/posts', (p) => (k) => k.includes(`|url=${p}`));
|
|
221
|
+
*/
|
|
222
|
+
invalidateUrlPrefix(urlPrefix: string, match?: (urlPrefix: string) => (key: string) => boolean): number;
|
|
192
223
|
/**
|
|
193
224
|
* Invalidates every cache entry whose key matches the predicate. Use for
|
|
194
225
|
* arbitrary bulk invalidation that doesn't fit prefix matching (e.g.
|
|
@@ -242,6 +273,26 @@ type CacheOptions = {
|
|
|
242
273
|
*/
|
|
243
274
|
version?: number;
|
|
244
275
|
};
|
|
276
|
+
/**
|
|
277
|
+
* Provides a deterministic, in-memory `QueryCache` for unit tests.
|
|
278
|
+
*
|
|
279
|
+
* Unlike {@link provideQueryCache} this never touches IndexedDB or BroadcastChannel
|
|
280
|
+
* and disables the cleanup sweep interval (`checkInterval: Infinity`), so it plays
|
|
281
|
+
* nicely with `vi.useFakeTimers()`. It's a real cache (not a stub), so you can
|
|
282
|
+
* assert cache hits via {@link injectQueryCache} / its `stats` signal.
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* TestBed.configureTestingModule({
|
|
286
|
+
* providers: [
|
|
287
|
+
* provideMockQueryCache(),
|
|
288
|
+
* provideHttpClient(withInterceptors([createCacheInterceptor()])),
|
|
289
|
+
* ],
|
|
290
|
+
* });
|
|
291
|
+
*/
|
|
292
|
+
declare function provideMockQueryCache(opt?: {
|
|
293
|
+
ttl?: number;
|
|
294
|
+
staleTime?: number;
|
|
295
|
+
}): Provider;
|
|
245
296
|
/**
|
|
246
297
|
* Provides the instance of the QueryCache for queryResource. This should probably be called
|
|
247
298
|
* in your application's root configuration, but can also be overriden with component/module providers.
|
|
@@ -530,7 +581,9 @@ type HashableRequest = {
|
|
|
530
581
|
* Builds a stable cache/dedupe key from an HTTP request shape (accepts both
|
|
531
582
|
* `HttpRequest` and `HttpResourceRequest`).
|
|
532
583
|
*
|
|
533
|
-
* Key composition: `${method}
|
|
584
|
+
* Key composition: `${method}␟${url}␟${responseType}[␟${params}][␟${body}][␟${vary}]`,
|
|
585
|
+
* where `␟` is {@link KEY_DELIMITER} (ASCII Unit Separator) — a content-rare top-level
|
|
586
|
+
* separator. Sub-fields inside `params`/`vary` keep their own `&`/`=` delimiters.
|
|
534
587
|
* - `method` defaults to `'GET'`, `responseType` to `'json'` (Angular defaults).
|
|
535
588
|
* - Query params are sorted alphabetically and URL-encoded for stability.
|
|
536
589
|
* - Body hashing handles `File`/`Blob`/`FormData`/`URLSearchParams`/`ArrayBuffer`
|
|
@@ -573,6 +626,29 @@ type RetryOptions = number | {
|
|
|
573
626
|
backoff?: number;
|
|
574
627
|
};
|
|
575
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Provides controllable {@link ResourceSensors} for unit tests, letting you drive a
|
|
631
|
+
* resource's offline / page-hidden behavior deterministically instead of relying on
|
|
632
|
+
* the real `navigator.onLine` / `document.visibilityState`.
|
|
633
|
+
*
|
|
634
|
+
* Pass your own writable signals to toggle state mid-test; omit them for a static
|
|
635
|
+
* online + visible environment.
|
|
636
|
+
*
|
|
637
|
+
* @example
|
|
638
|
+
* import { signal } from '@angular/core';
|
|
639
|
+
*
|
|
640
|
+
* const online = signal(true);
|
|
641
|
+
* TestBed.configureTestingModule({
|
|
642
|
+
* providers: [provideMockResourceSensors({ networkStatus: online })],
|
|
643
|
+
* });
|
|
644
|
+
* // ...later in the test
|
|
645
|
+
* online.set(false); // the resource now sees the network as down
|
|
646
|
+
*/
|
|
647
|
+
declare function provideMockResourceSensors(opt?: {
|
|
648
|
+
networkStatus?: Signal<boolean>;
|
|
649
|
+
pageVisibility?: Signal<DocumentVisibilityState>;
|
|
650
|
+
}): Provider;
|
|
651
|
+
|
|
576
652
|
/**
|
|
577
653
|
* Options for enabling and configuring caching for a resource.
|
|
578
654
|
*
|
|
@@ -1144,14 +1220,17 @@ type MutationResourceOptions<TResult, TRaw = TResult, TMutation = TResult, TCTX
|
|
|
1144
1220
|
* Cache entries to invalidate after a SUCCESSFUL mutation — the declarative
|
|
1145
1221
|
* alternative to calling `injectQueryCache().invalidatePrefix(...)` in `onSuccess`.
|
|
1146
1222
|
*
|
|
1147
|
-
* Each string is a URL prefix matched against
|
|
1148
|
-
*
|
|
1149
|
-
* plus subpaths like `/api/posts/123` — and all `varyHeaders`
|
|
1223
|
+
* Each string is a URL prefix matched against the request URL of every cached
|
|
1224
|
+
* entry, regardless of HTTP method: `'/api/posts'` invalidates `/api/posts` with
|
|
1225
|
+
* any query params, plus subpaths like `/api/posts/123` — and all `varyHeaders`
|
|
1226
|
+
* variants of each — across GET/HEAD/OPTIONS/POST or whatever methods you cache.
|
|
1150
1227
|
* Note that plain prefix matching also catches sibling paths sharing the prefix
|
|
1151
1228
|
* (`/api/posts-archive`); pass `'/api/posts/'` or the exact URL to narrow.
|
|
1152
1229
|
*
|
|
1153
|
-
*
|
|
1154
|
-
*
|
|
1230
|
+
* Keys built by a custom `cache.hash` that merely *prepends* a namespace (e.g. a
|
|
1231
|
+
* tenant/`sub` for per-user persistent caches) are still matched — the URL is
|
|
1232
|
+
* recovered structurally. Keys that abandon the auto shape entirely need an
|
|
1233
|
+
* a custom invalidateMatcher (or manual `injectQueryCache().invalidateWhere`).
|
|
1155
1234
|
*
|
|
1156
1235
|
* The function form receives the mutation result and the mutated value:
|
|
1157
1236
|
* ```ts
|
|
@@ -1159,6 +1238,11 @@ type MutationResourceOptions<TResult, TRaw = TResult, TMutation = TResult, TCTX
|
|
|
1159
1238
|
* ```
|
|
1160
1239
|
*/
|
|
1161
1240
|
invalidates?: string[] | ((value: NoInfer<TResult>, mutation: NoInfer<TMutation>) => string[]);
|
|
1241
|
+
/**
|
|
1242
|
+
* override for how {@link MutationResourceOptions.invalidates} URL
|
|
1243
|
+
* prefixes map onto cache keys — given a prefix, return a key predicate.
|
|
1244
|
+
*/
|
|
1245
|
+
invalidateMatcher?: (urlPrefix: string) => (key: string) => boolean;
|
|
1162
1246
|
equal?: ValueEqualityFn<TMutation>;
|
|
1163
1247
|
};
|
|
1164
1248
|
/**
|
|
@@ -1273,5 +1357,5 @@ declare function mutationResource<TResult, TRaw = TResult, TMutation = TResult,
|
|
|
1273
1357
|
body: TMutation;
|
|
1274
1358
|
}) | undefined | void, options0?: MutationResourceOptions<TResult, TRaw, TMutation, TCTX, TICTX>): MutationResourceRef<TResult, TMutation, TICTX>;
|
|
1275
1359
|
|
|
1276
|
-
export { Cache, MutationCancelledError, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, hashRequest, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
1360
|
+
export { Cache, MutationCancelledError, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, hashRequest, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMockQueryCache, provideMockResourceSensors, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
1277
1361
|
export type { CacheEntry, CleanupType, CommonResourceOptions, DisabledReason, InfiniteQueryResourceOptions, InfiniteQueryResourceRef, InfiniteRequestContext, ManualQueryResourceRef, MutationCancellationReason, MutationQueueOptions, MutationResourceOptions, MutationResourceRef, QueryResourceOptions, QueryResourceRef, RefreshOptions, RequestContext, ResourceCacheOptions, ResourceRequestFn, TransitionRegistration };
|