@mmstack/resource 21.4.2 → 21.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmstack/resource",
3
- "version": "21.4.2",
3
+ "version": "21.4.4",
4
4
  "keywords": [
5
5
  "angular",
6
6
  "signals",
@@ -1,4 +1,4 @@
1
- import { HttpResponse, HttpInterceptorFn, HttpRequest, HttpContext, HttpResourceOptions, HttpResourceRequest, HttpResourceRef, HttpHeaders } from '@angular/common/http';
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
3
  import { PauseOption } from '@mmstack/primitives';
4
4
 
@@ -518,6 +518,33 @@ declare function noDedupe(ctx?: HttpContext): HttpContext;
518
518
  */
519
519
  declare function createDedupeRequestsInterceptor(allowed?: string[], keyFn?: (req: HttpRequest<unknown>) => string): HttpInterceptorFn;
520
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
+
521
548
  /**
522
549
  * Refresh configuration for a query resource.
523
550
  * - a `number` is shorthand for `{ interval: number }` (poll every n milliseconds)
@@ -546,6 +573,59 @@ type RetryOptions = number | {
546
573
  backoff?: number;
547
574
  };
548
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
+ };
549
629
  /**
550
630
  * Auto-registration into the nearest transition scope, as a resource OPTION:
551
631
  * - `'suspend'` — register as *suspending*: the boundary holds its placeholder until this
@@ -582,59 +662,6 @@ declare function provideTypedResourceOptions<T>(token: InjectionToken<T>, valueO
582
662
  */
583
663
  declare function applyResourceRegistration(ref: ResourceRef<unknown>, register: TransitionRegistration | undefined, injector?: Injector): void;
584
664
 
585
- /**
586
- * Options for configuring caching behavior of a `queryResource`.
587
- * - `true`: Enables caching with default settings.
588
- * - `{ ttl?: number; staleTime?: number; hash?: (req: HttpResourceRequest) => string; }`: Configures caching with custom settings.
589
- */
590
- type ResourceCacheOptions = true | {
591
- /**
592
- * The Time To Live (TTL) for the cached data, in milliseconds. After this time, the cached data is
593
- * considered expired and will be refetched.
594
- */
595
- ttl?: number;
596
- /**
597
- * The duration, in milliseconds, during which stale data can be served while a revalidation request
598
- * is made in the background.
599
- */
600
- staleTime?: number;
601
- /**
602
- * A custom function to generate the cache key. Defaults to using the request URL with parameters.
603
- * Provide a custom hash function if you need more control over how cache keys are generated,
604
- * for instance, to ignore certain query parameters or to use request body for the cache key.
605
- */
606
- hash?: (req: HttpResourceRequest) => string;
607
- /**
608
- * Whether to bust the browser cache by appending a unique query parameter to the request URL.
609
- * This is useful for ensuring that the latest data is fetched from the server, bypassing any
610
- * cached responses in the browser. The unique parameter is removed before calling the cache function, so it does not affect the cache key.
611
- * @default false - By default, the resource will not bust the browser cache.
612
- */
613
- bustBrowserCache?: boolean;
614
- /**
615
- * Whether to ignore the `Cache-Control` headers from the server when caching responses.
616
- * If set to `true`, the resource will not respect any cache directives from the server,
617
- * allowing you to control caching behavior entirely through the resource options.
618
- * @default false - By default the resource will respect `Cache-Control` headers.
619
- */
620
- ignoreCacheControl?: boolean;
621
- /**
622
- * Whether to persist the cache entry in the local DB instance.
623
- * @default false - By default, the cache entry is not persisted.
624
- */
625
- persist?: boolean;
626
- /**
627
- * Request headers whose values should partition the cache key — e.g.
628
- * `['Authorization']` gives each user their own entries, `['Accept-Language']`
629
- * separates per-language responses. Header values are one-way digested into the
630
- * key (never embedded raw), so secrets don't end up in persisted/broadcast keys.
631
- * Ignored when a custom `hash` function is provided (it owns the key entirely).
632
- *
633
- * Note: still call `cache.clear()` on logout — the previous user's entries are
634
- * unreachable under the new key but linger until their TTL.
635
- */
636
- varyHeaders?: string[];
637
- };
638
665
  /**
639
666
  * Options for configuring a `queryResource`. Extends Angular's
640
667
  * `HttpResourceOptions` with caching, retries, refresh intervals, circuit
@@ -1197,5 +1224,5 @@ type MutationResourceRef<TResult, TMutation = TResult, TICTX = void> = Omit<Quer
1197
1224
  */
1198
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>;
1199
1226
 
1200
- export { Cache, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
1201
- export type { CacheEntry, CleanupType, CommonResourceOptions, DisabledReason, InfiniteQueryResourceOptions, InfiniteQueryResourceRef, InfiniteRequestContext, ManualQueryResourceRef, MutationResourceOptions, MutationResourceRef, QueryResourceOptions, QueryResourceRef, RefreshOptions, 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 };