@mmstack/resource 22.1.2 → 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.
|
@@ -841,13 +841,46 @@ const SAFE_RAW_HEADERS = new Set([
|
|
|
841
841
|
'content-language',
|
|
842
842
|
'content-type',
|
|
843
843
|
]);
|
|
844
|
+
const UNSAFE_HEADER_MESSAGES = new Map([
|
|
845
|
+
[
|
|
846
|
+
'cookie',
|
|
847
|
+
"[@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.",
|
|
848
|
+
],
|
|
849
|
+
[
|
|
850
|
+
'set-cookie',
|
|
851
|
+
"[@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.",
|
|
852
|
+
],
|
|
853
|
+
[
|
|
854
|
+
'authorization',
|
|
855
|
+
"[@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.",
|
|
856
|
+
],
|
|
857
|
+
[
|
|
858
|
+
'x-request-id',
|
|
859
|
+
"[@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.",
|
|
860
|
+
],
|
|
861
|
+
[
|
|
862
|
+
'x-correlation-id',
|
|
863
|
+
"[@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.",
|
|
864
|
+
],
|
|
865
|
+
[
|
|
866
|
+
'if-none-match',
|
|
867
|
+
"[@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.",
|
|
868
|
+
],
|
|
869
|
+
[
|
|
870
|
+
'if-modified-since',
|
|
871
|
+
"[@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.",
|
|
872
|
+
],
|
|
873
|
+
]);
|
|
844
874
|
function normalizeVaryHeaders(headers, names) {
|
|
875
|
+
const isDev = isDevMode();
|
|
845
876
|
return names
|
|
846
877
|
.map((n) => n.toLowerCase())
|
|
847
878
|
.toSorted()
|
|
848
879
|
.map((name) => {
|
|
849
|
-
if (
|
|
850
|
-
|
|
880
|
+
if (isDev) {
|
|
881
|
+
const warning = UNSAFE_HEADER_MESSAGES.get(name);
|
|
882
|
+
if (warning)
|
|
883
|
+
console.warn(warning);
|
|
851
884
|
}
|
|
852
885
|
const value = readHeader(headers, name);
|
|
853
886
|
if (value === null)
|
|
@@ -861,13 +894,17 @@ function normalizeVaryHeaders(headers, names) {
|
|
|
861
894
|
.join('&');
|
|
862
895
|
}
|
|
863
896
|
function normalizeParams(params) {
|
|
864
|
-
const p = params instanceof HttpParams
|
|
897
|
+
const p = params instanceof HttpParams
|
|
898
|
+
? params
|
|
899
|
+
: new HttpParams({ fromObject: params });
|
|
865
900
|
return p
|
|
866
901
|
.keys()
|
|
867
902
|
.toSorted()
|
|
868
903
|
.map((key) => {
|
|
869
904
|
const encodedKey = encodeURIComponent(key);
|
|
870
|
-
return (p.getAll(key) ?? [])
|
|
905
|
+
return (p.getAll(key) ?? [])
|
|
906
|
+
.map((v) => `${encodedKey}=${encodeURIComponent(v)}`)
|
|
907
|
+
.join('&');
|
|
871
908
|
})
|
|
872
909
|
.join('&');
|
|
873
910
|
}
|
|
@@ -887,7 +924,8 @@ function hashBody(body) {
|
|
|
887
924
|
entries.sort(([ak, av], [bk, bv]) => ak.localeCompare(bk) || av.localeCompare(bv));
|
|
888
925
|
return `FormData:${entries.map(([k, v]) => `${k}=${v}`).join('&')}`;
|
|
889
926
|
}
|
|
890
|
-
if (typeof URLSearchParams !== 'undefined' &&
|
|
927
|
+
if (typeof URLSearchParams !== 'undefined' &&
|
|
928
|
+
body instanceof URLSearchParams) {
|
|
891
929
|
const sp = new URLSearchParams(body);
|
|
892
930
|
sp.sort();
|
|
893
931
|
return `URLSearchParams:${sp.toString()}`;
|
|
@@ -1640,6 +1678,57 @@ function hasSlowConnection() {
|
|
|
1640
1678
|
return false;
|
|
1641
1679
|
}
|
|
1642
1680
|
|
|
1681
|
+
/**
|
|
1682
|
+
* Deep merges multiple circuit breaker options.
|
|
1683
|
+
* The latter options override the former.
|
|
1684
|
+
*/
|
|
1685
|
+
function mergeCircuitBreakerOptions(global, query, local) {
|
|
1686
|
+
if (!global && !query && !local)
|
|
1687
|
+
return undefined;
|
|
1688
|
+
return {
|
|
1689
|
+
...(global === true ? {} : global),
|
|
1690
|
+
...(query === true ? {} : query),
|
|
1691
|
+
...(local === true ? {} : local),
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Deep merges multiple retry options.
|
|
1696
|
+
* The latter options override the former.
|
|
1697
|
+
*/
|
|
1698
|
+
function mergeRetryOptions(global, query, local) {
|
|
1699
|
+
if (global === undefined && query === undefined && local === undefined)
|
|
1700
|
+
return undefined;
|
|
1701
|
+
return {
|
|
1702
|
+
...(typeof global === 'number' ? { max: global } : global),
|
|
1703
|
+
...(typeof query === 'number' ? { max: query } : query),
|
|
1704
|
+
...(typeof local === 'number' ? { max: local } : local),
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
/**
|
|
1708
|
+
* Deep merges multiple cache options.
|
|
1709
|
+
* The latter options override the former.
|
|
1710
|
+
*/
|
|
1711
|
+
function mergeCacheOptions(query, local) {
|
|
1712
|
+
if (query === undefined && local === undefined)
|
|
1713
|
+
return undefined;
|
|
1714
|
+
return {
|
|
1715
|
+
...(query === true ? {} : query),
|
|
1716
|
+
...(local === true ? {} : local),
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Deep merges multiple refresh options.
|
|
1721
|
+
* The latter options override the former.
|
|
1722
|
+
*/
|
|
1723
|
+
function mergeRefreshOptions(query, local) {
|
|
1724
|
+
if (query === undefined && local === undefined)
|
|
1725
|
+
return undefined;
|
|
1726
|
+
return {
|
|
1727
|
+
...(typeof query === 'number' ? { interval: query } : query),
|
|
1728
|
+
...(typeof local === 'number' ? { interval: local } : local),
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1643
1732
|
function persistResourceValues(resource, shouldPersist = false, equal) {
|
|
1644
1733
|
if (!shouldPersist)
|
|
1645
1734
|
return resource;
|
|
@@ -1860,10 +1949,16 @@ function injectQueryResourceOptions(injector) {
|
|
|
1860
1949
|
const PAUSED = Symbol('@mmstack/resource:paused');
|
|
1861
1950
|
function queryResource(request, options0) {
|
|
1862
1951
|
// Two-layer option injection: per-call > provideQueryResourceOptions > provideResourceOptions.
|
|
1952
|
+
const globalOpts = injectResourceOptions(options0?.injector);
|
|
1953
|
+
const queryOpts = injectQueryResourceOptions(options0?.injector);
|
|
1863
1954
|
const options = {
|
|
1864
|
-
...
|
|
1865
|
-
...
|
|
1955
|
+
...globalOpts,
|
|
1956
|
+
...queryOpts,
|
|
1866
1957
|
...options0,
|
|
1958
|
+
cache: mergeCacheOptions(queryOpts.cache, options0?.cache),
|
|
1959
|
+
circuitBreaker: mergeCircuitBreakerOptions(globalOpts.circuitBreaker, queryOpts.circuitBreaker, options0?.circuitBreaker),
|
|
1960
|
+
retry: mergeRetryOptions(globalOpts.retry, queryOpts.retry, options0?.retry),
|
|
1961
|
+
refresh: mergeRefreshOptions(queryOpts.refresh, options0?.refresh),
|
|
1867
1962
|
};
|
|
1868
1963
|
const cache = injectQueryCache(options?.injector);
|
|
1869
1964
|
const destroyRef = options?.injector
|
|
@@ -2346,10 +2441,14 @@ function injectMutationResourceOptions(injector) {
|
|
|
2346
2441
|
*/
|
|
2347
2442
|
function mutationResource(request, options0 = {}) {
|
|
2348
2443
|
// Two-layer option injection: per-call > provideMutationResourceOptions > provideResourceOptions.
|
|
2444
|
+
const globalOpts = injectResourceOptions(options0.injector);
|
|
2445
|
+
const mutOpts = injectMutationResourceOptions(options0.injector);
|
|
2349
2446
|
const options = {
|
|
2350
|
-
...
|
|
2351
|
-
...
|
|
2447
|
+
...globalOpts,
|
|
2448
|
+
...mutOpts,
|
|
2352
2449
|
...options0,
|
|
2450
|
+
circuitBreaker: mergeCircuitBreakerOptions(globalOpts.circuitBreaker, mutOpts.circuitBreaker, options0?.circuitBreaker),
|
|
2451
|
+
retry: mergeRetryOptions(globalOpts.retry, mutOpts.retry, options0?.retry),
|
|
2353
2452
|
};
|
|
2354
2453
|
// `register` is pulled out (and forced off on the inner query below) so the mutation ref is
|
|
2355
2454
|
// the only thing registered into the transition scope, not its internal query resource.
|
|
@@ -2532,5 +2631,5 @@ function mutationResource(request, options0 = {}) {
|
|
|
2532
2631
|
* Generated bundle index. Do not edit.
|
|
2533
2632
|
*/
|
|
2534
2633
|
|
|
2535
|
-
export { Cache, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
2634
|
+
export { Cache, PAUSED, applyResourceRegistration, createCacheInterceptor, createCircuitBreaker, createDedupeRequestsInterceptor, hashRequest, infiniteQueryResource, injectQueryCache, injectResourceOptions, manualQueryResource, mutationResource, noDedupe, provideCircuitBreakerDefaultOptions, provideMutationResourceOptions, provideQueryCache, provideQueryResourceOptions, provideResourceOptions, provideTypedResourceOptions, queryResource };
|
|
2536
2635
|
//# sourceMappingURL=mmstack-resource.mjs.map
|