@warp-drive/core 5.9.0-beta.1 → 5.9.0-beta.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/dist/-private-BL9zXgJB.js +3530 -0
- package/dist/-private-BL9zXgJB.js.map +1 -0
- package/dist/{-private-DMzvF_Q6.js → -private-Cxa8cMBj.js} +2 -2
- package/dist/-private-Cxa8cMBj.js.map +1 -0
- package/dist/{unpkg/dev-deprecated/-private-DL4tfrv9.js → -private-xK1KgxZJ.js} +2 -2
- package/dist/{-private-b1g4dhl0.js.map → -private-xK1KgxZJ.js.map} +1 -1
- package/{declarations/concepts-LHsLJZMl.d.ts → dist/concepts-DFldVwEM.d.ts} +2 -2
- package/{declarations/concepts-LHsLJZMl.d.ts.map → dist/concepts-DFldVwEM.d.ts.map} +1 -1
- package/dist/configure.js +1 -1
- package/dist/graph/-private.d.ts +2 -0
- package/dist/graph/-private.js +46 -33
- package/dist/graph/-private.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/{declarations/internal-Cz-893zD.d.ts → dist/internal-DtWOpxrR.d.ts} +2763 -2271
- package/dist/internal-DtWOpxrR.d.ts.map +1 -0
- package/dist/reactive/-private.d.ts +2 -0
- package/dist/reactive/-private.js +1 -1
- package/dist/reactive.d.ts +2 -0
- package/dist/reactive.js +3 -3
- package/{declarations → dist}/record-D3QQcaIR.d.ts.map +1 -1
- package/dist/{request--vRFALbQ.js → request-z2NByNx0.js} +2 -2
- package/dist/request-z2NByNx0.js.map +1 -0
- package/dist/request.d.ts +2 -0
- package/dist/request.js +1 -1
- package/dist/signals/-leaked.d.ts +1060 -0
- package/dist/signals/-leaked.d.ts.map +1 -0
- package/dist/signals/-leaked.js +2 -2
- package/dist/{src-Dex_phWI.js → src-s5HHjglV.js} +192 -53
- package/dist/src-s5HHjglV.js.map +1 -0
- package/dist/store/-private.d.ts +2 -0
- package/dist/store/-private.js +1 -1
- package/dist/store-DNF9Rgoh.js.map +1 -1
- package/dist/store.d.ts +2 -0
- package/{declarations → dist}/types/-private.d.ts +1 -1
- package/{declarations → dist}/types/-private.d.ts.map +1 -1
- package/dist/types/-private.js +1 -1
- package/dist/types/cache.d.ts +2 -0
- package/dist/types/record.js.map +1 -1
- package/dist/types/request.d.ts +2 -0
- package/dist/types/request.js +1 -1
- package/dist/types/request.js.map +1 -1
- package/dist/types/runtime.js +1 -1
- package/dist/types/schema/concepts.d.ts +2 -0
- package/dist/types/schema/fields.js.map +1 -1
- package/dist/types/schema/schema-service.d.ts +2 -0
- package/dist/types/symbols.js +1 -1
- package/dist/types/symbols.js.map +1 -1
- package/{declarations → dist}/types.d.ts +1 -1
- package/dist/{-private-b1g4dhl0.js → unpkg/dev/-private-BGCYELwo.js} +2 -2
- package/dist/unpkg/{dev-deprecated/-private-DL4tfrv9.js.map → dev/-private-BGCYELwo.js.map} +1 -1
- package/dist/unpkg/{dev-deprecated/-private-2RfQ2761.js → dev/-private-DhiS6yOR.js} +2 -2
- package/dist/unpkg/dev/-private-DhiS6yOR.js.map +1 -0
- package/dist/unpkg/dev/-private-pNQae3qH.js +3519 -0
- package/dist/unpkg/dev/-private-pNQae3qH.js.map +1 -0
- package/dist/unpkg/dev/configure.js +1 -1
- package/dist/unpkg/dev/graph/-private.js +46 -33
- package/dist/unpkg/dev/graph/-private.js.map +1 -1
- package/dist/unpkg/dev/index.js +1 -1
- package/dist/unpkg/dev/reactive/-private.js +1 -1
- package/dist/unpkg/dev/reactive.js +3 -3
- package/dist/unpkg/{dev-deprecated/request-DAuXbfYi.js → dev/request-BbbzRou7.js} +2 -2
- package/dist/unpkg/dev/request-BbbzRou7.js.map +1 -0
- package/dist/unpkg/dev/request.js +1 -1
- package/dist/unpkg/dev/{runtime-EoVKAhTv.js → runtime-DoDtzXJb.js} +2 -2
- package/dist/unpkg/dev/runtime-DoDtzXJb.js.map +1 -0
- package/dist/unpkg/dev/signals/-leaked.js +2 -2
- package/dist/unpkg/dev/{src-Bxlr_vue.js → src-Cf7NXXR2.js} +194 -55
- package/dist/unpkg/dev/src-Cf7NXXR2.js.map +1 -0
- package/dist/unpkg/dev/store/-private.js +1 -1
- package/dist/unpkg/{dev-deprecated/store-TcP2H4Af.js → dev/store-DamE3C4y.js} +2 -2
- package/dist/unpkg/dev/store-DamE3C4y.js.map +1 -0
- package/dist/unpkg/dev/store.js +1 -1
- package/dist/unpkg/dev/types/-private.js +1 -1
- package/dist/unpkg/dev/types/record.js.map +1 -1
- package/dist/unpkg/dev/types/request.js +1 -1
- package/dist/unpkg/dev/types/request.js.map +1 -1
- package/dist/unpkg/dev/types/runtime.js +1 -1
- package/dist/unpkg/dev/types/schema/fields.js.map +1 -1
- package/dist/unpkg/dev/types/symbols.js +1 -1
- package/dist/unpkg/dev/types/symbols.js.map +1 -1
- package/dist/unpkg/{dev/-private-DL4tfrv9.js → dev-deprecated/-private-BGCYELwo.js} +2 -2
- package/dist/unpkg/{prod/-private-Z9i0icpE.js.map → dev-deprecated/-private-BGCYELwo.js.map} +1 -1
- package/dist/unpkg/{dev/-private-2RfQ2761.js → dev-deprecated/-private-DhiS6yOR.js} +2 -2
- package/dist/unpkg/dev-deprecated/-private-DhiS6yOR.js.map +1 -0
- package/dist/unpkg/dev-deprecated/-private-pNQae3qH.js +3519 -0
- package/dist/unpkg/dev-deprecated/-private-pNQae3qH.js.map +1 -0
- package/dist/unpkg/dev-deprecated/configure.js +1 -1
- package/dist/unpkg/dev-deprecated/graph/-private.js +47 -34
- package/dist/unpkg/dev-deprecated/graph/-private.js.map +1 -1
- package/dist/unpkg/dev-deprecated/index.js +1 -1
- package/dist/unpkg/dev-deprecated/reactive/-private.js +1 -1
- package/dist/unpkg/dev-deprecated/reactive.js +3 -3
- package/dist/unpkg/{dev/request-DAuXbfYi.js → dev-deprecated/request-BbbzRou7.js} +2 -2
- package/dist/unpkg/dev-deprecated/request-BbbzRou7.js.map +1 -0
- package/dist/unpkg/dev-deprecated/request.js +1 -1
- package/dist/unpkg/dev-deprecated/{runtime-BacZMq1r.js → runtime-CPL2BGgT.js} +2 -2
- package/dist/unpkg/dev-deprecated/runtime-CPL2BGgT.js.map +1 -0
- package/dist/unpkg/dev-deprecated/signals/-leaked.js +2 -2
- package/dist/unpkg/dev-deprecated/{src-DEl2Ca3T.js → src-CSuFUXv4.js} +195 -56
- package/dist/unpkg/dev-deprecated/src-CSuFUXv4.js.map +1 -0
- package/dist/unpkg/dev-deprecated/store/-private.js +1 -1
- package/dist/unpkg/{dev/store-DmiFvT1B.js → dev-deprecated/store-Bsdz5mRe.js} +2 -2
- package/dist/unpkg/dev-deprecated/store-Bsdz5mRe.js.map +1 -0
- package/dist/unpkg/dev-deprecated/store.js +1 -1
- package/dist/unpkg/dev-deprecated/types/-private.js +1 -1
- package/dist/unpkg/dev-deprecated/types/record.js.map +1 -1
- package/dist/unpkg/dev-deprecated/types/request.js +1 -1
- package/dist/unpkg/dev-deprecated/types/request.js.map +1 -1
- package/dist/unpkg/dev-deprecated/types/runtime.js +1 -1
- package/dist/unpkg/dev-deprecated/types/schema/fields.js.map +1 -1
- package/dist/unpkg/dev-deprecated/types/symbols.js +1 -1
- package/dist/unpkg/dev-deprecated/types/symbols.js.map +1 -1
- package/dist/unpkg/prod/-private-8gd8hbwm.js +22 -0
- package/dist/unpkg/{prod-deprecated/-private-Z9i0icpE.js.map → prod/-private-8gd8hbwm.js.map} +1 -1
- package/dist/unpkg/prod/{-private-BK71-uXR.js → -private-B6aLbrgV.js} +2 -2
- package/dist/unpkg/prod/-private-B6aLbrgV.js.map +1 -0
- package/dist/unpkg/prod/-private-ggVX_Iob.js +3294 -0
- package/dist/unpkg/prod/-private-ggVX_Iob.js.map +1 -0
- package/dist/unpkg/prod/configure.js +1 -1
- package/dist/unpkg/prod/graph/-private.js +45 -32
- package/dist/unpkg/prod/graph/-private.js.map +1 -1
- package/dist/unpkg/prod/index.js +1 -1
- package/dist/unpkg/prod/reactive/-private.js +1 -1
- package/dist/unpkg/prod/reactive.js +3 -3
- package/dist/unpkg/prod/{request-BcJNzSgv.js → request-BoeppjDj.js} +2 -2
- package/dist/unpkg/prod/request-BoeppjDj.js.map +1 -0
- package/dist/unpkg/prod/request.js +1 -1
- package/dist/unpkg/prod/signals/-leaked.js +2 -2
- package/dist/unpkg/prod/{src-Dzz-j6pp.js → src-C0wuASrN.js} +196 -53
- package/dist/unpkg/prod/src-C0wuASrN.js.map +1 -0
- package/dist/unpkg/prod/store/-private.js +1 -1
- package/dist/unpkg/prod/store-BWhmb7Ob.js.map +1 -1
- package/dist/unpkg/prod/types/-private.js +1 -1
- package/dist/unpkg/prod/types/record.js.map +1 -1
- package/dist/unpkg/prod/types/request.js +1 -1
- package/dist/unpkg/prod/types/request.js.map +1 -1
- package/dist/unpkg/prod/types/runtime.js +1 -1
- package/dist/unpkg/prod/types/schema/fields.js.map +1 -1
- package/dist/unpkg/prod/types/symbols.js +1 -1
- package/dist/unpkg/prod/types/symbols.js.map +1 -1
- package/dist/unpkg/prod-deprecated/{-private-Z9i0icpE.js → -private-8gd8hbwm.js} +2 -2
- package/dist/unpkg/{dev/-private-DL4tfrv9.js.map → prod-deprecated/-private-8gd8hbwm.js.map} +1 -1
- package/dist/unpkg/prod-deprecated/{-private-BK71-uXR.js → -private-B6aLbrgV.js} +2 -2
- package/dist/unpkg/prod-deprecated/-private-B6aLbrgV.js.map +1 -0
- package/dist/unpkg/prod-deprecated/-private-ggVX_Iob.js +3294 -0
- package/dist/unpkg/prod-deprecated/-private-ggVX_Iob.js.map +1 -0
- package/dist/unpkg/prod-deprecated/configure.js +1 -1
- package/dist/unpkg/prod-deprecated/graph/-private.js +46 -35
- package/dist/unpkg/prod-deprecated/graph/-private.js.map +1 -1
- package/dist/unpkg/prod-deprecated/index.js +1 -1
- package/dist/unpkg/prod-deprecated/reactive/-private.js +1 -1
- package/dist/unpkg/prod-deprecated/reactive.js +3 -3
- package/dist/unpkg/prod-deprecated/{request-BcJNzSgv.js → request-BoeppjDj.js} +2 -2
- package/dist/unpkg/prod-deprecated/request-BoeppjDj.js.map +1 -0
- package/dist/unpkg/prod-deprecated/request.js +1 -1
- package/dist/unpkg/prod-deprecated/signals/-leaked.js +2 -2
- package/dist/unpkg/prod-deprecated/{src-BOifHFQ5.js → src-BXOgNqmz.js} +197 -54
- package/dist/unpkg/prod-deprecated/src-BXOgNqmz.js.map +1 -0
- package/dist/unpkg/prod-deprecated/store/-private.js +1 -1
- package/dist/unpkg/prod-deprecated/store-BWhmb7Ob.js.map +1 -1
- package/dist/unpkg/prod-deprecated/types/-private.js +1 -1
- package/dist/unpkg/prod-deprecated/types/record.js.map +1 -1
- package/dist/unpkg/prod-deprecated/types/request.js +1 -1
- package/dist/unpkg/prod-deprecated/types/request.js.map +1 -1
- package/dist/unpkg/prod-deprecated/types/runtime.js +1 -1
- package/dist/unpkg/prod-deprecated/types/schema/fields.js.map +1 -1
- package/dist/unpkg/prod-deprecated/types/symbols.js +1 -1
- package/dist/unpkg/prod-deprecated/types/symbols.js.map +1 -1
- package/package.json +15 -19
- package/declarations/graph/-private.d.ts +0 -2
- package/declarations/index.d.ts +0 -2
- package/declarations/internal-Cz-893zD.d.ts.map +0 -1
- package/declarations/reactive/-private.d.ts +0 -2
- package/declarations/reactive.d.ts +0 -2
- package/declarations/request.d.ts +0 -2
- package/declarations/signals/-leaked.d.ts +0 -63
- package/declarations/signals/-leaked.d.ts.map +0 -1
- package/declarations/store/-private.d.ts +0 -2
- package/declarations/store.d.ts +0 -8358
- package/declarations/store.d.ts.map +0 -1
- package/declarations/types/cache.d.ts +0 -2
- package/declarations/types/request.d.ts +0 -2
- package/declarations/types/schema/concepts.d.ts +0 -2
- package/declarations/types/schema/schema-service.d.ts +0 -2
- package/dist/-private-DMzvF_Q6.js.map +0 -1
- package/dist/-private-HjaQ1wp1.js +0 -1695
- package/dist/-private-HjaQ1wp1.js.map +0 -1
- package/dist/request--vRFALbQ.js.map +0 -1
- package/dist/src-Dex_phWI.js.map +0 -1
- package/dist/unpkg/dev/-private-2RfQ2761.js.map +0 -1
- package/dist/unpkg/dev/-private-CM1zxNws.js +0 -1684
- package/dist/unpkg/dev/-private-CM1zxNws.js.map +0 -1
- package/dist/unpkg/dev/request-DAuXbfYi.js.map +0 -1
- package/dist/unpkg/dev/runtime-EoVKAhTv.js.map +0 -1
- package/dist/unpkg/dev/src-Bxlr_vue.js.map +0 -1
- package/dist/unpkg/dev/store-DmiFvT1B.js.map +0 -1
- package/dist/unpkg/dev-deprecated/-private-2RfQ2761.js.map +0 -1
- package/dist/unpkg/dev-deprecated/-private-CM1zxNws.js +0 -1684
- package/dist/unpkg/dev-deprecated/-private-CM1zxNws.js.map +0 -1
- package/dist/unpkg/dev-deprecated/request-DAuXbfYi.js.map +0 -1
- package/dist/unpkg/dev-deprecated/runtime-BacZMq1r.js.map +0 -1
- package/dist/unpkg/dev-deprecated/src-DEl2Ca3T.js.map +0 -1
- package/dist/unpkg/dev-deprecated/store-TcP2H4Af.js.map +0 -1
- package/dist/unpkg/prod/-private-BK71-uXR.js.map +0 -1
- package/dist/unpkg/prod/-private-TNaS5Piv.js +0 -1494
- package/dist/unpkg/prod/-private-TNaS5Piv.js.map +0 -1
- package/dist/unpkg/prod/-private-Z9i0icpE.js +0 -22
- package/dist/unpkg/prod/request-BcJNzSgv.js.map +0 -1
- package/dist/unpkg/prod/src-Dzz-j6pp.js.map +0 -1
- package/dist/unpkg/prod-deprecated/-private-BK71-uXR.js.map +0 -1
- package/dist/unpkg/prod-deprecated/-private-TNaS5Piv.js +0 -1494
- package/dist/unpkg/prod-deprecated/-private-TNaS5Piv.js.map +0 -1
- package/dist/unpkg/prod-deprecated/request-BcJNzSgv.js.map +0 -1
- package/dist/unpkg/prod-deprecated/src-BOifHFQ5.js.map +0 -1
- /package/{declarations → dist}/aliases-BWYW5EhX.d.ts +0 -0
- /package/{declarations → dist}/aliases-BWYW5EhX.d.ts.map +0 -0
- /package/{declarations → dist}/build-config/babel-macros.d.ts +0 -0
- /package/{declarations → dist}/build-config/canary-features.d.ts +0 -0
- /package/{declarations → dist}/build-config/debugging.d.ts +0 -0
- /package/{declarations → dist}/build-config/deprecations.d.ts +0 -0
- /package/{declarations → dist}/build-config/env.d.ts +0 -0
- /package/{declarations → dist}/build-config/macros.d.ts +0 -0
- /package/{declarations → dist}/build-config.d.ts +0 -0
- /package/{declarations → dist}/change-C7kqv2kW.d.ts +0 -0
- /package/{declarations → dist}/change-C7kqv2kW.d.ts.map +0 -0
- /package/{declarations → dist}/configure-B_F639tN.d.ts +0 -0
- /package/{declarations → dist}/configure-B_F639tN.d.ts.map +0 -0
- /package/{declarations → dist}/configure.d.ts +0 -0
- /package/{declarations → dist}/document-BEn91SwT.d.ts +0 -0
- /package/{declarations → dist}/document-BEn91SwT.d.ts.map +0 -0
- /package/{declarations → dist}/error-50OSEhsF.d.ts +0 -0
- /package/{declarations → dist}/error-50OSEhsF.d.ts.map +0 -0
- /package/{declarations → dist}/fields-FM7peCiM.d.ts +0 -0
- /package/{declarations → dist}/fields-FM7peCiM.d.ts.map +0 -0
- /package/{declarations → dist}/graph-DLqYXP2z.d.ts +0 -0
- /package/{declarations → dist}/graph-DLqYXP2z.d.ts.map +0 -0
- /package/{declarations → dist}/identifier-DQnqOSJK.d.ts +0 -0
- /package/{declarations → dist}/identifier-DQnqOSJK.d.ts.map +0 -0
- /package/{declarations → dist}/json-api-raw-C5APJHHB.d.ts +0 -0
- /package/{declarations → dist}/json-api-raw-C5APJHHB.d.ts.map +0 -0
- /package/{declarations → dist}/mutations-CqtoGB4t.d.ts +0 -0
- /package/{declarations → dist}/mutations-CqtoGB4t.d.ts.map +0 -0
- /package/{declarations → dist}/operations-D1qA6r0_.d.ts +0 -0
- /package/{declarations → dist}/operations-D1qA6r0_.d.ts.map +0 -0
- /package/{declarations → dist}/params-DrEx3bf8.d.ts +0 -0
- /package/{declarations → dist}/params-DrEx3bf8.d.ts.map +0 -0
- /package/{declarations → dist}/raw-D5hnjiq7.d.ts +0 -0
- /package/{declarations → dist}/raw-D5hnjiq7.d.ts.map +0 -0
- /package/{declarations → dist}/record-D3QQcaIR.d.ts +0 -0
- /package/{declarations → dist}/relationship-CmHzMPKf.d.ts +0 -0
- /package/{declarations → dist}/relationship-CmHzMPKf.d.ts.map +0 -0
- /package/{declarations → dist}/symbols-DjRDCeX0.d.ts +0 -0
- /package/{declarations → dist}/symbols-DjRDCeX0.d.ts.map +0 -0
- /package/{declarations → dist}/types/cache/aliases.d.ts +0 -0
- /package/{declarations → dist}/types/cache/change.d.ts +0 -0
- /package/{declarations → dist}/types/cache/mutations.d.ts +0 -0
- /package/{declarations → dist}/types/cache/operations.d.ts +0 -0
- /package/{declarations → dist}/types/cache/relationship.d.ts +0 -0
- /package/{declarations → dist}/types/graph.d.ts +0 -0
- /package/{declarations → dist}/types/identifier.d.ts +0 -0
- /package/{declarations → dist}/types/json/raw.d.ts +0 -0
- /package/{declarations → dist}/types/params.d.ts +0 -0
- /package/{declarations → dist}/types/record.d.ts +0 -0
- /package/{declarations → dist}/types/runtime.d.ts +0 -0
- /package/{declarations → dist}/types/runtime.d.ts.map +0 -0
- /package/{declarations → dist}/types/schema/fields.d.ts +0 -0
- /package/{declarations → dist}/types/schema/fields.type-test.d.ts +0 -0
- /package/{declarations → dist}/types/spec/document.d.ts +0 -0
- /package/{declarations → dist}/types/spec/error.d.ts +0 -0
- /package/{declarations → dist}/types/spec/json-api-raw.d.ts +0 -0
- /package/{declarations → dist}/types/symbols.d.ts +0 -0
- /package/{declarations → dist}/types/utils.d.ts +0 -0
- /package/{declarations → dist}/utils/string.d.ts +0 -0
- /package/{declarations → dist}/utils/string.d.ts.map +0 -0
- /package/{declarations → dist}/utils-BtURiy8l.d.ts +0 -0
- /package/{declarations → dist}/utils-BtURiy8l.d.ts.map +0 -0
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as coerceId, C as isResourceKey, F as setRecordIdentifier, I as storeFor, L as assertPrivateCapabilities, M as StoreMap, N as _clearCaches, P as recordIdentifierFor, S as isRequestKey, _ as Store, b as RecordArrayManager, f as log, g as CacheHandler, h as constructResource, j as ensureStringId, k as normalizeModelName, m as createLegacyManyArray, p as logGroup, v as assertPrivateStore, x as fastPush, y as isPrivateStore } from "../src-
|
|
1
|
+
import { A as coerceId, C as isResourceKey, F as setRecordIdentifier, I as storeFor, L as assertPrivateCapabilities, M as StoreMap, N as _clearCaches, P as recordIdentifierFor, S as isRequestKey, _ as Store, b as RecordArrayManager, f as log, g as CacheHandler, h as constructResource, j as ensureStringId, k as normalizeModelName, m as createLegacyManyArray, p as logGroup, v as assertPrivateStore, x as fastPush, y as isPrivateStore } from "../src-C0wuASrN.js";
|
|
2
2
|
|
|
3
3
|
export { CacheHandler, RecordArrayManager, Store, StoreMap, _clearCaches, normalizeModelName as _deprecatingNormalize, assertPrivateCapabilities, assertPrivateStore, coerceId, constructResource, createLegacyManyArray, ensureStringId, fastPush, isPrivateStore, isRequestKey, isResourceKey, log, logGroup, recordIdentifierFor, setRecordIdentifier, storeFor };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-BWhmb7Ob.js","names":["LRUCache","NUMERIC_KEYS","Set","parseCacheControl","header","CACHE_CONTROL_CACHE","get","key","value","isParsingKey","cacheControlValue","i","length","char","charAt","has","parseCacheControlValue","stringToParse","parsedValue","Number","parseInt","isNaN","isExpired","cacheKey","request","config","constraints","result","headers","response","now","Date","date","xWarpDriveExpires","expirationTime","getTime","cacheControl","age","maxAge","ageValue","dateValue","Expires","expires","apiCacheHardExpires","time","deadline","DefaultCachePolicy","_getStore","store","set","_stores","invalidated","types","Map","constructor","WeakMap","_config","arguments","console","warn","invalidateRequest","add","invalidateRequestsForType","type","storeCache","notifications","forEach","id","notify","didRequest","op","statusNumber","status","records","map","r","additionalTypes","cacheOptions","delete","isHardExpired","cache","cached","peekRequest","isSoftExpired","apiCacheSoftExpires"],"sources":["../../../src/store/-private/default-cache-policy.ts"],"sourcesContent":["import { deprecate } from '@ember/debug';\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { CacheHandler, Fetch } from '@warp-drive/core';\nimport { LOG_CACHE_POLICY } from '@warp-drive/core/build-config/debugging';\nimport { TESTING } from '@warp-drive/core/build-config/env';\nimport { assert } from '@warp-drive/core/build-config/macros';\nimport type { Cache } from '@warp-drive/core/types/cache';\nimport type { RequestKey, ResourceKey } from '@warp-drive/core/types/identifier';\nimport type {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n CacheOptions,\n ImmutableRequestInfo,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n RequestInfo,\n ResponseInfo,\n StructuredDocument,\n} from '@warp-drive/core/types/request';\nimport type { ResourceDocument } from '@warp-drive/core/types/spec/document';\n\nimport { LRUCache } from '../../utils/string';\nimport type { CachePolicy } from '../-private';\n\ntype UnsubscribeToken = object;\ntype CacheOperation = 'added' | 'removed' | 'updated' | 'state';\ntype DocumentCacheOperation = 'invalidated' | 'added' | 'removed' | 'updated' | 'state';\n\nexport interface NotificationCallback {\n (resourceKey: ResourceKey, notificationType: 'attributes' | 'relationships', key?: string): void;\n (resourceKey: ResourceKey, notificationType: 'errors' | 'meta' | 'identity' | 'state'): void;\n // (resourceKey: ResourceKey, notificationType: NotificationType, key?: string): void;\n}\n\ninterface ResourceOperationCallback {\n // resource updates\n (resourceKey: ResourceKey, notificationType: CacheOperation): void;\n}\n\ninterface DocumentOperationCallback {\n // document updates\n (cacheKey: RequestKey, notificationType: DocumentCacheOperation): void;\n}\n\ntype NotificationManager = {\n subscribe(resourceKey: ResourceKey, callback: NotificationCallback): UnsubscribeToken;\n subscribe(cacheKey: 'resource', callback: ResourceOperationCallback): UnsubscribeToken;\n subscribe(cacheKey: 'document' | RequestKey, callback: DocumentOperationCallback): UnsubscribeToken;\n\n notify(cacheKey: ResourceKey, value: 'attributes' | 'relationships', key?: string): boolean;\n notify(cacheKey: ResourceKey, value: 'errors' | 'meta' | 'identity' | 'state'): boolean;\n notify(cacheKey: ResourceKey, value: CacheOperation): boolean;\n notify(cacheKey: RequestKey, value: DocumentCacheOperation): boolean;\n};\n\ntype Store = {\n cache: Cache;\n notifications: NotificationManager;\n};\n\n/**\n * Interface of a parsed Cache-Control header value.\n *\n * - [MDN Cache-Control Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control)\n */\nexport interface CacheControlValue {\n /** Indicates the response will never change; parsed but not currently used by this cache policy's expiration logic. */\n immutable?: boolean;\n /** Seconds since the response's `Date` that it is considered fresh; combined with the `Age` header to determine expiration. */\n 'max-age'?: number;\n /** Indicates a stale response must be revalidated before use; parsed but not currently used by this cache policy's expiration logic. */\n 'must-revalidate'?: boolean;\n /** Indicates the client must understand the response's status code semantics before caching; parsed but not currently used by this cache policy's expiration logic. */\n 'must-understand'?: boolean;\n /** Indicates the response must be revalidated before being reused from cache; parsed but not currently used by this cache policy's expiration logic. */\n 'no-cache'?: boolean;\n /** Indicates the response must not be stored in any cache; parsed but not currently used by this cache policy's expiration logic. */\n 'no-store'?: boolean;\n /** Indicates the response must not be transformed by intermediaries; parsed but not currently used by this cache policy's expiration logic. */\n 'no-transform'?: boolean;\n /** Indicates only an already-cached response should be used; parsed but not currently used by this cache policy's expiration logic. */\n 'only-if-cached'?: boolean;\n /** Indicates the response is intended for a single user and should not be stored by shared caches; parsed but not currently used by this cache policy's expiration logic. */\n private?: boolean;\n /** Like `must-revalidate` but only for shared caches; parsed but not currently used by this cache policy's expiration logic. */\n 'proxy-revalidate'?: boolean;\n /** Indicates the response may be stored by any cache; parsed but not currently used by this cache policy's expiration logic. */\n public?: boolean;\n /** Seconds since the response's `Date` that it is considered fresh for shared caches; used as a fallback for `max-age` when determining expiration. */\n 's-maxage'?: number;\n /** Seconds a stale response may be reused if an error occurs while revalidating; parsed but not currently used by this cache policy's expiration logic. */\n 'stale-if-error'?: number;\n /** Seconds a stale response may be reused while a revalidation happens in the background; parsed but not currently used by this cache policy's expiration logic. */\n 'stale-while-revalidate'?: number;\n}\n\ntype CacheControlKey = keyof CacheControlValue;\n\nconst NUMERIC_KEYS = new Set(['max-age', 's-maxage', 'stale-if-error', 'stale-while-revalidate']);\n\n/**\n * Parses a string Cache-Control header value into an object with the following structure:\n *\n * ```ts\n * interface CacheControlValue {\n * immutable?: boolean;\n * 'max-age'?: number;\n * 'must-revalidate'?: boolean;\n * 'must-understand'?: boolean;\n * 'no-cache'?: boolean;\n * 'no-store'?: boolean;\n * 'no-transform'?: boolean;\n * 'only-if-cached'?: boolean;\n * private?: boolean;\n * 'proxy-revalidate'?: boolean;\n * public?: boolean;\n * 's-maxage'?: number;\n * 'stale-if-error'?: number;\n * 'stale-while-revalidate'?: number;\n * }\n * ```\n *\n * See also {@link CacheControlValue} and [Response Directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#response_directives)\n *\n * @public\n */\nexport function parseCacheControl(header: string): CacheControlValue {\n return CACHE_CONTROL_CACHE.get(header);\n}\n\nconst CACHE_CONTROL_CACHE = new LRUCache((header: string) => {\n let key: CacheControlKey = '' as CacheControlKey;\n let value = '';\n let isParsingKey = true;\n const cacheControlValue: CacheControlValue = {};\n\n for (let i = 0; i < header.length; i++) {\n const char = header.charAt(i);\n if (char === ',') {\n assert(`Invalid Cache-Control value, expected a value`, !isParsingKey || !NUMERIC_KEYS.has(key));\n assert(\n `Invalid Cache-Control value, expected a value after \"=\" but got \",\"`,\n i === 0 || header.charAt(i - 1) !== '='\n );\n isParsingKey = true;\n // @ts-expect-error TS incorrectly thinks that optional keys must have a type that includes undefined\n cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true;\n key = '' as CacheControlKey;\n value = '';\n continue;\n } else if (char === '=') {\n assert(`Invalid Cache-Control value, expected a value after \"=\"`, i + 1 !== header.length);\n isParsingKey = false;\n } else if (char === ' ' || char === `\\t` || char === `\\n`) {\n continue;\n } else if (isParsingKey) {\n key += char;\n } else {\n value += char;\n }\n\n if (i === header.length - 1) {\n // @ts-expect-error TS incorrectly thinks that optional keys must have a type that includes undefined\n cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true;\n }\n }\n\n return cacheControlValue;\n}, 200);\n\nfunction parseCacheControlValue(stringToParse: string): number {\n const parsedValue = Number.parseInt(stringToParse);\n assert(`Invalid Cache-Control value, expected a number but got - ${stringToParse}`, !Number.isNaN(parsedValue));\n assert(`Invalid Cache-Control value, expected a number greater than 0 but got - ${stringToParse}`, parsedValue >= 0);\n if (Number.isNaN(parsedValue) || parsedValue < 0) {\n return 0;\n }\n\n return parsedValue;\n}\n\nfunction isExpired(cacheKey: RequestKey, request: StructuredDocument<ResourceDocument>, config: PolicyConfig): boolean {\n const { constraints } = config;\n\n if (constraints?.isExpired) {\n const result = constraints.isExpired(request);\n if (result !== null) {\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because constraints.isExpired returned ${result}`\n );\n }\n return result;\n }\n }\n\n const { headers } = request.response!;\n\n if (!headers) {\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is EXPIRED because no headers were provided`);\n }\n\n // if we have no headers then both the headers based expiration\n // and the time based expiration will be considered expired\n return true;\n }\n\n // check for X-WarpDrive-Expires\n const now = Date.now();\n const date = headers.get('Date');\n\n if (constraints?.headers) {\n if (constraints.headers['X-WarpDrive-Expires']) {\n const xWarpDriveExpires = headers.get('X-WarpDrive-Expires');\n if (xWarpDriveExpires) {\n const expirationTime = new Date(xWarpDriveExpires).getTime();\n const result = now >= expirationTime;\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the time set by X-WarpDrive-Expires header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n return result;\n }\n }\n\n // check for Cache-Control\n if (constraints.headers['Cache-Control']) {\n const cacheControl = headers.get('Cache-Control');\n const age = headers.get('Age');\n\n if (cacheControl && age && date) {\n const cacheControlValue = parseCacheControl(cacheControl);\n\n // max-age and s-maxage are stored in\n const maxAge = cacheControlValue['max-age'] || cacheControlValue['s-maxage'];\n\n if (maxAge) {\n // age is stored in seconds\n const ageValue = parseInt(age, 10);\n assert(`Invalid Cache-Control value, expected a number but got - ${age}`, !Number.isNaN(ageValue));\n assert(`Invalid Cache-Control value, expected a number greater than 0 but got - ${age}`, ageValue >= 0);\n\n if (!Number.isNaN(ageValue) && ageValue >= 0) {\n const dateValue = new Date(date).getTime();\n const expirationTime = dateValue + (maxAge - ageValue) * 1000;\n const result = now >= expirationTime;\n\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the time set by Cache-Control header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n\n return result;\n }\n }\n }\n }\n\n // check for Expires\n if (constraints.headers.Expires) {\n const expires = headers.get('Expires');\n if (expires) {\n const expirationTime = new Date(expires).getTime();\n const result = now >= expirationTime;\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the time set by Expires header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n return result;\n }\n }\n }\n\n // check for Date\n if (!date) {\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is EXPIRED because no Date header was provided`);\n }\n return true;\n }\n\n let expirationTime = config.apiCacheHardExpires;\n if (TESTING) {\n if (!config.disableTestOptimization) {\n expirationTime = config.apiCacheSoftExpires;\n }\n }\n\n const time = new Date(date).getTime();\n const deadline = time + expirationTime;\n const result = now >= deadline;\n\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the apiCacheHardExpires time since the response's Date header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n\n return result;\n}\n\n/**\n * The constraint options for {@link PolicyConfig.constraints}\n */\nexport interface PolicyConfigConstraints {\n /**\n * Headers that should be checked for expiration.\n *\n */\n headers?: {\n /**\n * Whether the `Cache-Control` header should be checked for expiration.\n * If `true`, then the `max-age` and `s-maxage` directives are used alongside\n * the `Age` and `Date` headers to determine if the expiration time has passed.\n *\n * Other directives are ignored.\n *\n * 'Cache-Control' will take precedence over 'Expires' if both are present\n * and both configured to be checked.\n *\n */\n 'Cache-Control'?: boolean;\n\n /**\n * Whether the `Expires` header should be checked for expiration.\n *\n * If `true`, then the `Expires` header is used to caclulate the expiration time\n * and determine if the expiration time has passed.\n *\n * 'Cache-Control' will take precedence over 'Expires' if both are present.\n *\n */\n Expires?: boolean;\n\n /**\n * Whether the `X-WarpDrive-Expires` header should be checked for expiration.\n *\n * If `true`, then the `X-WarpDrive-Expires` header is used to caclulate the expiration time\n * and determine if the expiration time has passed.\n *\n * This header will take precedence over 'Cache-Control' and 'Expires' if all three are present.\n *\n * The header's value should be a [UTC date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString).\n *\n */\n 'X-WarpDrive-Expires'?: boolean;\n };\n\n /**\n * A function that should be called to determine if the request is expired.\n *\n * If present, this function will be called with the request and should return\n * `true` if the request is expired, `false` if it is not expired, and\n * `null` if the expiration status is unknown.\n *\n * If the function does not return `null`,\n *\n */\n isExpired?: (request: StructuredDocument<ResourceDocument>) => boolean | null;\n}\n\n/**\n * The configuration options for the {@link DefaultCachePolicy}\n *\n * ```ts [app/services/store.ts]\n * import { Store } from '@warp-drive/core';\n * import { DefaultCachePolicy } from '@warp-drive/core/store'; // [!code focus]\n *\n * export default class AppStore extends Store {\n * lifetimes = new DefaultCachePolicy({ // [!code focus:3]\n * // ... PolicyConfig Settings ... //\n * });\n * }\n * ```\n *\n */\nexport interface PolicyConfig {\n /**\n * the number of milliseconds after which a request is considered\n * stale. If a request is issued again after this time, the request\n * will respond from cache immediately while a background request\n * is made to update the cache.\n *\n * This is calculated against the `date` header of the response.\n *\n * If your API does not provide a `date` header, the {@link Fetch} handler\n * will automatically add it to responses if it is not present. Responses\n * without a `date` header will be considered stale immediately.\n *\n */\n apiCacheSoftExpires: number;\n /**\n * the number of milliseconds after which a request is considered\n * expired and should be re-fetched. If a request is issued again\n * after this time, the request will disregard the cache and\n * wait for a fresh response from the API.\n *\n * This is calculated against the `date` header of the response.\n *\n * If your API does not provide a `date` header, the {@link Fetch} handler\n * will automatically add it to responses if it is not present. Responses\n * without a `date` header will be considered hard expired immediately.\n *\n */\n apiCacheHardExpires: number;\n /**\n * In Testing environments, the `apiCacheSoftExpires` will always be `false`\n * and `apiCacheHardExpires` will use the `apiCacheSoftExpires` value.\n *\n * This helps reduce flakiness and produce predictably rendered results in test suites.\n *\n * Requests that specifically set {@link RequestInfo.cacheOptions.backgroundReload | cacheOptions.backgroundReload }\n * will still be background reloaded in tests.\n *\n * This behavior can be opted out of by setting this value to `true`.\n *\n */\n disableTestOptimization?: boolean;\n\n /**\n * In addition to the simple time-based expiration strategy, CachePolicy\n * supports various common server-supplied expiration strategies via\n * headers, as well as custom expiration strategies via the {@link PolicyConfigConstraints.isExpired | isExpired}\n * function.\n *\n * Requests will be validated for expiration against these constraints.\n * If any of these constraints are not met, the request will be considered\n * expired. If all constraints are met, the request will be considered\n * valid and the time based expiration strategy will NOT be used.\n *\n * Meeting a constraint means BOTH that the properties the constraint\n * requires are present AND that the expiration time indicated by those\n * properties has not been exceeded.\n *\n * In other words, if the properties for a constraint are not present,\n * this does not count either as meeting or as not meeting the constraint,\n * the constraint simply does not apply.\n *\n * The `isExpired` function is called with the request and should return\n * `true` if the request is expired, `false` if it is not expired, and\n * `null` if the expiration status is unknown.\n *\n * In order constraints are checked:\n *\n * - isExpired function\n * - ↳ (if null) X-WarpDrive-Expires header\n * - ↳ (if null) Cache-Control header\n * - ↳ (if null) Expires header\n *\n * See {@link PolicyConfigConstraints} for configuration options.\n */\n constraints?: PolicyConfigConstraints;\n}\n\n/**\n * A basic {@link CachePolicy} that can be added to the Store service.\n *\n * ```ts [app/services/store.ts]\n * import { Store } from '@warp-drive/core';\n * import { DefaultCachePolicy } from '@warp-drive/core/store'; // [!code focus]\n *\n * export default class AppStore extends Store {\n * lifetimes = new DefaultCachePolicy({ // [!code focus:5]\n * apiCacheSoftExpires: 30_000,\n * apiCacheHardExpires: 60_000,\n * // ... Other PolicyConfig Settings ... //\n * });\n * }\n * ```\n *\n * :::tip 💡 TIP\n * Date headers do not have millisecond precision, so expiration times should\n * generally be larger than 1000ms.\n * :::\n *\n * See also {@link PolicyConfig} for configuration options.\n *\n * ### The Mechanics\n *\n * This policy determines staleness based on various configurable constraints falling back to a simple\n * check of the time elapsed since the request was last received from the API using the `date` header\n * from the last response.\n *\n * :::tip 💡 TIP\n * The {@link Fetch} handler provided by `@warp-drive/core` will automatically\n * add the `date` header to responses if it is not present.\n * :::\n *\n * - For manual override of reload see {@link CacheOptions.reload | cacheOptions.reload}\n * - For manual override of background reload see {@link CacheOptions.backgroundReload | cacheOptions.backgroundReload}\n *\n * In order expiration is determined by:\n *\n * ```md\n * Is explicitly invalidated by `cacheOptions.reload`\n * ↳ (if falsey) if the request has been explicitly invalidated\n * since the last request (see Automatic Invalidation below)\n * ↳ (if false) (If Active) isExpired function\n * ↳ (if null) (If Active) X-WarpDrive-Expires header\n * ↳ (if null) (If Active) Cache-Control header\n * ↳ (if null) (If Active) Expires header\n * ↳ (if null) Date header + apiCacheHardExpires < current time\n *\n * -- <if above is false, a background request is issued if> --\n *\n * ↳ is invalidated by `cacheOptions.backgroundReload`\n * ↳ (if falsey) Date header + apiCacheSoftExpires < current time\n * ```\n *\n * ### Automatic Invalidation / Entanglement\n *\n * It also invalidates any request with an {@link RequestInfo.op | OpCode} of `\"query\"`\n * for which {@link CacheOptions.types | cacheOptions.types} was provided\n * when a request with an `OpCode` of `\"createRecord\"` is successful and also includes\n * a matching type in its own `cacheOptions.types` array.\n\n * :::tip 💡 TIP\n * Abstracting this behavior via builders is recommended to ensure consistency.\n * :::\n *\n * ### Testing\n *\n * In Testing environments:\n *\n * - `apiCacheSoftExpires` will always be `false`\n * - `apiCacheHardExpires` will use the `apiCacheSoftExpires` value.\n *\n * This helps reduce flakiness and produce predictably rendered results in test suites.\n *\n * Requests that specifically set `cacheOptions.backgroundReload = true` will\n * still be background reloaded in tests.\n *\n * This behavior can be opted out of by setting `disableTestOptimization = true`\n * in the policy config.\n *\n * @public\n */\nexport class DefaultCachePolicy implements CachePolicy {\n /**\n * @internal\n */\n declare private config: PolicyConfig;\n /**\n * @internal\n */\n declare private _stores: WeakMap<Store, { invalidated: Set<RequestKey>; types: Map<string, Set<RequestKey>> }>;\n\n /**\n * @internal\n */\n private _getStore(store: Store): {\n invalidated: Set<RequestKey>;\n types: Map<string, Set<RequestKey>>;\n } {\n let set = this._stores.get(store);\n if (!set) {\n set = { invalidated: new Set(), types: new Map() };\n this._stores.set(store, set);\n }\n return set;\n }\n\n constructor(config: PolicyConfig) {\n this._stores = new WeakMap();\n\n const _config = arguments.length === 1 ? config : (arguments[1] as unknown as PolicyConfig);\n deprecate(\n `Passing a Store to the CachePolicy is deprecated, please pass only a config instead.`,\n arguments.length === 1,\n {\n id: 'ember-data:request-utils:lifetimes-service-store-arg',\n since: {\n enabled: '5.4',\n available: '4.13',\n },\n for: '@ember-data/request-utils',\n until: '6.0',\n }\n );\n assert(`You must pass a config to the CachePolicy`, _config);\n assert(`You must pass a apiCacheSoftExpires to the CachePolicy`, typeof _config.apiCacheSoftExpires === 'number');\n assert(`You must pass a apiCacheHardExpires to the CachePolicy`, typeof _config.apiCacheHardExpires === 'number');\n this.config = _config;\n }\n\n /**\n * Invalidate a request by its CacheKey for the given store instance.\n *\n * While the store argument may seem redundant, the CachePolicy\n * is designed to be shared across multiple stores / forks\n * of the store.\n *\n * ```ts\n * store.lifetimes.invalidateRequest(store, cacheKey);\n * ```\n *\n * @public\n */\n invalidateRequest(cacheKey: RequestKey, store: Store): void {\n this._getStore(store).invalidated.add(cacheKey);\n }\n\n /**\n * Invalidate all requests associated to a specific type\n * for a given store instance.\n *\n * While the store argument may seem redundant, the CachePolicy\n * is designed to be shared across multiple stores / forks\n * of the store.\n *\n * This invalidation is done automatically when using this service\n * for both the {@link CacheHandler} and the [NetworkHandler](/api/@warp-drive/legacy/compat/variables/LegacyNetworkHandler).\n *\n * ```ts\n * store.lifetimes.invalidateRequestsForType(store, 'person');\n * ```\n *\n * @public\n */\n invalidateRequestsForType(type: string, store: Store): void {\n const storeCache = this._getStore(store);\n const set = storeCache.types.get(type);\n const notifications = store.notifications;\n\n if (set) {\n // TODO batch notifications\n set.forEach((id) => {\n storeCache.invalidated.add(id);\n // @ts-expect-error\n notifications.notify(id, 'invalidated', null);\n });\n }\n }\n\n /**\n * Invoked when a request has been fulfilled from the configured request handlers.\n * This is invoked by the CacheHandler for both foreground and background requests\n * once the cache has been updated.\n *\n * Note, this is invoked by the {@link CacheHandler} regardless of whether\n * the request has a cache-key.\n *\n * This method should not be invoked directly by consumers.\n *\n * @public\n */\n didRequest(\n request: ImmutableRequestInfo,\n response: Response | ResponseInfo | null,\n cacheKey: RequestKey | null,\n store: Store\n ): void {\n // if this is a successful createRecord request, invalidate the cacheKey for the type\n if (request.op === 'createRecord') {\n const statusNumber = response?.status ?? 0;\n if (statusNumber >= 200 && statusNumber < 400) {\n const types = new Set(request.records?.map((r) => r.type));\n const additionalTypes = request.cacheOptions?.types;\n additionalTypes?.forEach((type) => {\n types.add(type);\n });\n\n types.forEach((type) => {\n this.invalidateRequestsForType(type, store);\n });\n }\n\n // add this document's cacheKey to a map for all associated types\n // it is recommended to only use this for queries\n } else if (cacheKey && request.cacheOptions?.types?.length) {\n const storeCache = this._getStore(store);\n request.cacheOptions?.types.forEach((type) => {\n const set = storeCache.types.get(type);\n if (set) {\n set.add(cacheKey);\n storeCache.invalidated.delete(cacheKey);\n } else {\n storeCache.types.set(type, new Set([cacheKey]));\n }\n });\n }\n }\n\n /**\n * Invoked to determine if the request may be fulfilled from cache\n * if possible.\n *\n * Note, this is only invoked by the {@link CacheHandler} if the request has\n * a cache-key.\n *\n * If no cache entry is found or the entry is hard expired,\n * the request will be fulfilled from the configured request handlers\n * and the cache will be updated before returning the response.\n *\n * @public\n * @return true if the request is considered hard expired\n */\n isHardExpired(cacheKey: RequestKey, store: Store): boolean {\n // if we are explicitly invalidated, we are hard expired\n const storeCache = this._getStore(store);\n if (storeCache.invalidated.has(cacheKey)) {\n return true;\n }\n const cache = store.cache;\n const cached = cache.peekRequest(cacheKey);\n\n if (!cached?.response) {\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is EXPIRED because no cache entry was found`);\n }\n return true;\n }\n\n return isExpired(cacheKey, cached, this.config);\n }\n\n /**\n * Invoked if `isHardExpired` is false to determine if the request\n * should be update behind the scenes if cache data is already available.\n *\n * Note, this is only invoked by the {@link CacheHandler} if the request has\n * a cache-key.\n *\n * If true, the request will be fulfilled from cache while a backgrounded\n * request is made to update the cache via the configured request handlers.\n *\n * @public\n * @return true if the request is considered soft expired\n */\n isSoftExpired(cacheKey: RequestKey, store: Store): boolean {\n if (TESTING) {\n if (!this.config.disableTestOptimization) {\n return false;\n }\n }\n const cache = store.cache;\n const cached = cache.peekRequest(cacheKey);\n\n if (cached?.response) {\n const date = cached.response.headers.get('date');\n\n if (!date) {\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is STALE because no date header was found`);\n }\n return true;\n } else {\n const time = new Date(date).getTime();\n const now = Date.now();\n const deadline = time + this.config.apiCacheSoftExpires;\n const result = now >= deadline;\n\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'STALE' : 'NOT stale'}. Expiration time: ${deadline}, now: ${now}`\n );\n }\n\n return result;\n }\n }\n\n if (LOG_CACHE_POLICY) {\n // eslint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is STALE because no cache entry was found`);\n }\n\n return true;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store-BWhmb7Ob.js","names":["LRUCache","NUMERIC_KEYS","Set","parseCacheControl","header","CACHE_CONTROL_CACHE","get","key","value","isParsingKey","cacheControlValue","i","length","char","charAt","has","parseCacheControlValue","stringToParse","parsedValue","Number","parseInt","isNaN","isExpired","cacheKey","request","config","constraints","result","headers","response","now","Date","date","xWarpDriveExpires","expirationTime","getTime","cacheControl","age","maxAge","ageValue","dateValue","Expires","expires","apiCacheHardExpires","time","deadline","DefaultCachePolicy","_getStore","store","set","_stores","invalidated","types","Map","constructor","WeakMap","_config","arguments","console","warn","invalidateRequest","add","invalidateRequestsForType","type","storeCache","notifications","forEach","id","notify","didRequest","op","statusNumber","status","records","map","r","additionalTypes","cacheOptions","delete","isHardExpired","cache","cached","peekRequest","isSoftExpired","apiCacheSoftExpires"],"sources":["../../../src/store/-private/default-cache-policy.ts"],"sourcesContent":["import { deprecate } from '@ember/debug';\n\nimport { LOG_CACHE_POLICY } from '@warp-drive/core/build-config/debugging';\nimport { TESTING } from '@warp-drive/core/build-config/env';\nimport { assert } from '@warp-drive/core/build-config/macros';\n\n// oxlint-disable-next-line no-unused-vars\nimport type { CacheHandler, CachePolicy } from '../-private';\n// oxlint-disable-next-line no-unused-vars\nimport type { Fetch } from '../../request/-private/fetch';\nimport type { Cache } from '../../types/cache';\nimport type { RequestKey, ResourceKey } from '../../types/identifier';\nimport type {\n // oxlint-disable-next-line no-unused-vars\n CacheOptions,\n ImmutableRequestInfo,\n // oxlint-disable-next-line no-unused-vars\n RequestInfo,\n ResponseInfo,\n StructuredDocument,\n} from '../../types/request';\nimport type { ResourceDocument } from '../../types/spec/document';\nimport { LRUCache } from '../../utils/string';\n\ntype UnsubscribeToken = object;\ntype CacheOperation = 'added' | 'removed' | 'updated' | 'state';\ntype DocumentCacheOperation = 'invalidated' | 'added' | 'removed' | 'updated' | 'state';\n\nexport interface NotificationCallback {\n (resourceKey: ResourceKey, notificationType: 'attributes' | 'relationships', key?: string): void;\n (resourceKey: ResourceKey, notificationType: 'errors' | 'meta' | 'identity' | 'state'): void;\n // (resourceKey: ResourceKey, notificationType: NotificationType, key?: string): void;\n}\n\ninterface ResourceOperationCallback {\n // resource updates\n (resourceKey: ResourceKey, notificationType: CacheOperation): void;\n}\n\ninterface DocumentOperationCallback {\n // document updates\n (cacheKey: RequestKey, notificationType: DocumentCacheOperation): void;\n}\n\ntype NotificationManager = {\n subscribe(resourceKey: ResourceKey, callback: NotificationCallback): UnsubscribeToken;\n subscribe(cacheKey: 'resource', callback: ResourceOperationCallback): UnsubscribeToken;\n subscribe(cacheKey: 'document' | RequestKey, callback: DocumentOperationCallback): UnsubscribeToken;\n\n notify(cacheKey: ResourceKey, value: 'attributes' | 'relationships', key?: string): boolean;\n notify(cacheKey: ResourceKey, value: 'errors' | 'meta' | 'identity' | 'state'): boolean;\n notify(cacheKey: ResourceKey, value: CacheOperation): boolean;\n notify(cacheKey: RequestKey, value: DocumentCacheOperation): boolean;\n};\n\ntype Store = {\n cache: Cache;\n notifications: NotificationManager;\n};\n\n/**\n * Interface of a parsed Cache-Control header value.\n *\n * - [MDN Cache-Control Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control)\n */\nexport interface CacheControlValue {\n /** Indicates the response will never change; parsed but not currently used by this cache policy's expiration logic. */\n immutable?: boolean;\n /** Seconds since the response's `Date` that it is considered fresh; combined with the `Age` header to determine expiration. */\n 'max-age'?: number;\n /** Indicates a stale response must be revalidated before use; parsed but not currently used by this cache policy's expiration logic. */\n 'must-revalidate'?: boolean;\n /** Indicates the client must understand the response's status code semantics before caching; parsed but not currently used by this cache policy's expiration logic. */\n 'must-understand'?: boolean;\n /** Indicates the response must be revalidated before being reused from cache; parsed but not currently used by this cache policy's expiration logic. */\n 'no-cache'?: boolean;\n /** Indicates the response must not be stored in any cache; parsed but not currently used by this cache policy's expiration logic. */\n 'no-store'?: boolean;\n /** Indicates the response must not be transformed by intermediaries; parsed but not currently used by this cache policy's expiration logic. */\n 'no-transform'?: boolean;\n /** Indicates only an already-cached response should be used; parsed but not currently used by this cache policy's expiration logic. */\n 'only-if-cached'?: boolean;\n /** Indicates the response is intended for a single user and should not be stored by shared caches; parsed but not currently used by this cache policy's expiration logic. */\n private?: boolean;\n /** Like `must-revalidate` but only for shared caches; parsed but not currently used by this cache policy's expiration logic. */\n 'proxy-revalidate'?: boolean;\n /** Indicates the response may be stored by any cache; parsed but not currently used by this cache policy's expiration logic. */\n public?: boolean;\n /** Seconds since the response's `Date` that it is considered fresh for shared caches; used as a fallback for `max-age` when determining expiration. */\n 's-maxage'?: number;\n /** Seconds a stale response may be reused if an error occurs while revalidating; parsed but not currently used by this cache policy's expiration logic. */\n 'stale-if-error'?: number;\n /** Seconds a stale response may be reused while a revalidation happens in the background; parsed but not currently used by this cache policy's expiration logic. */\n 'stale-while-revalidate'?: number;\n}\n\ntype CacheControlKey = keyof CacheControlValue;\n\nconst NUMERIC_KEYS = new Set(['max-age', 's-maxage', 'stale-if-error', 'stale-while-revalidate']);\n\n/**\n * Parses a string Cache-Control header value into an object with the following structure:\n *\n * ```ts\n * interface CacheControlValue {\n * immutable?: boolean;\n * 'max-age'?: number;\n * 'must-revalidate'?: boolean;\n * 'must-understand'?: boolean;\n * 'no-cache'?: boolean;\n * 'no-store'?: boolean;\n * 'no-transform'?: boolean;\n * 'only-if-cached'?: boolean;\n * private?: boolean;\n * 'proxy-revalidate'?: boolean;\n * public?: boolean;\n * 's-maxage'?: number;\n * 'stale-if-error'?: number;\n * 'stale-while-revalidate'?: number;\n * }\n * ```\n *\n * See also {@link CacheControlValue} and [Response Directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#response_directives)\n *\n * @public\n */\nexport function parseCacheControl(header: string): CacheControlValue {\n return CACHE_CONTROL_CACHE.get(header);\n}\n\nconst CACHE_CONTROL_CACHE = new LRUCache((header: string) => {\n let key: CacheControlKey = '' as CacheControlKey;\n let value = '';\n let isParsingKey = true;\n const cacheControlValue: CacheControlValue = {};\n\n for (let i = 0; i < header.length; i++) {\n const char = header.charAt(i);\n if (char === ',') {\n assert(`Invalid Cache-Control value, expected a value`, !isParsingKey || !NUMERIC_KEYS.has(key));\n assert(\n `Invalid Cache-Control value, expected a value after \"=\" but got \",\"`,\n i === 0 || header.charAt(i - 1) !== '='\n );\n isParsingKey = true;\n // @ts-expect-error TS incorrectly thinks that optional keys must have a type that includes undefined\n cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true;\n key = '' as CacheControlKey;\n value = '';\n continue;\n } else if (char === '=') {\n assert(`Invalid Cache-Control value, expected a value after \"=\"`, i + 1 !== header.length);\n isParsingKey = false;\n } else if (char === ' ' || char === `\\t` || char === `\\n`) {\n continue;\n } else if (isParsingKey) {\n key += char;\n } else {\n value += char;\n }\n\n if (i === header.length - 1) {\n // @ts-expect-error TS incorrectly thinks that optional keys must have a type that includes undefined\n cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true;\n }\n }\n\n return cacheControlValue;\n}, 200);\n\nfunction parseCacheControlValue(stringToParse: string): number {\n const parsedValue = Number.parseInt(stringToParse);\n assert(`Invalid Cache-Control value, expected a number but got - ${stringToParse}`, !Number.isNaN(parsedValue));\n assert(`Invalid Cache-Control value, expected a number greater than 0 but got - ${stringToParse}`, parsedValue >= 0);\n if (Number.isNaN(parsedValue) || parsedValue < 0) {\n return 0;\n }\n\n return parsedValue;\n}\n\nfunction isExpired(cacheKey: RequestKey, request: StructuredDocument<ResourceDocument>, config: PolicyConfig): boolean {\n const { constraints } = config;\n\n if (constraints?.isExpired) {\n const result = constraints.isExpired(request);\n if (result !== null) {\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because constraints.isExpired returned ${result}`\n );\n }\n return result;\n }\n }\n\n const { headers } = request.response!;\n\n if (!headers) {\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is EXPIRED because no headers were provided`);\n }\n\n // if we have no headers then both the headers based expiration\n // and the time based expiration will be considered expired\n return true;\n }\n\n // check for X-WarpDrive-Expires\n const now = Date.now();\n const date = headers.get('Date');\n\n if (constraints?.headers) {\n if (constraints.headers['X-WarpDrive-Expires']) {\n const xWarpDriveExpires = headers.get('X-WarpDrive-Expires');\n if (xWarpDriveExpires) {\n const expirationTime = new Date(xWarpDriveExpires).getTime();\n const result = now >= expirationTime;\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the time set by X-WarpDrive-Expires header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n return result;\n }\n }\n\n // check for Cache-Control\n if (constraints.headers['Cache-Control']) {\n const cacheControl = headers.get('Cache-Control');\n const age = headers.get('Age');\n\n if (cacheControl && age && date) {\n const cacheControlValue = parseCacheControl(cacheControl);\n\n // max-age and s-maxage are stored in\n const maxAge = cacheControlValue['max-age'] || cacheControlValue['s-maxage'];\n\n if (maxAge) {\n // age is stored in seconds\n const ageValue = parseInt(age, 10);\n assert(`Invalid Cache-Control value, expected a number but got - ${age}`, !Number.isNaN(ageValue));\n assert(`Invalid Cache-Control value, expected a number greater than 0 but got - ${age}`, ageValue >= 0);\n\n if (!Number.isNaN(ageValue) && ageValue >= 0) {\n const dateValue = new Date(date).getTime();\n const expirationTime = dateValue + (maxAge - ageValue) * 1000;\n const result = now >= expirationTime;\n\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the time set by Cache-Control header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n\n return result;\n }\n }\n }\n }\n\n // check for Expires\n if (constraints.headers.Expires) {\n const expires = headers.get('Expires');\n if (expires) {\n const expirationTime = new Date(expires).getTime();\n const result = now >= expirationTime;\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the time set by Expires header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n return result;\n }\n }\n }\n\n // check for Date\n if (!date) {\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is EXPIRED because no Date header was provided`);\n }\n return true;\n }\n\n let expirationTime = config.apiCacheHardExpires;\n if (TESTING) {\n if (!config.disableTestOptimization) {\n expirationTime = config.apiCacheSoftExpires;\n }\n }\n\n const time = new Date(date).getTime();\n const deadline = time + expirationTime;\n const result = now >= deadline;\n\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'EXPIRED' : 'NOT expired'} because the apiCacheHardExpires time since the response's Date header is ${result ? 'in the past' : 'in the future'}`\n );\n }\n\n return result;\n}\n\n/**\n * The constraint options for {@link PolicyConfig.constraints}\n */\nexport interface PolicyConfigConstraints {\n /**\n * Headers that should be checked for expiration.\n *\n */\n headers?: {\n /**\n * Whether the `Cache-Control` header should be checked for expiration.\n * If `true`, then the `max-age` and `s-maxage` directives are used alongside\n * the `Age` and `Date` headers to determine if the expiration time has passed.\n *\n * Other directives are ignored.\n *\n * 'Cache-Control' will take precedence over 'Expires' if both are present\n * and both configured to be checked.\n *\n */\n 'Cache-Control'?: boolean;\n\n /**\n * Whether the `Expires` header should be checked for expiration.\n *\n * If `true`, then the `Expires` header is used to caclulate the expiration time\n * and determine if the expiration time has passed.\n *\n * 'Cache-Control' will take precedence over 'Expires' if both are present.\n *\n */\n Expires?: boolean;\n\n /**\n * Whether the `X-WarpDrive-Expires` header should be checked for expiration.\n *\n * If `true`, then the `X-WarpDrive-Expires` header is used to caclulate the expiration time\n * and determine if the expiration time has passed.\n *\n * This header will take precedence over 'Cache-Control' and 'Expires' if all three are present.\n *\n * The header's value should be a [UTC date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString).\n *\n */\n 'X-WarpDrive-Expires'?: boolean;\n };\n\n /**\n * A function that should be called to determine if the request is expired.\n *\n * If present, this function will be called with the request and should return\n * `true` if the request is expired, `false` if it is not expired, and\n * `null` if the expiration status is unknown.\n *\n * If the function does not return `null`,\n *\n */\n isExpired?: (request: StructuredDocument<ResourceDocument>) => boolean | null;\n}\n\n/**\n * The configuration options for the {@link DefaultCachePolicy}\n *\n * ```ts [app/services/store.ts]\n * import { Store } from '@warp-drive/core';\n * import { DefaultCachePolicy } from '@warp-drive/core/store'; // [!code focus]\n *\n * export default class AppStore extends Store {\n * lifetimes = new DefaultCachePolicy({ // [!code focus:3]\n * // ... PolicyConfig Settings ... //\n * });\n * }\n * ```\n *\n */\nexport interface PolicyConfig {\n /**\n * the number of milliseconds after which a request is considered\n * stale. If a request is issued again after this time, the request\n * will respond from cache immediately while a background request\n * is made to update the cache.\n *\n * This is calculated against the `date` header of the response.\n *\n * If your API does not provide a `date` header, the {@link Fetch} handler\n * will automatically add it to responses if it is not present. Responses\n * without a `date` header will be considered stale immediately.\n *\n */\n apiCacheSoftExpires: number;\n /**\n * the number of milliseconds after which a request is considered\n * expired and should be re-fetched. If a request is issued again\n * after this time, the request will disregard the cache and\n * wait for a fresh response from the API.\n *\n * This is calculated against the `date` header of the response.\n *\n * If your API does not provide a `date` header, the {@link Fetch} handler\n * will automatically add it to responses if it is not present. Responses\n * without a `date` header will be considered hard expired immediately.\n *\n */\n apiCacheHardExpires: number;\n /**\n * In Testing environments, the `apiCacheSoftExpires` will always be `false`\n * and `apiCacheHardExpires` will use the `apiCacheSoftExpires` value.\n *\n * This helps reduce flakiness and produce predictably rendered results in test suites.\n *\n * Requests that specifically set {@link RequestInfo.cacheOptions.backgroundReload | cacheOptions.backgroundReload }\n * will still be background reloaded in tests.\n *\n * This behavior can be opted out of by setting this value to `true`.\n *\n */\n disableTestOptimization?: boolean;\n\n /**\n * In addition to the simple time-based expiration strategy, CachePolicy\n * supports various common server-supplied expiration strategies via\n * headers, as well as custom expiration strategies via the {@link PolicyConfigConstraints.isExpired | isExpired}\n * function.\n *\n * Requests will be validated for expiration against these constraints.\n * If any of these constraints are not met, the request will be considered\n * expired. If all constraints are met, the request will be considered\n * valid and the time based expiration strategy will NOT be used.\n *\n * Meeting a constraint means BOTH that the properties the constraint\n * requires are present AND that the expiration time indicated by those\n * properties has not been exceeded.\n *\n * In other words, if the properties for a constraint are not present,\n * this does not count either as meeting or as not meeting the constraint,\n * the constraint simply does not apply.\n *\n * The `isExpired` function is called with the request and should return\n * `true` if the request is expired, `false` if it is not expired, and\n * `null` if the expiration status is unknown.\n *\n * In order constraints are checked:\n *\n * - isExpired function\n * - ↳ (if null) X-WarpDrive-Expires header\n * - ↳ (if null) Cache-Control header\n * - ↳ (if null) Expires header\n *\n * See {@link PolicyConfigConstraints} for configuration options.\n */\n constraints?: PolicyConfigConstraints;\n}\n\n/**\n * A basic {@link CachePolicy} that can be added to the Store service.\n *\n * ```ts [app/services/store.ts]\n * import { Store } from '@warp-drive/core';\n * import { DefaultCachePolicy } from '@warp-drive/core/store'; // [!code focus]\n *\n * export default class AppStore extends Store {\n * lifetimes = new DefaultCachePolicy({ // [!code focus:5]\n * apiCacheSoftExpires: 30_000,\n * apiCacheHardExpires: 60_000,\n * // ... Other PolicyConfig Settings ... //\n * });\n * }\n * ```\n *\n * :::tip 💡 TIP\n * Date headers do not have millisecond precision, so expiration times should\n * generally be larger than 1000ms.\n * :::\n *\n * See also {@link PolicyConfig} for configuration options.\n *\n * ### The Mechanics\n *\n * This policy determines staleness based on various configurable constraints falling back to a simple\n * check of the time elapsed since the request was last received from the API using the `date` header\n * from the last response.\n *\n * :::tip 💡 TIP\n * The {@link Fetch} handler provided by `@warp-drive/core` will automatically\n * add the `date` header to responses if it is not present.\n * :::\n *\n * - For manual override of reload see {@link CacheOptions.reload | cacheOptions.reload}\n * - For manual override of background reload see {@link CacheOptions.backgroundReload | cacheOptions.backgroundReload}\n *\n * In order expiration is determined by:\n *\n * ```md\n * Is explicitly invalidated by `cacheOptions.reload`\n * ↳ (if falsey) if the request has been explicitly invalidated\n * since the last request (see Automatic Invalidation below)\n * ↳ (if false) (If Active) isExpired function\n * ↳ (if null) (If Active) X-WarpDrive-Expires header\n * ↳ (if null) (If Active) Cache-Control header\n * ↳ (if null) (If Active) Expires header\n * ↳ (if null) Date header + apiCacheHardExpires < current time\n *\n * -- <if above is false, a background request is issued if> --\n *\n * ↳ is invalidated by `cacheOptions.backgroundReload`\n * ↳ (if falsey) Date header + apiCacheSoftExpires < current time\n * ```\n *\n * ### Automatic Invalidation / Entanglement\n *\n * It also invalidates any request with an {@link RequestInfo.op | OpCode} of `\"query\"`\n * for which {@link CacheOptions.types | cacheOptions.types} was provided\n * when a request with an `OpCode` of `\"createRecord\"` is successful and also includes\n * a matching type in its own `cacheOptions.types` array.\n\n * :::tip 💡 TIP\n * Abstracting this behavior via builders is recommended to ensure consistency.\n * :::\n *\n * ### Testing\n *\n * In Testing environments:\n *\n * - `apiCacheSoftExpires` will always be `false`\n * - `apiCacheHardExpires` will use the `apiCacheSoftExpires` value.\n *\n * This helps reduce flakiness and produce predictably rendered results in test suites.\n *\n * Requests that specifically set `cacheOptions.backgroundReload = true` will\n * still be background reloaded in tests.\n *\n * This behavior can be opted out of by setting `disableTestOptimization = true`\n * in the policy config.\n *\n * @public\n */\nexport class DefaultCachePolicy implements CachePolicy {\n /**\n * @internal\n */\n declare private config: PolicyConfig;\n /**\n * @internal\n */\n declare private _stores: WeakMap<Store, { invalidated: Set<RequestKey>; types: Map<string, Set<RequestKey>> }>;\n\n /**\n * @internal\n */\n private _getStore(store: Store): {\n invalidated: Set<RequestKey>;\n types: Map<string, Set<RequestKey>>;\n } {\n let set = this._stores.get(store);\n if (!set) {\n set = { invalidated: new Set(), types: new Map() };\n this._stores.set(store, set);\n }\n return set;\n }\n\n constructor(config: PolicyConfig) {\n this._stores = new WeakMap();\n\n const _config = arguments.length === 1 ? config : (arguments[1] as unknown as PolicyConfig);\n deprecate(\n `Passing a Store to the CachePolicy is deprecated, please pass only a config instead.`,\n arguments.length === 1,\n {\n id: 'ember-data:request-utils:lifetimes-service-store-arg',\n since: {\n enabled: '5.4',\n available: '4.13',\n },\n for: '@ember-data/request-utils',\n until: '6.0',\n }\n );\n assert(`You must pass a config to the CachePolicy`, _config);\n assert(`You must pass a apiCacheSoftExpires to the CachePolicy`, typeof _config.apiCacheSoftExpires === 'number');\n assert(`You must pass a apiCacheHardExpires to the CachePolicy`, typeof _config.apiCacheHardExpires === 'number');\n this.config = _config;\n }\n\n /**\n * Invalidate a request by its CacheKey for the given store instance.\n *\n * While the store argument may seem redundant, the CachePolicy\n * is designed to be shared across multiple stores / forks\n * of the store.\n *\n * ```ts\n * store.lifetimes.invalidateRequest(store, cacheKey);\n * ```\n *\n * @public\n */\n invalidateRequest(cacheKey: RequestKey, store: Store): void {\n this._getStore(store).invalidated.add(cacheKey);\n }\n\n /**\n * Invalidate all requests associated to a specific type\n * for a given store instance.\n *\n * While the store argument may seem redundant, the CachePolicy\n * is designed to be shared across multiple stores / forks\n * of the store.\n *\n * This invalidation is done automatically when using this service\n * for both the {@link CacheHandler} and the [NetworkHandler](/api/@warp-drive/legacy/compat/variables/LegacyNetworkHandler).\n *\n * ```ts\n * store.lifetimes.invalidateRequestsForType(store, 'person');\n * ```\n *\n * @public\n */\n invalidateRequestsForType(type: string, store: Store): void {\n const storeCache = this._getStore(store);\n const set = storeCache.types.get(type);\n const notifications = store.notifications;\n\n if (set) {\n // TODO batch notifications\n set.forEach((id) => {\n storeCache.invalidated.add(id);\n // @ts-expect-error\n notifications.notify(id, 'invalidated', null);\n });\n }\n }\n\n /**\n * Invoked when a request has been fulfilled from the configured request handlers.\n * This is invoked by the CacheHandler for both foreground and background requests\n * once the cache has been updated.\n *\n * Note, this is invoked by the {@link CacheHandler} regardless of whether\n * the request has a cache-key.\n *\n * This method should not be invoked directly by consumers.\n *\n * @public\n */\n didRequest(\n request: ImmutableRequestInfo,\n response: Response | ResponseInfo | null,\n cacheKey: RequestKey | null,\n store: Store\n ): void {\n // if this is a successful createRecord request, invalidate the cacheKey for the type\n if (request.op === 'createRecord') {\n const statusNumber = response?.status ?? 0;\n if (statusNumber >= 200 && statusNumber < 400) {\n const types = new Set(request.records?.map((r) => r.type));\n const additionalTypes = request.cacheOptions?.types;\n additionalTypes?.forEach((type) => {\n types.add(type);\n });\n\n types.forEach((type) => {\n this.invalidateRequestsForType(type, store);\n });\n }\n\n // add this document's cacheKey to a map for all associated types\n // it is recommended to only use this for queries\n } else if (cacheKey && request.cacheOptions?.types?.length) {\n const storeCache = this._getStore(store);\n request.cacheOptions?.types.forEach((type) => {\n const set = storeCache.types.get(type);\n if (set) {\n set.add(cacheKey);\n storeCache.invalidated.delete(cacheKey);\n } else {\n storeCache.types.set(type, new Set([cacheKey]));\n }\n });\n }\n }\n\n /**\n * Invoked to determine if the request may be fulfilled from cache\n * if possible.\n *\n * Note, this is only invoked by the {@link CacheHandler} if the request has\n * a cache-key.\n *\n * If no cache entry is found or the entry is hard expired,\n * the request will be fulfilled from the configured request handlers\n * and the cache will be updated before returning the response.\n *\n * @public\n * @return true if the request is considered hard expired\n */\n isHardExpired(cacheKey: RequestKey, store: Store): boolean {\n // if we are explicitly invalidated, we are hard expired\n const storeCache = this._getStore(store);\n if (storeCache.invalidated.has(cacheKey)) {\n return true;\n }\n const cache = store.cache;\n const cached = cache.peekRequest(cacheKey);\n\n if (!cached?.response) {\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is EXPIRED because no cache entry was found`);\n }\n return true;\n }\n\n return isExpired(cacheKey, cached, this.config);\n }\n\n /**\n * Invoked if `isHardExpired` is false to determine if the request\n * should be update behind the scenes if cache data is already available.\n *\n * Note, this is only invoked by the {@link CacheHandler} if the request has\n * a cache-key.\n *\n * If true, the request will be fulfilled from cache while a backgrounded\n * request is made to update the cache via the configured request handlers.\n *\n * @public\n * @return true if the request is considered soft expired\n */\n isSoftExpired(cacheKey: RequestKey, store: Store): boolean {\n if (TESTING) {\n if (!this.config.disableTestOptimization) {\n return false;\n }\n }\n const cache = store.cache;\n const cached = cache.peekRequest(cacheKey);\n\n if (cached?.response) {\n const date = cached.response.headers.get('date');\n\n if (!date) {\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is STALE because no date header was found`);\n }\n return true;\n } else {\n const time = new Date(date).getTime();\n const now = Date.now();\n const deadline = time + this.config.apiCacheSoftExpires;\n const result = now >= deadline;\n\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(\n `CachePolicy: ${cacheKey.lid} is ${result ? 'STALE' : 'NOT stale'}. Expiration time: ${deadline}, now: ${now}`\n );\n }\n\n return result;\n }\n }\n\n if (LOG_CACHE_POLICY) {\n // oxlint-disable-next-line no-console\n console.log(`CachePolicy: ${cacheKey.lid} is STALE because no cache entry was found`);\n }\n\n return true;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as setTransient, i as peekUniversalTransient, n as getOrSetUniversal, o as setUniversalTransient, r as peekTransient, t as getOrSetGlobal } from "../-private-
|
|
1
|
+
import { a as setTransient, i as peekUniversalTransient, n as getOrSetUniversal, o as setUniversalTransient, r as peekTransient, t as getOrSetGlobal } from "../-private-B6aLbrgV.js";
|
|
2
2
|
|
|
3
3
|
export { getOrSetGlobal, getOrSetUniversal, peekTransient, peekUniversalTransient, setTransient, setUniversalTransient };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record.js","names":["createIncludeValidator","validateIncludes","includes"],"sources":["../../../../src/types/record.ts"],"sourcesContent":["import type { Type } from './symbols.ts';\n\n/**\n * Records may be anything, They don't even\n * have to be objects.\n *\n * Whatever they are, if they have a Type\n * property, that property will be used by WarpDrive\n * and WarpDrive to provide better type safety and\n * intellisense.\n *\n * @class TypedRecordInstance\n */\nexport interface TypedRecordInstance {\n /**\n * The type of the resource.\n *\n * This is an optional feature that can be used by\n * record implementations to provide a typescript\n * hint for the type of the resource.\n *\n * When used, WarpDrive APIs can\n * take advantage of this to provide better type\n * safety and intellisense.\n *\n * @property [Type]\n * @type {Type}\n * @type {String}\n */\n [Type]: string;\n}\n\n/**\n * A type utility that extracts the Type if available,\n * otherwise it returns never.\n *\n */\nexport type TypeFromInstance<T> = T extends TypedRecordInstance ? T[typeof Type] : never;\n\n/**\n * A type utility that extracts the Type if available,\n * otherwise it returns string\n *\n */\nexport type TypeFromInstanceOrString<T> = T extends TypedRecordInstance ? T[typeof Type] : string;\n\ntype IsUniqueSymbol<T> = T extends `___(unique) Symbol(${string})` ? true : false;\ntype Unpacked<T> = T extends (infer U)[] ? U : T;\ntype NONE = { __NONE: never };\n\ntype __InternalExtract<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n V extends TypedRecordInstance,\n IncludePrefix extends boolean,\n Ignore,\n Pre extends string,\n DEPTH extends _DEPTHCOUNT,\n> =\n // if we extend T, we return the leaf value\n V extends T\n ? IncludePrefix extends false\n ? V[typeof Type]\n : Pre\n : // else if we are in Ignore we add the lead and exit\n V extends Ignore\n ? IncludePrefix extends false\n ? V[typeof Type]\n : Pre\n : // else if we are at max depth, we return never\n IS_MAX_DEPTH<DEPTH, MAX_DEPTH> extends true\n ? Pre\n : // else add T to Ignore and recurse\n ExtractUnion<MAX_DEPTH, V, IncludePrefix, Ignore | T, Pre, INC_DEPTH<DEPTH>>;\n\ntype __ExtractIfRecord<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n V,\n IncludePrefix extends boolean,\n Ignore,\n Pre extends string,\n DEPTH extends _DEPTHCOUNT,\n> = V extends TypedRecordInstance ? __InternalExtract<MAX_DEPTH, T, V, IncludePrefix, Ignore, Pre, DEPTH> : never;\n\ntype _ExtractUnion<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n IncludePrefix extends boolean,\n Ignore,\n Pre,\n DEPTH extends _DEPTHCOUNT,\n> = {\n // for each string key in the record,\n [K in keyof T]: IsUniqueSymbol<K> extends true\n ? never\n : K extends string\n ? // we recursively extract any values that resolve to a TypedRecordInstance\n __ExtractIfRecord<\n MAX_DEPTH,\n T,\n Unpacked<Awaited<T[K]>>,\n IncludePrefix,\n Ignore,\n Pre extends string ? `${Pre}.${K}` : K,\n DEPTH\n >\n : never;\n // then we return any value that is not 'never'\n}[keyof T];\n\n/**\n * A Utility that extracts either resource types or resource paths from a TypedRecordInstance.\n *\n * Its limitations are mostly around its intentional non-recursiveness. It presumes that APIs which\n * implement includes will not allow cyclical include paths, and will collapse includes by type.\n *\n * This follows closer to the JSON:API fields spec than to the includes spec in nature, but in\n * practice it is so impracticle for an API to allow z-algo include paths that this is probably\n * reasonable.\n *\n * We may need to revisit this in the future, opting to either make this restriction optional or\n * to allow for other strategies.\n *\n * There's a 90% chance this particular implementation belongs being in the JSON:API package instead\n * of core-types, but it's here for now.\n *\n */\ntype ExtractUnion<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n IncludePrefix extends boolean = false,\n Ignore = NONE,\n Pre = NONE,\n DEPTH extends _DEPTHCOUNT = 1,\n> = Exclude<\n IncludePrefix extends true\n ? // if we want to include prefix, we union with the prefix. Outer Exclude will filter any \"NONE\" types\n _ExtractUnion<MAX_DEPTH, T, IncludePrefix, Ignore, Pre, DEPTH> | Pre\n : // Else we just union the types.\n _ExtractUnion<MAX_DEPTH, T, IncludePrefix, Ignore, Pre, DEPTH> | T[typeof Type],\n NONE\n>;\n\ntype _DEPTHCOUNT = 1 | 2 | 3 | 4 | 5;\ntype INC_DEPTH<START extends _DEPTHCOUNT> = START extends 1 ? 2 : START extends 2 ? 3 : START extends 3 ? 4 : 5;\ntype IS_MAX_DEPTH<\n DEPTH extends _DEPTHCOUNT,\n MAX_DEPTH extends _DEPTHCOUNT = DEFAULT_MAX_DEPTH,\n> = DEPTH extends MAX_DEPTH ? true : false;\ntype DEFAULT_MAX_DEPTH = 3;\n/**\n * A utility that provides the union of all ResourceName for all potential\n * includes for the given TypedRecordInstance.\n *\n */\nexport type ExtractSuggestedCacheTypes<\n T extends TypedRecordInstance,\n MAX_DEPTH extends _DEPTHCOUNT = DEFAULT_MAX_DEPTH,\n> = ExtractUnion<MAX_DEPTH, T>; // ToPaths<ExpandIgnore<T, true>, false>;\n\n/**\n * A utility that provides the union type of all valid include paths for the given\n * TypedRecordInstance.\n *\n * Cyclical paths are filtered out.\n *\n */\nexport type Includes<T extends TypedRecordInstance, MAX_DEPTH extends _DEPTHCOUNT = DEFAULT_MAX_DEPTH> = ExtractUnion<\n MAX_DEPTH,\n T,\n true\n>;\n\n/**\n * A type-erased placeholder for a record instance, used where the\n * specific record type is not known or not relevant.\n */\nexport type OpaqueRecordInstance = unknown;\n\n/**\n * @internal\n */\nexport type _StringSatisfiesIncludes<T extends string, SET extends string, FT extends string> = T extends SET\n ? FT\n : T extends `${infer U},${infer V}`\n ? U extends SET\n ? _StringSatisfiesIncludes<V, Exclude<SET, U>, FT>\n : never\n : never;\n\n/**\n * Validates that the comma-separated-string `T` (e.g. `'company,company.ceo,friends'`)\n * only contains paths present in the union `SET` (typically {@link Includes}).\n *\n * TypeScript cannot autocomplete against this type; prefer {@link createIncludeValidator}\n * for a better development experience unless you are writing a similar wrapper utility.\n *\n * @example\n * ```ts\n * import type { StringSatisfiesIncludes, Includes } from '@warp-drive/core/types/record';\n *\n * const includes: StringSatisfiesIncludes<\n * 'company,company.ceo,friends',\n * Includes<User>\n * > = 'company,company.ceo,friends';\n * ```\n */\nexport type StringSatisfiesIncludes<T extends string, SET extends string> = _StringSatisfiesIncludes<T, SET, T>;\n\n/**\n * Creates a runtime validator function for comma-separated `include` strings,\n * ensuring at compile time that only valid paths for `T` (per {@link Includes})\n * are supplied.\n *\n * @example\n * ```ts\n * import { createIncludeValidator } from '@warp-drive/core/types/record';\n *\n * const userIncludesValidator = createIncludeValidator<User>;\n *\n * userIncludesValidator('company,company.ceo,friends');\n * ```\n */\nexport function createIncludeValidator<T extends TypedRecordInstance>() {\n return function validateIncludes<U extends string>(includes: StringSatisfiesIncludes<U, Includes<T>>): U {\n return includes;\n };\n}\n\n/**\n * A utility that takes two types, K and T, and produces a new type that is a \"mask\" of T based on K.\n *\n * That's a mouthful, so let's break it down:\n *\n * Let's say you have a User type and an Address type.\n *\n * ```ts\n * interface Address {\n * street: string;\n * city: string;\n * state: string;\n * zip: string;\n * }\n *\n * interface User {\n * name: string;\n * title: string;\n * address: Address;\n * }\n * ```\n *\n * Now, imagine you want to load a preview of the user with some information about their address,\n * but you don't want to load the entire user or address. You probably want to still ensure\n * the type of the data you do load matches the underlying Address and User types, but doesn't\n * include everything.\n *\n * If you did this manually, you might do something like this:\n *\n * ```ts\n * interface UserPreview {\n * name: string;\n * address: AddressPreview;\n * }\n *\n * interface AddressPreview {\n * city: string;\n * }\n * ```\n *\n * From a TypeScript performance perspective, this is the best way to approach these preview\n * types, but this is also tedious and error-prone, especially if the User or Address types change.\n *\n * For Address, we could create a validated type using `Pick`:\n *\n * ```ts\n * type AddressPreview = Pick<Address, 'city'>;\n * ```\n *\n * This ensures that if the Address type changes, our AddressPreview will still be valid.\n * However, for UserPreview, we can't just use `Pick` because the `address` property is of type `Address`,\n * not `AddressPreview`. This is where the `Mask` type comes in.\n *\n * With `Mask`, we define the `UserPreview` in two parts\n * - first, we define the subset of fields we want to include from `User`, using `Pick` or an interface.\n * - then, we use `Mask` to replace the related types of fields like Address with their more limited subset.\n *\n * Here's how we can do it:\n *\n * ```ts\n * // First, we define the base of UserPreview with Pick\n * type UserPreviewBase = Pick<User, 'name' | 'address'>;\n * // Then, we use Mask to replace Address with AddressPreview\n * type UserPreview = Mask<{ address: AddressPreview }, UserPreviewBase>;\n * ```\n *\n * Now, `UserPreview` will have the `name` field from `User` and the `address` field will be of type `AddressPreview`.\n * This way, if the `User` or `Address` types change, TypeScript will ensure that our `UserPreview` and `AddressPreview`\n * types remain valid and consistent with the underlying types.\n *\n * But what if your app has data with massive interfaces such that the TypeScript performance of this\n * approach becomes a problem? In that case, see {@link Validate}\n */\nexport type Mask<K extends object, T extends K> = {\n [P in keyof T]: P extends keyof K ? (T[P] extends K[P] ? K[P] : never) : T[P];\n};\n\n/**\n * A utility that takes two types, K and T, and ensures that K is a valid subset of T.\n *\n * That's a mouthful, so let's break it down:\n *\n * Let's say you have a User type and an Address type.\n *\n * ```ts\n * interface Address {\n * street: string;\n * city: string;\n * state: string;\n * zip: string;\n * }\n *\n * interface User {\n * name: string;\n * title: string;\n * address: Address;\n * }\n * ```\n *\n * Now, imagine you want to load a preview of the user with some information about their address,\n * but you don't want to load the entire user or address. You probably want to still ensure\n * the type of the data you do load matches the underlying Address and User types, but doesn't\n * include everything.\n *\n * You might do something like this:\n *\n * ```ts\n * interface UserPreview {\n * name: string;\n * address: AddressPreview;\n * }\n *\n * interface AddressPreview {\n * city: string;\n * }\n * ```\n *\n * From a TypeScript performance perspective, this is the best way to approach these preview\n * types, but this is also error-prone, especially if the User or Address types change.\n *\n * Validate can help ensure that your preview types remain valid.\n *\n * ```ts\n * type IsValidUserPreview = Validate<UserPreview, User>; // This will be valid\n * ```\n *\n * For help creating subsets of types, see {@link Mask}\n */\nexport type Validate<K extends object, T extends K> = T extends K ? K : never;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgOA,SAAgBA,yBAAwD;CACtE,OAAO,SAASC,iBAAmCC,UAAsD;EACvG,OAAOA;CACT;AACF"}
|
|
1
|
+
{"version":3,"file":"record.js","names":["createIncludeValidator","validateIncludes","includes"],"sources":["../../../../src/types/record.ts"],"sourcesContent":["import type { Type } from './symbols.ts';\n\n/**\n * Records may be anything, They don't even\n * have to be objects.\n *\n * Whatever they are, if they have a Type\n * property, that property will be used by WarpDrive\n * and WarpDrive to provide better type safety and\n * intellisense.\n *\n * @class TypedRecordInstance\n */\nexport interface TypedRecordInstance {\n /**\n * The type of the resource.\n *\n * This is an optional feature that can be used by\n * record implementations to provide a typescript\n * hint for the type of the resource.\n *\n * When used, WarpDrive APIs can\n * take advantage of this to provide better type\n * safety and intellisense.\n *\n * @property [Type]\n * @type {Type}\n * @type {String}\n */\n [Type]: string;\n}\n\n/**\n * A type utility that extracts the Type if available,\n * otherwise it returns never.\n *\n */\nexport type TypeFromInstance<T> = T extends TypedRecordInstance ? T[typeof Type] : never;\n\n/**\n * A type utility that extracts the Type if available,\n * otherwise it returns string\n *\n */\nexport type TypeFromInstanceOrString<T> = T extends TypedRecordInstance ? T[typeof Type] : string;\n\ntype IsUniqueSymbol<T> = T extends `___(unique) Symbol(${string})` ? true : false;\ntype Unpacked<T> = T extends (infer U)[] ? U : T;\ntype NONE = { __NONE: never };\n\ntype __InternalExtract<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n V extends TypedRecordInstance,\n IncludePrefix extends boolean,\n Ignore,\n Pre extends string,\n DEPTH extends _DEPTHCOUNT,\n> =\n // if we extend T, we return the leaf value\n V extends T\n ? IncludePrefix extends false\n ? V[typeof Type]\n : Pre\n : // else if we are in Ignore we add the lead and exit\n V extends Ignore\n ? IncludePrefix extends false\n ? V[typeof Type]\n : Pre\n : // else if we are at max depth, we return never\n IS_MAX_DEPTH<DEPTH, MAX_DEPTH> extends true\n ? Pre\n : // else add T to Ignore and recurse\n ExtractUnion<MAX_DEPTH, V, IncludePrefix, Ignore | T, Pre, INC_DEPTH<DEPTH>>;\n\ntype __ExtractIfRecord<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n V,\n IncludePrefix extends boolean,\n Ignore,\n Pre extends string,\n DEPTH extends _DEPTHCOUNT,\n> = V extends TypedRecordInstance ? __InternalExtract<MAX_DEPTH, T, V, IncludePrefix, Ignore, Pre, DEPTH> : never;\n\ntype _ExtractUnion<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n IncludePrefix extends boolean,\n Ignore,\n Pre,\n DEPTH extends _DEPTHCOUNT,\n> = {\n // for each string key in the record,\n [K in keyof T]: IsUniqueSymbol<K> extends true\n ? never\n : K extends string\n ? // we recursively extract any values that resolve to a TypedRecordInstance\n __ExtractIfRecord<\n MAX_DEPTH,\n T,\n Unpacked<Awaited<T[K]>>,\n IncludePrefix,\n Ignore,\n Pre extends string ? `${Pre}.${K}` : K,\n DEPTH\n >\n : never;\n // then we return any value that is not 'never'\n}[keyof T];\n\n/**\n * A Utility that extracts either resource types or resource paths from a TypedRecordInstance.\n *\n * Its limitations are mostly around its intentional non-recursiveness. It presumes that APIs which\n * implement includes will not allow cyclical include paths, and will collapse includes by type.\n *\n * This follows closer to the JSON:API fields spec than to the includes spec in nature, but in\n * practice it is so impracticle for an API to allow z-algo include paths that this is probably\n * reasonable.\n *\n * We may need to revisit this in the future, opting to either make this restriction optional or\n * to allow for other strategies.\n *\n * There's a 90% chance this particular implementation belongs being in the JSON:API package instead\n * of core-types, but it's here for now.\n *\n */\ntype ExtractUnion<\n MAX_DEPTH extends _DEPTHCOUNT,\n T extends TypedRecordInstance,\n IncludePrefix extends boolean = false,\n Ignore = NONE,\n Pre = NONE,\n DEPTH extends _DEPTHCOUNT = 1,\n> = Exclude<\n IncludePrefix extends true\n ? // if we want to include prefix, we union with the prefix. Outer Exclude will filter any \"NONE\" types\n _ExtractUnion<MAX_DEPTH, T, IncludePrefix, Ignore, Pre, DEPTH> | Pre\n : // Else we just union the types.\n _ExtractUnion<MAX_DEPTH, T, IncludePrefix, Ignore, Pre, DEPTH> | T[typeof Type],\n NONE\n>;\n\ntype _DEPTHCOUNT = 1 | 2 | 3 | 4 | 5;\ntype INC_DEPTH<START extends _DEPTHCOUNT> = START extends 1 ? 2 : START extends 2 ? 3 : START extends 3 ? 4 : 5;\ntype IS_MAX_DEPTH<\n DEPTH extends _DEPTHCOUNT,\n MAX_DEPTH extends _DEPTHCOUNT = DEFAULT_MAX_DEPTH,\n> = DEPTH extends MAX_DEPTH ? true : false;\ntype DEFAULT_MAX_DEPTH = 3;\n/**\n * A utility that provides the union of all ResourceName for all potential\n * includes for the given TypedRecordInstance.\n *\n */\nexport type ExtractSuggestedCacheTypes<\n T extends TypedRecordInstance,\n MAX_DEPTH extends _DEPTHCOUNT = DEFAULT_MAX_DEPTH,\n> = ExtractUnion<MAX_DEPTH, T>; // ToPaths<ExpandIgnore<T, true>, false>;\n\n/**\n * A utility that provides the union type of all valid include paths for the given\n * TypedRecordInstance.\n *\n * Cyclical paths are filtered out.\n *\n */\nexport type Includes<T extends TypedRecordInstance, MAX_DEPTH extends _DEPTHCOUNT = DEFAULT_MAX_DEPTH> = ExtractUnion<\n MAX_DEPTH,\n T,\n true\n>;\n\n/**\n * A type-erased placeholder for a record instance, used where the\n * specific record type is not known or not relevant.\n */\nexport type OpaqueRecordInstance = unknown;\n\n/**\n * @internal\n */\nexport type _StringSatisfiesIncludes<T extends string, SET extends string, FT extends string> = T extends SET\n ? FT\n : T extends `${infer U},${infer V}`\n ? U extends SET\n ? _StringSatisfiesIncludes<V, Exclude<SET, U>, FT>\n : never\n : never;\n\n/**\n * Validates that the comma-separated-string `T` (e.g. `'company,company.ceo,friends'`)\n * only contains paths present in the union `SET` (typically {@link Includes}).\n *\n * TypeScript cannot autocomplete against this type; prefer {@link createIncludeValidator}\n * for a better development experience unless you are writing a similar wrapper utility.\n *\n * @example\n * ```ts\n * import type { StringSatisfiesIncludes, Includes } from '@warp-drive/core/types/record';\n *\n * const includes: StringSatisfiesIncludes<\n * 'company,company.ceo,friends',\n * Includes<User>\n * > = 'company,company.ceo,friends';\n * ```\n */\nexport type StringSatisfiesIncludes<T extends string, SET extends string> = _StringSatisfiesIncludes<T, SET, T>;\n\n/**\n * Creates a runtime validator function for comma-separated `include` strings,\n * ensuring at compile time that only valid paths for `T` (per {@link Includes})\n * are supplied.\n *\n * @example\n * ```ts\n * import { createIncludeValidator } from '@warp-drive/core/types/record';\n *\n * const userIncludesValidator = createIncludeValidator<User>;\n *\n * userIncludesValidator('company,company.ceo,friends');\n * ```\n */\nexport function createIncludeValidator<T extends TypedRecordInstance>() {\n return function validateIncludes<U extends string>(includes: StringSatisfiesIncludes<U, Includes<T>>): U {\n return includes;\n };\n}\n\n/**\n * A utility that takes two types, K and T, and produces a new type that is a \"mask\" of T based on K.\n *\n * That's a mouthful, so let's break it down:\n *\n * Let's say you have a User type and an Address type.\n *\n * ```ts\n * interface Address {\n * street: string;\n * city: string;\n * state: string;\n * zip: string;\n * }\n *\n * interface User {\n * name: string;\n * title: string;\n * address: Address;\n * }\n * ```\n *\n * Now, imagine you want to load a preview of the user with some information about their address,\n * but you don't want to load the entire user or address. You probably want to still ensure\n * the type of the data you do load matches the underlying Address and User types, but doesn't\n * include everything.\n *\n * If you did this manually, you might do something like this:\n *\n * ```ts\n * interface UserPreview {\n * name: string;\n * address: AddressPreview;\n * }\n *\n * interface AddressPreview {\n * city: string;\n * }\n * ```\n *\n * From a TypeScript performance perspective, this is the best way to approach these preview\n * types, but this is also tedious and error-prone, especially if the User or Address types change.\n *\n * For Address, we could create a validated type using `Pick`:\n *\n * ```ts\n * type AddressPreview = Pick<Address, 'city'>;\n * ```\n *\n * This ensures that if the Address type changes, our AddressPreview will still be valid.\n * However, for UserPreview, we can't just use `Pick` because the `address` property is of type `Address`,\n * not `AddressPreview`. This is where the `Mask` type comes in.\n *\n * With `Mask`, we define the `UserPreview` in two parts\n * - first, we define the subset of fields we want to include from `User`, using `Pick` or an interface.\n * - then, we use `Mask` to replace the related types of fields like Address with their more limited subset.\n *\n * Here's how we can do it:\n *\n * ```ts\n * // First, we define the base of UserPreview with Pick\n * type UserPreviewBase = Pick<User, 'name' | 'address'>;\n * // Then, we use Mask to replace Address with AddressPreview\n * type UserPreview = Mask<{ address: AddressPreview }, UserPreviewBase>;\n * ```\n *\n * Now, `UserPreview` will have the `name` field from `User` and the `address` field will be of type `AddressPreview`.\n * This way, if the `User` or `Address` types change, TypeScript will ensure that our `UserPreview` and `AddressPreview`\n * types remain valid and consistent with the underlying types.\n *\n * But what if your app has data with massive interfaces such that the TypeScript performance of this\n * approach becomes a problem? In that case, see {@link Validate}\n */\nexport type Mask<K extends object, T extends K> = {\n [P in keyof T]: P extends keyof K ? (T[P] extends K[P] ? K[P] : never) : T[P];\n};\n\n/**\n * A utility that takes two types, K and T, and ensures that K is a valid subset of T.\n *\n * That's a mouthful, so let's break it down:\n *\n * Let's say you have a User type and an Address type.\n *\n * ```ts\n * interface Address {\n * street: string;\n * city: string;\n * state: string;\n * zip: string;\n * }\n *\n * interface User {\n * name: string;\n * title: string;\n * address: Address;\n * }\n * ```\n *\n * Now, imagine you want to load a preview of the user with some information about their address,\n * but you don't want to load the entire user or address. You probably want to still ensure\n * the type of the data you do load matches the underlying Address and User types, but doesn't\n * include everything.\n *\n * You might do something like this:\n *\n * ```ts\n * interface UserPreview {\n * name: string;\n * address: AddressPreview;\n * }\n *\n * interface AddressPreview {\n * city: string;\n * }\n * ```\n *\n * From a TypeScript performance perspective, this is the best way to approach these preview\n * types, but this is also error-prone, especially if the User or Address types change.\n *\n * Validate can help ensure that your preview types remain valid.\n *\n * ```ts\n * type IsValidUserPreview = Validate<UserPreview, User>; // This will be valid\n * ```\n *\n * For help creating subsets of types, see {@link Mask}\n */\nexport type Validate<K extends object, T extends K> = T extends K ? K : never;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgOA,SAAgBA,yBAAwD;CACtE,OAAO,SAASC,iBAAmCC,UAAsD;EACvG,OAAOA;CACT;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","names":["getOrSetGlobal","getOrSetUniversal","SkipCache","Symbol","for","EnableHydration","IS_FUTURE","STRUCTURED"],"sources":["../../../../src/types/request.ts"],"sourcesContent":["// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { Future, Handler } from '../request.ts';\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { Fetch } from '../request/-private/fetch.ts';\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { RequestManager } from '../request/-private/manager.ts';\nimport type { FetchError } from '../request/-private/utils.ts';\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport type { RequestLoadingState } from '../signals/request-state.ts';\nimport type { Store } from '../store/-private.ts';\nimport { getOrSetGlobal, getOrSetUniversal } from './-private.ts';\nimport type { ResourceKey } from './identifier.ts';\nimport type { QueryParamsSerializationOptions } from './params.ts';\nimport type {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n Includes,\n TypeFromInstanceOrString,\n} from './record.ts';\nimport type { ResourceIdentifierObject } from './spec/json-api-raw.ts';\nimport type { RequestSignature } from './symbols.ts';\n\n/**\n * A {@link RequestInfo.cacheOptions | cacheOptions} flag which, when set,\n * signals that a request should never be handled by the cache-manager and\n * thus will never resolve from cache nor update the cache.\n */\nexport const SkipCache: '___(unique) Symbol(SkipCache)' = getOrSetUniversal('SkipCache', Symbol.for('wd:skip-cache'));\n/**\n * A {@link RequestInfo} flag which, when set, signals to the store's\n * `instantiateRecord` hook that the resolved content should be hydrated\n * into reactive records rather than returned as raw data.\n */\nexport const EnableHydration: '___(unique) Symbol(EnableHydration)' = getOrSetUniversal(\n 'EnableHydration',\n Symbol.for('wd:enable-hydration')\n);\n/**\n * @private\n */\nexport const IS_FUTURE: '___(unique) Symbol(IS_FUTURE)' = getOrSetGlobal('IS_FUTURE', Symbol('IS_FUTURE'));\n/**\n * @private\n */\nexport const STRUCTURED: '___(unique) Symbol(DOC)' = getOrSetGlobal('DOC', Symbol('DOC'));\n\nexport type { FetchError };\n\n/**\n * The HTTP methods WarpDrive's request layer supports.\n */\nexport type HTTPMethod =\n | 'QUERY'\n | 'GET'\n | 'OPTIONS'\n | 'POST'\n | 'PUT'\n | 'PATCH'\n | 'DELETE'\n | 'HEAD'\n | 'CONNECT'\n | 'TRACE';\n\n/**\n * Use these options to adjust {@link CacheHandler} behavior for a request\n * via {@link RequestInfo.cacheOptions}.\n *\n */\nexport interface CacheOptions {\n /**\n * A key that uniquely identifies this request. If not present, the url wil be used\n * as the key for any GET request, while all other requests will not be cached.\n *\n */\n key?: string;\n /**\n * If true, the request will be made even if a cached response is present\n * and not expired.\n *\n */\n reload?: boolean;\n /**\n * If true, and a cached response is present and not expired, the request\n * will be made in the background and the cached response will be returned.\n *\n */\n backgroundReload?: boolean;\n /**\n * Useful for metadata around when to invalidate the cache. Typically used\n * by strategies that invalidate requests by resource type when a new resource\n * of that type has been created. See the CachePolicy implementation\n * provided by `@ember-data/request-utils` for an example.\n *\n * It is recommended to only use this for query/queryRecord requests where\n * new records created later would affect the results, though using it for\n * findRecord requests is also supported if desired where it may be useful\n * when a create may affect the result of a sideloaded relationship.\n *\n * Generally it is better to patch the cache directly for relationship updates\n * than to invalidate findRecord requests for one.\n *\n */\n // TODO: Ideally this would be T extends TypedRecordInstance ? ExtractSuggestedCacheTypes<T>[] : string[];\n // but that leads to `Type instantiation is excessively deep and possibly infinite.`\n // issues when `T` has many properties.\n types?: string[];\n\n /**\n * If true, the request will never be handled by the cache-manager and thus\n * will never resolve from cache nor update the cache.\n *\n * Generally this is only used for legacy request that manage resource cache\n * updates in a non-standard way via the LegacyNetworkHandler.\n *\n */\n [SkipCache]?: boolean;\n}\n/**\n * The request shape produced by the `findRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type FindRecordRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'GET';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * see {@link CacheOptions}\n */\n cacheOptions?: CacheOptions;\n /**\n * the name of the request operation\n */\n op: 'findRecord';\n /**\n * the resource being requested\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `query` request builders, for\n * use with {@link Store.request}.\n */\nexport type QueryRequestOptions<RT = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'GET';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * see {@link CacheOptions}\n */\n cacheOptions?: CacheOptions;\n /**\n * the name of the request operation\n */\n op: 'query';\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `postQuery` request builders, for\n * use with {@link Store.request}.\n */\nexport type PostQueryRequestOptions<RT = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'POST' | 'QUERY';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * see {@link CacheOptions}. A `key` is required since `POST`/`QUERY`\n * requests otherwise have no cache-safe way to derive one from the url.\n */\n cacheOptions: CacheOptions & {\n /**\n * a key that uniquely identifies this request\n */\n key: string;\n };\n /**\n * the name of the request operation\n */\n op: 'query';\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `deleteRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type DeleteRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'DELETE';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the name of the request operation\n */\n op: 'deleteRecord';\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * data for handlers to convert into the request body\n */\n data: {\n /**\n * the resource being deleted\n */\n record: ResourceKey<TypeFromInstanceOrString<T>>;\n };\n /**\n * the resource being deleted\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\ntype ImmutableRequest<T> = Readonly<T> & {\n readonly headers: ImmutableHeaders;\n readonly records: [ResourceKey];\n};\n\n/**\n * The request shape produced by the `updateRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type UpdateRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'PATCH' | 'PUT';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the name of the request operation\n */\n op: 'updateRecord';\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * data for handlers to convert into the request body\n */\n data: {\n /**\n * the resource being updated\n */\n record: ResourceKey<TypeFromInstanceOrString<T>>;\n };\n /**\n * the resource being updated\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `createRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type CreateRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'POST';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the name of the request operation\n */\n op: 'createRecord';\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * data for handlers to convert into the request body\n */\n data: {\n /**\n * the resource being created\n */\n record: ResourceKey<TypeFromInstanceOrString<T>>;\n };\n /**\n * the resource being created\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The immutable, handler-facing form of {@link DeleteRequestOptions}.\n */\nexport type ImmutableDeleteRequestOptions = ImmutableRequest<DeleteRequestOptions>;\n/**\n * The immutable, handler-facing form of {@link UpdateRequestOptions}.\n */\nexport type ImmutableUpdateRequestOptions = ImmutableRequest<UpdateRequestOptions>;\n/**\n * The immutable, handler-facing form of {@link CreateRequestOptions}.\n */\nexport type ImmutableCreateRequestOptions = ImmutableRequest<CreateRequestOptions>;\n\n/**\n * A minimal reference to a resource sufficient to build a URL for it,\n * as accepted by the request builders.\n */\nexport type RemotelyAccessibleIdentifier<T extends string = string> = {\n /**\n * the resource's persisted id\n */\n id: string;\n /**\n * the resource's type\n */\n type: T;\n /**\n * the local identifier WarpDrive has assigned to the resource, if known\n */\n lid?: string;\n};\n\n/**\n * Options accepted by the request builders for constraining how a\n * request's url is constructed and how the request interacts with the cache.\n */\nexport interface ConstrainedRequestOptions {\n /**\n * If true, the request will be made even if a cached response is present\n * and not expired.\n */\n reload?: boolean;\n /**\n * If true, and a cached response is present and not expired, the request\n * will be made in the background and the cached response will be returned.\n */\n backgroundReload?: boolean;\n /**\n * The host to use when constructing the request's url, overriding any\n * host configured via `setBuildURLConfig`.\n */\n host?: string;\n /**\n * The namespace to use when constructing the request's url, overriding\n * any namespace configured via `setBuildURLConfig`.\n */\n namespace?: string;\n /**\n * The resource path to use when constructing the request's url,\n * overriding the default of pluralizing the resource's type.\n */\n resourcePath?: string;\n /**\n * Options for how to serialize the request's query params, see {@link QueryParamsSerializationOptions}.\n */\n urlParamsSettings?: QueryParamsSerializationOptions;\n}\n\n/**\n * Options accepted by the `findRecord` request builders.\n */\nexport interface FindRecordOptions extends ConstrainedRequestOptions {\n /**\n * the relationship paths to sideload, see {@link Includes}\n */\n include?: string | string[];\n}\n\n/**\n * When a {@link Future} resolves, it returns an object\n * containing the original {@link RequestInfo | request},\n * the {@link Response | response} set by the handler chain (if any), and\n * the processed content.\n */\nexport interface StructuredDataDocument<T> {\n /**\n * @private\n */\n [STRUCTURED]?: true;\n /**\n * @see {@link ImmutableRequestInfo}\n */\n request: ImmutableRequestInfo;\n /**\n * the response set by the handler chain, if any\n */\n response: Response | ResponseInfo | null;\n /**\n * the processed content of the response\n */\n content: T;\n}\n\n/**\n * When a {@link Future} rejects, it throws either an {@link Error}\n * an {@link AggregateError} or a {@link DOMException} that maintains\n * the `{ request, response, content }` shape but is also an Error instance\n * itself.\n *\n * If using the error originates from the {@link Fetch | Fetch Handler}\n * the error will be a {@link FetchError}\n */\nexport interface StructuredErrorDocument<T = unknown> extends Error {\n /**\n * @private\n */\n [STRUCTURED]?: true;\n /**\n * @see {@link ImmutableRequestInfo}\n */\n request: ImmutableRequestInfo;\n /**\n * the response set by the handler chain, if any\n */\n response: Response | ResponseInfo | null;\n /**\n * the error that caused the request to fail\n */\n error: string | object;\n /**\n * the processed content of the response, if any was received before the failure\n */\n content?: T;\n}\n\n/**\n * A union of the resolve/reject data types for the {@link Future}\n * returned by {@link Store.request | request}\n *\n * See also the docs for:\n *\n * - {@link Future}\n * - {@link StructuredDataDocument} (resolved/successful requests)\n * - {@link StructuredErrorDocument} (rejected/failed requests)\n */\nexport type StructuredDocument<T> = StructuredDataDocument<T> | StructuredErrorDocument<T>;\n\n/**\n * The {@link RequestInit} interface accepted by the native {@link fetch} API.\n *\n * WarpDrive provides our own typings due to incompleteness in the native typings.\n *\n * @privateRemarks\n * - [MDN Reference (fetch)](https://developer.mozilla.org/docs/Web/API/Window/fetch)\n * - [MDN Reference (RequestInit)](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit)\n * - [MDN Reference (Request)](https://developer.mozilla.org/docs/Web/API/Request)\n *\n */\ninterface NativeRequestInit {\n /** Returns the cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching.\n */\n cache?: RequestCache;\n /** Returns the credentials mode associated with request, which is a string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL.\n */\n credentials?: RequestCredentials;\n /** Returns the kind of resource requested by request, e.g., \"document\" or \"script\".\n */\n destination?: RequestDestination;\n /** Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the \"Host\" header.\n */\n headers?: Headers;\n /** Returns request's subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. [SRI]\n */\n integrity?: string;\n /** Returns a boolean indicating whether or not request can outlive the global in which it was created.\n */\n keepalive?: boolean;\n /** Returns request's HTTP method, which is \"GET\" by default.\n */\n method?: HTTPMethod;\n /** Returns the mode associated with request, which is a string indicating whether the request will use CORS, or will be restricted to same-origin URLs.\n *\n * `no-cors` is not allowed for streaming request bodies.\n *\n */\n mode?: RequestMode;\n /**\n * provides an explicit priority hint for the request.\n */\n priority?: RequestPriority;\n /** Returns the redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default.\n */\n redirect?: RequestRedirect;\n /** Returns the referrer of request. Its value can be a same-origin URL if explicitly set in init, the empty string to indicate no referrer, and \"about:client\" when defaulting to the global's default. This is used during fetching to determine the value of the `Referer` header of the request being made.\n */\n referrer?: string;\n /** Returns the referrer policy associated with request. This is used during fetching to compute the value of the request's referrer.\n */\n referrerPolicy?: ReferrerPolicy;\n /** Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler.\n */\n signal?: AbortSignal;\n /** Returns the URL of request as a string.\n */\n url?: string;\n /** Any body that you want to add to your request. Note that a GET or HEAD request may not have a body.\n */\n body?: BodyInit | null;\n\n /**\n * When sending a ReadableStream as the body of a request, 'half' must be\n * specified.\n *\n * [Half Duplex Further Reading](https://developer.chrome.com/docs/capabilities/web-apis/fetch-streaming-requests#half_duplex)\n *\n */\n duplex?: 'half';\n}\n\n/**\n * A read-only {@link Headers} instance, as passed to {@link Handler | Handlers}\n * via {@link ImmutableRequestInfo.headers}.\n */\nexport interface ImmutableHeaders extends Headers {\n /**\n * Returns a mutable clone of these headers, if supported by the implementation.\n */\n clone?(): Headers;\n /**\n * Returns the headers as an array of `[key, value]` pairs.\n */\n toJSON(): [string, string][];\n}\n\n/**\n * Extends JavaScript's native {@link fetch} {@link NativeRequestInit | RequestInit} with additional\n * properties specific to the {@link RequestManager | RequestManager's} capabilities.\n *\n * This interface is used to define the shape of a request that can be made via\n * either the {@link RequestManager.request} or {@link Store.request} methods.\n *\n * @privateRemarks\n * - [MDN Reference (fetch)](https://developer.mozilla.org/docs/Web/API/Window/fetch)\n * - [MDN Reference (RequestInit)](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit)\n * - [MDN Reference (Request)](https://developer.mozilla.org/docs/Web/API/Request)\n *\n * @public\n * @since 4.12\n */\nexport interface RequestInfo<RT = unknown> extends NativeRequestInit {\n /**\n * If provided, used instead of the AbortController auto-configured for each request by the RequestManager\n *\n */\n controller?: AbortController;\n\n /**\n * @see {@link CacheOptions}\n */\n cacheOptions?: CacheOptions;\n /**\n * The {@link Store} the request was made against, if made via\n * {@link Store.request} rather than directly against a {@link RequestManager}.\n *\n * A {@link Handler} can read this off of {@link RequestContext.request | context.request}\n * to reach store state (the cache, other services attached to a custom\n * store subclass, etc.) without needing any Ember DI/`setOwner` wiring at\n * handler-construction time. This works for a handler of any shape (a\n * function, plain object, or class) because the store is attached to each\n * request individually rather than to the handler itself.\n *\n * The trade-off is that this is only populated for requests issued via\n * {@link Store.request | store.request(...)}; a request issued directly\n * against a {@link RequestManager} will not have it set unless the caller\n * supplies it explicitly. Handlers that rely on it should treat it as\n * optional.\n *\n * @example\n * ```ts\n * const LoggingHandler = {\n * request<T>(context: RequestContext, next: NextFn<T>) {\n * const store = context.request.store;\n * if (store) {\n * console.log(`[${store.constructor.name}] ${context.request.url ?? ''}`);\n * }\n * return next(context.request);\n * },\n * };\n * ```\n */\n store?: Store;\n\n /**\n * The name of the request operation, if any (e.g. `'findRecord'`, `'query'`).\n */\n op?: string;\n\n /**\n * The {@link ResourceKey | ResourceKeys} of the primary resources involved in the request\n * (if any). This may be used by handlers to perform transactional\n * operations on the store.\n *\n */\n records?: ResourceKey[];\n\n /**\n * If true, this request will not be tracked by test waiters.\n */\n disableTestWaiter?: boolean;\n /**\n * data that a handler should convert into\n * the query (GET) or body (POST).\n *\n * Note: It is recommended that builders set query params\n * and body directly in most scenarios.\n *\n */\n data?: Record<string, unknown>;\n /**\n * options specifically intended for {@link Handler | Handlers}\n * to utilize to process the request\n *\n */\n options?: Record<string, unknown>;\n\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n\n /**\n * see {@link EnableHydration}\n */\n [EnableHydration]?: boolean;\n}\n\n/**\n * Immutable version of {@link RequestInfo}. This is what is passed to handlers.\n *\n */\nexport type ImmutableRequestInfo<RT = unknown> = Readonly<Omit<RequestInfo<RT>, 'controller'>> & {\n /**\n * see {@link CacheOptions}\n */\n readonly cacheOptions?: Readonly<CacheOptions>;\n /**\n * see {@link ImmutableHeaders}\n */\n readonly headers?: ImmutableHeaders;\n /**\n * see {@link RequestInfo.data}\n */\n readonly data?: Readonly<Record<string, unknown>>;\n /**\n * see {@link RequestInfo.options}\n */\n readonly options?: Readonly<Record<string, unknown>>;\n\n /** Whether the request body has been read.\n */\n readonly bodyUsed?: boolean;\n};\n\n/**\n * An immutable, JSON-serializable subset of the native {@link Response}\n * interface.\n */\nexport interface ResponseInfo {\n /**\n * see {@link ImmutableHeaders}\n */\n readonly headers: ImmutableHeaders; // to do, maybe not this?\n /**\n * whether the response's status code was in the 200-299 range\n */\n readonly ok: boolean;\n /**\n * whether the response is the result of a redirect\n */\n readonly redirected: boolean;\n /**\n * the response's HTTP status code\n */\n readonly status: number;\n /**\n * the status message associated with the response's status code\n */\n readonly statusText: string;\n /**\n * the type of the response, see [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type)\n */\n readonly type: ResponseType;\n /**\n * the url of the response\n */\n readonly url: string;\n}\n\n/**\n * The object a {@link Handler} uses to fulfill a request: it provides a\n * readonly view of the {@link RequestContext.request | request} and methods\n * for supplying the {@link Future}'s stream and final response.\n */\nexport interface RequestContext {\n /**\n * @see {@link ImmutableRequestInfo}\n */\n request: ImmutableRequestInfo;\n /**\n * a unique id for this request\n */\n id: number;\n\n /**\n * Supplies the stream of the response's content, if available, enabling\n * consumers to monitor download progress via {@link RequestLoadingState}.\n */\n setStream(stream: ReadableStream | Promise<ReadableStream | null>): void;\n /**\n * Supplies the response for the request.\n */\n setResponse(response: Response | ResponseInfo | null): void;\n}\n"],"mappings":";;;;;;;;AA0BA,MAAaE,YAA6CD,kBAAkB,aAAaE,OAAOC,IAAI,eAAe,CAAC;;;;;;AAMpH,MAAaC,kBAAyDJ,kBACpE,mBACAE,OAAOC,IAAI,qBAAqB,CAClC;;;;AAIA,MAAaE,YAA6CN,eAAe,aAAaG,OAAO,WAAW,CAAC;;;;AAIzG,MAAaI,aAAwCP,eAAe,OAAOG,OAAO,KAAK,CAAC"}
|
|
1
|
+
{"version":3,"file":"request.js","names":["getOrSetGlobal","getOrSetUniversal","SkipCache","Symbol","for","EnableHydration","IS_FUTURE","STRUCTURED"],"sources":["../../../../src/types/request.ts"],"sourcesContent":["// oxlint-disable-next-line no-unused-vars\nimport type { Future, Handler } from '../request.ts';\n// oxlint-disable-next-line no-unused-vars\nimport type { Fetch } from '../request/-private/fetch.ts';\n// oxlint-disable-next-line no-unused-vars\nimport type { RequestManager } from '../request/-private/manager.ts';\nimport type { FetchError } from '../request/-private/utils.ts';\n// oxlint-disable-next-line no-unused-vars\nimport type { RequestLoadingState } from '../signals/request-state.ts';\nimport type { Store } from '../store/-private.ts';\nimport { getOrSetGlobal, getOrSetUniversal } from './-private.ts';\nimport type { ResourceKey } from './identifier.ts';\nimport type { QueryParamsSerializationOptions } from './params.ts';\nimport type {\n // oxlint-disable-next-line no-unused-vars\n Includes,\n TypeFromInstanceOrString,\n} from './record.ts';\nimport type { ResourceIdentifierObject } from './spec/json-api-raw.ts';\nimport type { RequestSignature } from './symbols.ts';\n\n/**\n * A {@link RequestInfo.cacheOptions | cacheOptions} flag which, when set,\n * signals that a request should never be handled by the cache-manager and\n * thus will never resolve from cache nor update the cache.\n */\nexport const SkipCache: '___(unique) Symbol(SkipCache)' = getOrSetUniversal('SkipCache', Symbol.for('wd:skip-cache'));\n/**\n * A {@link RequestInfo} flag which, when set, signals to the store's\n * `instantiateRecord` hook that the resolved content should be hydrated\n * into reactive records rather than returned as raw data.\n */\nexport const EnableHydration: '___(unique) Symbol(EnableHydration)' = getOrSetUniversal(\n 'EnableHydration',\n Symbol.for('wd:enable-hydration')\n);\n/**\n * @private\n */\nexport const IS_FUTURE: '___(unique) Symbol(IS_FUTURE)' = getOrSetGlobal('IS_FUTURE', Symbol('IS_FUTURE'));\n/**\n * @private\n */\nexport const STRUCTURED: '___(unique) Symbol(DOC)' = getOrSetGlobal('DOC', Symbol('DOC'));\n\nexport type { FetchError };\n\n/**\n * The HTTP methods WarpDrive's request layer supports.\n */\nexport type HTTPMethod =\n | 'QUERY'\n | 'GET'\n | 'OPTIONS'\n | 'POST'\n | 'PUT'\n | 'PATCH'\n | 'DELETE'\n | 'HEAD'\n | 'CONNECT'\n | 'TRACE';\n\n/**\n * Use these options to adjust {@link CacheHandler} behavior for a request\n * via {@link RequestInfo.cacheOptions}.\n *\n */\nexport interface CacheOptions {\n /**\n * A key that uniquely identifies this request. If not present, the url wil be used\n * as the key for any GET request, while all other requests will not be cached.\n *\n */\n key?: string;\n /**\n * If true, the request will be made even if a cached response is present\n * and not expired.\n *\n */\n reload?: boolean;\n /**\n * If true, and a cached response is present and not expired, the request\n * will be made in the background and the cached response will be returned.\n *\n */\n backgroundReload?: boolean;\n /**\n * Useful for metadata around when to invalidate the cache. Typically used\n * by strategies that invalidate requests by resource type when a new resource\n * of that type has been created. See the CachePolicy implementation\n * provided by `@ember-data/request-utils` for an example.\n *\n * It is recommended to only use this for query/queryRecord requests where\n * new records created later would affect the results, though using it for\n * findRecord requests is also supported if desired where it may be useful\n * when a create may affect the result of a sideloaded relationship.\n *\n * Generally it is better to patch the cache directly for relationship updates\n * than to invalidate findRecord requests for one.\n *\n */\n // TODO: Ideally this would be T extends TypedRecordInstance ? ExtractSuggestedCacheTypes<T>[] : string[];\n // but that leads to `Type instantiation is excessively deep and possibly infinite.`\n // issues when `T` has many properties.\n types?: string[];\n\n /**\n * If true, the request will never be handled by the cache-manager and thus\n * will never resolve from cache nor update the cache.\n *\n * Generally this is only used for legacy request that manage resource cache\n * updates in a non-standard way via the LegacyNetworkHandler.\n *\n */\n [SkipCache]?: boolean;\n}\n/**\n * The request shape produced by the `findRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type FindRecordRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'GET';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * see {@link CacheOptions}\n */\n cacheOptions?: CacheOptions;\n /**\n * the name of the request operation\n */\n op: 'findRecord';\n /**\n * the resource being requested\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `query` request builders, for\n * use with {@link Store.request}.\n */\nexport type QueryRequestOptions<RT = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'GET';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * see {@link CacheOptions}\n */\n cacheOptions?: CacheOptions;\n /**\n * the name of the request operation\n */\n op: 'query';\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `postQuery` request builders, for\n * use with {@link Store.request}.\n */\nexport type PostQueryRequestOptions<RT = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'POST' | 'QUERY';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * see {@link CacheOptions}. A `key` is required since `POST`/`QUERY`\n * requests otherwise have no cache-safe way to derive one from the url.\n */\n cacheOptions: CacheOptions & {\n /**\n * a key that uniquely identifies this request\n */\n key: string;\n };\n /**\n * the name of the request operation\n */\n op: 'query';\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `deleteRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type DeleteRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'DELETE';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the name of the request operation\n */\n op: 'deleteRecord';\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * data for handlers to convert into the request body\n */\n data: {\n /**\n * the resource being deleted\n */\n record: ResourceKey<TypeFromInstanceOrString<T>>;\n };\n /**\n * the resource being deleted\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\ntype ImmutableRequest<T> = Readonly<T> & {\n readonly headers: ImmutableHeaders;\n readonly records: [ResourceKey];\n};\n\n/**\n * The request shape produced by the `updateRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type UpdateRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'PATCH' | 'PUT';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the name of the request operation\n */\n op: 'updateRecord';\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * data for handlers to convert into the request body\n */\n data: {\n /**\n * the resource being updated\n */\n record: ResourceKey<TypeFromInstanceOrString<T>>;\n };\n /**\n * the resource being updated\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The request shape produced by the `createRecord` request builders, for\n * use with {@link Store.request}.\n */\nexport type CreateRequestOptions<RT = unknown, T = unknown> = {\n /**\n * the url to request\n */\n url: string;\n /**\n * the HTTP method to use\n */\n method: 'POST';\n /**\n * the headers to send with the request\n */\n headers: Headers;\n /**\n * the name of the request operation\n */\n op: 'createRecord';\n /**\n * the body to send with the request\n */\n body?: string | BodyInit | FormData;\n /**\n * data for handlers to convert into the request body\n */\n data: {\n /**\n * the resource being created\n */\n record: ResourceKey<TypeFromInstanceOrString<T>>;\n };\n /**\n * the resource being created\n */\n records: [ResourceIdentifierObject<TypeFromInstanceOrString<T>>];\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n};\n\n/**\n * The immutable, handler-facing form of {@link DeleteRequestOptions}.\n */\nexport type ImmutableDeleteRequestOptions = ImmutableRequest<DeleteRequestOptions>;\n/**\n * The immutable, handler-facing form of {@link UpdateRequestOptions}.\n */\nexport type ImmutableUpdateRequestOptions = ImmutableRequest<UpdateRequestOptions>;\n/**\n * The immutable, handler-facing form of {@link CreateRequestOptions}.\n */\nexport type ImmutableCreateRequestOptions = ImmutableRequest<CreateRequestOptions>;\n\n/**\n * A minimal reference to a resource sufficient to build a URL for it,\n * as accepted by the request builders.\n */\nexport type RemotelyAccessibleIdentifier<T extends string = string> = {\n /**\n * the resource's persisted id\n */\n id: string;\n /**\n * the resource's type\n */\n type: T;\n /**\n * the local identifier WarpDrive has assigned to the resource, if known\n */\n lid?: string;\n};\n\n/**\n * Options accepted by the request builders for constraining how a\n * request's url is constructed and how the request interacts with the cache.\n */\nexport interface ConstrainedRequestOptions {\n /**\n * If true, the request will be made even if a cached response is present\n * and not expired.\n */\n reload?: boolean;\n /**\n * If true, and a cached response is present and not expired, the request\n * will be made in the background and the cached response will be returned.\n */\n backgroundReload?: boolean;\n /**\n * The host to use when constructing the request's url, overriding any\n * host configured via `setBuildURLConfig`.\n */\n host?: string;\n /**\n * The namespace to use when constructing the request's url, overriding\n * any namespace configured via `setBuildURLConfig`.\n */\n namespace?: string;\n /**\n * The resource path to use when constructing the request's url,\n * overriding the default of pluralizing the resource's type.\n */\n resourcePath?: string;\n /**\n * Options for how to serialize the request's query params, see {@link QueryParamsSerializationOptions}.\n */\n urlParamsSettings?: QueryParamsSerializationOptions;\n}\n\n/**\n * Options accepted by the `findRecord` request builders.\n */\nexport interface FindRecordOptions extends ConstrainedRequestOptions {\n /**\n * the relationship paths to sideload, see {@link Includes}\n */\n include?: string | string[];\n}\n\n/**\n * When a {@link Future} resolves, it returns an object\n * containing the original {@link RequestInfo | request},\n * the {@link Response | response} set by the handler chain (if any), and\n * the processed content.\n */\nexport interface StructuredDataDocument<T> {\n /**\n * @private\n */\n [STRUCTURED]?: true;\n /**\n * @see {@link ImmutableRequestInfo}\n */\n request: ImmutableRequestInfo;\n /**\n * the response set by the handler chain, if any\n */\n response: Response | ResponseInfo | null;\n /**\n * the processed content of the response\n */\n content: T;\n}\n\n/**\n * When a {@link Future} rejects, it throws either an {@link Error}\n * an {@link AggregateError} or a {@link DOMException} that maintains\n * the `{ request, response, content }` shape but is also an Error instance\n * itself.\n *\n * If using the error originates from the {@link Fetch | Fetch Handler}\n * the error will be a {@link FetchError}\n */\nexport interface StructuredErrorDocument<T = unknown> extends Error {\n /**\n * @private\n */\n [STRUCTURED]?: true;\n /**\n * @see {@link ImmutableRequestInfo}\n */\n request: ImmutableRequestInfo;\n /**\n * the response set by the handler chain, if any\n */\n response: Response | ResponseInfo | null;\n /**\n * the error that caused the request to fail\n */\n error: string | object;\n /**\n * the processed content of the response, if any was received before the failure\n */\n content?: T;\n}\n\n/**\n * A union of the resolve/reject data types for the {@link Future}\n * returned by {@link Store.request | request}\n *\n * See also the docs for:\n *\n * - {@link Future}\n * - {@link StructuredDataDocument} (resolved/successful requests)\n * - {@link StructuredErrorDocument} (rejected/failed requests)\n */\nexport type StructuredDocument<T> = StructuredDataDocument<T> | StructuredErrorDocument<T>;\n\n/**\n * The {@link RequestInit} interface accepted by the native {@link fetch} API.\n *\n * WarpDrive provides our own typings due to incompleteness in the native typings.\n *\n * @privateRemarks\n * - [MDN Reference (fetch)](https://developer.mozilla.org/docs/Web/API/Window/fetch)\n * - [MDN Reference (RequestInit)](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit)\n * - [MDN Reference (Request)](https://developer.mozilla.org/docs/Web/API/Request)\n *\n */\ninterface NativeRequestInit {\n /** Returns the cache mode associated with request, which is a string indicating how the request will interact with the browser's cache when fetching.\n */\n cache?: RequestCache;\n /** Returns the credentials mode associated with request, which is a string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL.\n */\n credentials?: RequestCredentials;\n /** Returns the kind of resource requested by request, e.g., \"document\" or \"script\".\n */\n destination?: RequestDestination;\n /** Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the \"Host\" header.\n */\n headers?: Headers;\n /** Returns request's subresource integrity metadata, which is a cryptographic hash of the resource being fetched. Its value consists of multiple hashes separated by whitespace. [SRI]\n */\n integrity?: string;\n /** Returns a boolean indicating whether or not request can outlive the global in which it was created.\n */\n keepalive?: boolean;\n /** Returns request's HTTP method, which is \"GET\" by default.\n */\n method?: HTTPMethod;\n /** Returns the mode associated with request, which is a string indicating whether the request will use CORS, or will be restricted to same-origin URLs.\n *\n * `no-cors` is not allowed for streaming request bodies.\n *\n */\n mode?: RequestMode;\n /**\n * provides an explicit priority hint for the request.\n */\n priority?: RequestPriority;\n /** Returns the redirect mode associated with request, which is a string indicating how redirects for the request will be handled during fetching. A request will follow redirects by default.\n */\n redirect?: RequestRedirect;\n /** Returns the referrer of request. Its value can be a same-origin URL if explicitly set in init, the empty string to indicate no referrer, and \"about:client\" when defaulting to the global's default. This is used during fetching to determine the value of the `Referer` header of the request being made.\n */\n referrer?: string;\n /** Returns the referrer policy associated with request. This is used during fetching to compute the value of the request's referrer.\n */\n referrerPolicy?: ReferrerPolicy;\n /** Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort event handler.\n */\n signal?: AbortSignal;\n /** Returns the URL of request as a string.\n */\n url?: string;\n /** Any body that you want to add to your request. Note that a GET or HEAD request may not have a body.\n */\n body?: BodyInit | null;\n\n /**\n * When sending a ReadableStream as the body of a request, 'half' must be\n * specified.\n *\n * [Half Duplex Further Reading](https://developer.chrome.com/docs/capabilities/web-apis/fetch-streaming-requests#half_duplex)\n *\n */\n duplex?: 'half';\n}\n\n/**\n * A read-only {@link Headers} instance, as passed to {@link Handler | Handlers}\n * via {@link ImmutableRequestInfo.headers}.\n */\nexport interface ImmutableHeaders extends Headers {\n /**\n * Returns a mutable clone of these headers, if supported by the implementation.\n */\n clone?(): Headers;\n /**\n * Returns the headers as an array of `[key, value]` pairs.\n */\n toJSON(): [string, string][];\n}\n\n/**\n * Extends JavaScript's native {@link fetch} {@link NativeRequestInit | RequestInit} with additional\n * properties specific to the {@link RequestManager | RequestManager's} capabilities.\n *\n * This interface is used to define the shape of a request that can be made via\n * either the {@link RequestManager.request} or {@link Store.request} methods.\n *\n * @privateRemarks\n * - [MDN Reference (fetch)](https://developer.mozilla.org/docs/Web/API/Window/fetch)\n * - [MDN Reference (RequestInit)](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit)\n * - [MDN Reference (Request)](https://developer.mozilla.org/docs/Web/API/Request)\n *\n * @public\n * @since 4.12\n */\nexport interface RequestInfo<RT = unknown> extends NativeRequestInit {\n /**\n * If provided, used instead of the AbortController auto-configured for each request by the RequestManager\n *\n */\n controller?: AbortController;\n\n /**\n * @see {@link CacheOptions}\n */\n cacheOptions?: CacheOptions;\n /**\n * The {@link Store} the request was made against, if made via\n * {@link Store.request} rather than directly against a {@link RequestManager}.\n *\n * A {@link Handler} can read this off of {@link RequestContext.request | context.request}\n * to reach store state (the cache, other services attached to a custom\n * store subclass, etc.) without needing any Ember DI/`setOwner` wiring at\n * handler-construction time. This works for a handler of any shape (a\n * function, plain object, or class) because the store is attached to each\n * request individually rather than to the handler itself.\n *\n * The trade-off is that this is only populated for requests issued via\n * {@link Store.request | store.request(...)}; a request issued directly\n * against a {@link RequestManager} will not have it set unless the caller\n * supplies it explicitly. Handlers that rely on it should treat it as\n * optional.\n *\n * @example\n * ```ts\n * const LoggingHandler = {\n * request<T>(context: RequestContext, next: NextFn<T>) {\n * const store = context.request.store;\n * if (store) {\n * console.log(`[${store.constructor.name}] ${context.request.url ?? ''}`);\n * }\n * return next(context.request);\n * },\n * };\n * ```\n */\n store?: Store;\n\n /**\n * The name of the request operation, if any (e.g. `'findRecord'`, `'query'`).\n */\n op?: string;\n\n /**\n * The {@link ResourceKey | ResourceKeys} of the primary resources involved in the request\n * (if any). This may be used by handlers to perform transactional\n * operations on the store.\n *\n */\n records?: ResourceKey[];\n\n /**\n * If true, this request will not be tracked by test waiters.\n */\n disableTestWaiter?: boolean;\n /**\n * data that a handler should convert into\n * the query (GET) or body (POST).\n *\n * Note: It is recommended that builders set query params\n * and body directly in most scenarios.\n *\n */\n data?: Record<string, unknown>;\n /**\n * options specifically intended for {@link Handler | Handlers}\n * to utilize to process the request\n *\n */\n options?: Record<string, unknown>;\n\n /**\n * @private used only to carry the response type for type inference purposes\n */\n [RequestSignature]?: RT;\n\n /**\n * see {@link EnableHydration}\n */\n [EnableHydration]?: boolean;\n}\n\n/**\n * Immutable version of {@link RequestInfo}. This is what is passed to handlers.\n *\n */\nexport type ImmutableRequestInfo<RT = unknown> = Readonly<Omit<RequestInfo<RT>, 'controller'>> & {\n /**\n * see {@link CacheOptions}\n */\n readonly cacheOptions?: Readonly<CacheOptions>;\n /**\n * see {@link ImmutableHeaders}\n */\n readonly headers?: ImmutableHeaders;\n /**\n * see {@link RequestInfo.data}\n */\n readonly data?: Readonly<Record<string, unknown>>;\n /**\n * see {@link RequestInfo.options}\n */\n readonly options?: Readonly<Record<string, unknown>>;\n\n /** Whether the request body has been read.\n */\n readonly bodyUsed?: boolean;\n};\n\n/**\n * An immutable, JSON-serializable subset of the native {@link Response}\n * interface.\n */\nexport interface ResponseInfo {\n /**\n * see {@link ImmutableHeaders}\n */\n readonly headers: ImmutableHeaders; // to do, maybe not this?\n /**\n * whether the response's status code was in the 200-299 range\n */\n readonly ok: boolean;\n /**\n * whether the response is the result of a redirect\n */\n readonly redirected: boolean;\n /**\n * the response's HTTP status code\n */\n readonly status: number;\n /**\n * the status message associated with the response's status code\n */\n readonly statusText: string;\n /**\n * the type of the response, see [MDN Reference](https://developer.mozilla.org/docs/Web/API/Response/type)\n */\n readonly type: ResponseType;\n /**\n * the url of the response\n */\n readonly url: string;\n}\n\n/**\n * The object a {@link Handler} uses to fulfill a request: it provides a\n * readonly view of the {@link RequestContext.request | request} and methods\n * for supplying the {@link Future}'s stream and final response.\n */\nexport interface RequestContext {\n /**\n * @see {@link ImmutableRequestInfo}\n */\n request: ImmutableRequestInfo;\n /**\n * a unique id for this request\n */\n id: number;\n\n /**\n * Supplies the stream of the response's content, if available, enabling\n * consumers to monitor download progress via {@link RequestLoadingState}.\n */\n setStream(stream: ReadableStream | Promise<ReadableStream | null>): void;\n /**\n * Supplies the response for the request.\n */\n setResponse(response: Response | ResponseInfo | null): void;\n}\n"],"mappings":";;;;;;;;AA0BA,MAAaE,YAA6CD,kBAAkB,aAAaE,OAAOC,IAAI,eAAe,CAAC;;;;;;AAMpH,MAAaC,kBAAyDJ,kBACpE,mBACAE,OAAOC,IAAI,qBAAqB,CAClC;;;;AAIA,MAAaE,YAA6CN,eAAe,aAAaG,OAAO,WAAW,CAAC;;;;AAIzG,MAAaI,aAAwCP,eAAe,OAAOG,OAAO,KAAK,CAAC"}
|