@mmstack/resource 21.4.2 → 21.4.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.
|
@@ -837,13 +837,46 @@ const SAFE_RAW_HEADERS = new Set([
|
|
|
837
837
|
'content-language',
|
|
838
838
|
'content-type',
|
|
839
839
|
]);
|
|
840
|
+
const UNSAFE_HEADER_MESSAGES = new Map([
|
|
841
|
+
[
|
|
842
|
+
'cookie',
|
|
843
|
+
"[@mmstack/resource]: varyHeaders includes 'cookie'. Browser-attached cookies never appear on the request object (so this usually partitions nothing), and manually-set cookie values often rotate per-request (shredding the hit rate). The header IS still honored (digested) — but prefer varying on 'Authorization' or a tenant header.",
|
|
844
|
+
],
|
|
845
|
+
[
|
|
846
|
+
'set-cookie',
|
|
847
|
+
"[@mmstack/resource]: varyHeaders includes 'set-cookie'. Browser-attached cookies never appear on the request object (so this usually partitions nothing), and manually-set cookie values often rotate per-request (shredding the hit rate). The header IS still honored (digested) — but prefer varying on 'Authorization' or a tenant header.",
|
|
848
|
+
],
|
|
849
|
+
[
|
|
850
|
+
'authorization',
|
|
851
|
+
"[@mmstack/resource]: varyHeaders includes 'Authorization'. If your token rotates frequently (e.g., short-lived JWTs), this will cause 100% cache churn on refresh. Consider adding a namespace prefix with the users sub, not using it as a cache-key or using a custom 'cache.hash' function with a stable session/user ID instead.",
|
|
852
|
+
],
|
|
853
|
+
[
|
|
854
|
+
'x-request-id',
|
|
855
|
+
"[@mmstack/resource]: varyHeaders includes 'X-Request-ID'. This header is often set to a unique value per-request, which will cause 100% cache churn. Consider removing it from varyHeaders or using a custom 'cache.hash' function that ignores it.",
|
|
856
|
+
],
|
|
857
|
+
[
|
|
858
|
+
'x-correlation-id',
|
|
859
|
+
"[@mmstack/resource]: varyHeaders includes 'X-Correlation-ID'. This header is often set to a unique value per-request, which will cause 100% cache churn. Consider removing it from varyHeaders or using a custom 'cache.hash' function that ignores it.",
|
|
860
|
+
],
|
|
861
|
+
[
|
|
862
|
+
'if-none-match',
|
|
863
|
+
"[@mmstack/resource]: varyHeaders includes 'If-None-Match'. This header contains ETags that change whenever the server's resource version changes, which will cause cache misses on every update. Consider removing it from varyHeaders or using a custom 'cache.hash' function that ignores it.",
|
|
864
|
+
],
|
|
865
|
+
[
|
|
866
|
+
'if-modified-since',
|
|
867
|
+
"[@mmstack/resource]: varyHeaders includes 'If-Modified-Since'. This header contains timestamps that change whenever the server's resource version changes, which will cause cache misses on every update. Consider removing it from varyHeaders or using a custom 'cache.hash' function that ignores it.",
|
|
868
|
+
],
|
|
869
|
+
]);
|
|
840
870
|
function normalizeVaryHeaders(headers, names) {
|
|
871
|
+
const isDev = isDevMode();
|
|
841
872
|
return names
|
|
842
873
|
.map((n) => n.toLowerCase())
|
|
843
874
|
.toSorted()
|
|
844
875
|
.map((name) => {
|
|
845
|
-
if (
|
|
846
|
-
|
|
876
|
+
if (isDev) {
|
|
877
|
+
const warning = UNSAFE_HEADER_MESSAGES.get(name);
|
|
878
|
+
if (warning)
|
|
879
|
+
console.warn(warning);
|
|
847
880
|
}
|
|
848
881
|
const value = readHeader(headers, name);
|
|
849
882
|
if (value === null)
|
|
@@ -857,13 +890,17 @@ function normalizeVaryHeaders(headers, names) {
|
|
|
857
890
|
.join('&');
|
|
858
891
|
}
|
|
859
892
|
function normalizeParams(params) {
|
|
860
|
-
const p = params instanceof HttpParams
|
|
893
|
+
const p = params instanceof HttpParams
|
|
894
|
+
? params
|
|
895
|
+
: new HttpParams({ fromObject: params });
|
|
861
896
|
return p
|
|
862
897
|
.keys()
|
|
863
898
|
.toSorted()
|
|
864
899
|
.map((key) => {
|
|
865
900
|
const encodedKey = encodeURIComponent(key);
|
|
866
|
-
return (p.getAll(key) ?? [])
|
|
901
|
+
return (p.getAll(key) ?? [])
|
|
902
|
+
.map((v) => `${encodedKey}=${encodeURIComponent(v)}`)
|
|
903
|
+
.join('&');
|
|
867
904
|
})
|
|
868
905
|
.join('&');
|
|
869
906
|
}
|
|
@@ -883,7 +920,8 @@ function hashBody(body) {
|
|
|
883
920
|
entries.sort(([ak, av], [bk, bv]) => ak.localeCompare(bk) || av.localeCompare(bv));
|
|
884
921
|
return `FormData:${entries.map(([k, v]) => `${k}=${v}`).join('&')}`;
|
|
885
922
|
}
|
|
886
|
-
if (typeof URLSearchParams !== 'undefined' &&
|
|
923
|
+
if (typeof URLSearchParams !== 'undefined' &&
|
|
924
|
+
body instanceof URLSearchParams) {
|
|
887
925
|
const sp = new URLSearchParams(body);
|
|
888
926
|
sp.sort();
|
|
889
927
|
return `URLSearchParams:${sp.toString()}`;
|
|
@@ -1629,6 +1667,57 @@ function hasSlowConnection() {
|
|
|
1629
1667
|
return false;
|
|
1630
1668
|
}
|
|
1631
1669
|
|
|
1670
|
+
/**
|
|
1671
|
+
* Deep merges multiple circuit breaker options.
|
|
1672
|
+
* The latter options override the former.
|
|
1673
|
+
*/
|
|
1674
|
+
function mergeCircuitBreakerOptions(global, query, local) {
|
|
1675
|
+
if (!global && !query && !local)
|
|
1676
|
+
return undefined;
|
|
1677
|
+
return {
|
|
1678
|
+
...(global === true ? {} : global),
|
|
1679
|
+
...(query === true ? {} : query),
|
|
1680
|
+
...(local === true ? {} : local),
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Deep merges multiple retry options.
|
|
1685
|
+
* The latter options override the former.
|
|
1686
|
+
*/
|
|
1687
|
+
function mergeRetryOptions(global, query, local) {
|
|
1688
|
+
if (global === undefined && query === undefined && local === undefined)
|
|
1689
|
+
return undefined;
|
|
1690
|
+
return {
|
|
1691
|
+
...(typeof global === 'number' ? { max: global } : global),
|
|
1692
|
+
...(typeof query === 'number' ? { max: query } : query),
|
|
1693
|
+
...(typeof local === 'number' ? { max: local } : local),
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
/**
|
|
1697
|
+
* Deep merges multiple cache options.
|
|
1698
|
+
* The latter options override the former.
|
|
1699
|
+
*/
|
|
1700
|
+
function mergeCacheOptions(query, local) {
|
|
1701
|
+
if (query === undefined && local === undefined)
|
|
1702
|
+
return undefined;
|
|
1703
|
+
return {
|
|
1704
|
+
...(query === true ? {} : query),
|
|
1705
|
+
...(local === true ? {} : local),
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Deep merges multiple refresh options.
|
|
1710
|
+
* The latter options override the former.
|
|
1711
|
+
*/
|
|
1712
|
+
function mergeRefreshOptions(query, local) {
|
|
1713
|
+
if (query === undefined && local === undefined)
|
|
1714
|
+
return undefined;
|
|
1715
|
+
return {
|
|
1716
|
+
...(typeof query === 'number' ? { interval: query } : query),
|
|
1717
|
+
...(typeof local === 'number' ? { interval: local } : local),
|
|
1718
|
+
};
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1632
1721
|
function persistResourceValues(resource, shouldPersist = false, equal) {
|
|
1633
1722
|
if (!shouldPersist)
|
|
1634
1723
|
return resource;
|
|
@@ -1848,10 +1937,16 @@ function injectQueryResourceOptions(injector) {
|
|
|
1848
1937
|
const PAUSED = Symbol('@mmstack/resource:paused');
|
|
1849
1938
|
function queryResource(request, options0) {
|
|
1850
1939
|
// Two-layer option injection: per-call > provideQueryResourceOptions > provideResourceOptions.
|
|
1940
|
+
const globalOpts = injectResourceOptions(options0?.injector);
|
|
1941
|
+
const queryOpts = injectQueryResourceOptions(options0?.injector);
|
|
1851
1942
|
const options = {
|
|
1852
|
-
...
|
|
1853
|
-
...
|
|
1943
|
+
...globalOpts,
|
|
1944
|
+
...queryOpts,
|
|
1854
1945
|
...options0,
|
|
1946
|
+
cache: mergeCacheOptions(queryOpts.cache, options0?.cache),
|
|
1947
|
+
circuitBreaker: mergeCircuitBreakerOptions(globalOpts.circuitBreaker, queryOpts.circuitBreaker, options0?.circuitBreaker),
|
|
1948
|
+
retry: mergeRetryOptions(globalOpts.retry, queryOpts.retry, options0?.retry),
|
|
1949
|
+
refresh: mergeRefreshOptions(queryOpts.refresh, options0?.refresh),
|
|
1855
1950
|
};
|
|
1856
1951
|
const cache = injectQueryCache(options?.injector);
|
|
1857
1952
|
const destroyRef = options?.injector
|
|
@@ -2323,10 +2418,14 @@ function injectMutationResourceOptions(injector) {
|
|
|
2323
2418
|
*/
|
|
2324
2419
|
function mutationResource(request, options0 = {}) {
|
|
2325
2420
|
// Two-layer option injection: per-call > provideMutationResourceOptions > provideResourceOptions.
|
|
2421
|
+
const globalOpts = injectResourceOptions(options0.injector);
|
|
2422
|
+
const mutOpts = injectMutationResourceOptions(options0.injector);
|
|
2326
2423
|
const options = {
|
|
2327
|
-
...
|
|
2328
|
-
...
|
|
2424
|
+
...globalOpts,
|
|
2425
|
+
...mutOpts,
|
|
2329
2426
|
...options0,
|
|
2427
|
+
circuitBreaker: mergeCircuitBreakerOptions(globalOpts.circuitBreaker, mutOpts.circuitBreaker, options0?.circuitBreaker),
|
|
2428
|
+
retry: mergeRetryOptions(globalOpts.retry, mutOpts.retry, options0?.retry),
|
|
2330
2429
|
};
|
|
2331
2430
|
// `register` is pulled out (and forced off on the inner query below) so the mutation ref is
|
|
2332
2431
|
// the only thing registered into the transition scope, not its internal query resource.
|
|
@@ -2507,5 +2606,5 @@ function mutationResource(request, options0 = {}) {
|
|
|
2507
2606
|
* Generated bundle index. Do not edit.
|
|
2508
2607
|
*/
|
|
2509
2608
|
|
|
2510
|
-
export { Cache, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
2609
|
+
export { Cache, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, hashRequest, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
2511
2610
|
//# sourceMappingURL=mmstack-resource.mjs.map
|