@warp-drive/core 5.8.0-alpha.4 → 5.8.0-alpha.40

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.
Files changed (248) hide show
  1. package/README.md +22 -38
  2. package/declarations/build-config.d.ts +18 -1
  3. package/declarations/graph/-private/-edge-definition.d.ts +12 -2
  4. package/declarations/index.d.ts +90 -8
  5. package/declarations/reactive/-private/document.d.ts +58 -46
  6. package/declarations/reactive/-private/record.d.ts +10 -1
  7. package/declarations/reactive/-private/schema.d.ts +77 -4
  8. package/declarations/reactive/-private.d.ts +1 -0
  9. package/declarations/reactive.d.ts +13 -7
  10. package/declarations/request/-private/types.d.ts +1 -1
  11. package/declarations/request.d.ts +47 -0
  12. package/declarations/store/-private/caches/instance-cache.d.ts +5 -6
  13. package/declarations/store/-private/default-cache-policy.d.ts +147 -129
  14. package/declarations/store/-private/managers/cache-capabilities-manager.d.ts +1 -1
  15. package/declarations/store/-private/managers/cache-key-manager.d.ts +26 -8
  16. package/declarations/store/-private/managers/cache-manager.d.ts +6 -4
  17. package/declarations/store/-private/managers/notification-manager.d.ts +1 -1
  18. package/declarations/store/-private/new-core-tmp/promise-state.d.ts +1 -0
  19. package/declarations/store/-private/new-core-tmp/request-state.d.ts +1 -1
  20. package/declarations/store/-private/store-service.d.ts +43 -64
  21. package/declarations/store/-private.d.ts +0 -1
  22. package/declarations/store/-types/q/cache-capabilities-manager.d.ts +1 -1
  23. package/declarations/store/deprecated/-private.d.ts +1 -1
  24. package/declarations/store/deprecated/store.d.ts +33 -32
  25. package/declarations/store.d.ts +1 -0
  26. package/declarations/types/cache.d.ts +8 -6
  27. package/declarations/types/record.d.ts +132 -0
  28. package/declarations/types/request.d.ts +26 -14
  29. package/declarations/types/schema/fields.d.ts +33 -9
  30. package/declarations/{store/-types/q → types/schema}/schema-service.d.ts +15 -13
  31. package/declarations/types/spec/document.d.ts +34 -0
  32. package/declarations/types/symbols.d.ts +2 -2
  33. package/declarations/types.d.ts +1 -1
  34. package/dist/build-config.js +1 -1
  35. package/dist/default-cache-policy-D7_u4YRH.js +572 -0
  36. package/dist/graph/-private.js +13 -4
  37. package/dist/{request-state-CUuZzgvE.js → index-BKcD4JZK.js} +10018 -8847
  38. package/dist/index.js +6 -382
  39. package/dist/reactive.js +4 -778
  40. package/dist/{context-C_7OLieY.js → request-oqoLC9rz.js} +219 -172
  41. package/dist/request.js +1 -1
  42. package/dist/store/-private.js +1 -1
  43. package/dist/store.js +1 -533
  44. package/dist/types/-private.js +1 -1
  45. package/dist/types/record.js +127 -0
  46. package/dist/types/request.js +14 -12
  47. package/dist/types/schema/fields.js +14 -0
  48. package/dist/types/schema/schema-service.js +0 -0
  49. package/dist/types/symbols.js +2 -2
  50. package/dist/unpkg/dev/-private-3C1OkYtZ.js +39 -0
  51. package/dist/unpkg/dev/build-config/babel-macros.js +1 -0
  52. package/dist/unpkg/dev/build-config/canary-features.js +1 -0
  53. package/dist/unpkg/dev/build-config/debugging.js +1 -0
  54. package/dist/unpkg/dev/build-config/deprecations.js +1 -0
  55. package/dist/unpkg/dev/build-config/env.js +1 -0
  56. package/dist/unpkg/dev/build-config/macros.js +1 -0
  57. package/dist/unpkg/dev/build-config.js +1 -0
  58. package/dist/unpkg/dev/configure-BC66sfNO.js +183 -0
  59. package/dist/unpkg/dev/configure.js +1 -0
  60. package/dist/unpkg/dev/graph/-private.js +3131 -0
  61. package/dist/unpkg/dev/index-DqhXrNZ_.js +11160 -0
  62. package/dist/unpkg/dev/index.js +6 -0
  63. package/dist/unpkg/dev/reactive/-private.js +1 -0
  64. package/dist/unpkg/dev/reactive.js +127 -0
  65. package/dist/unpkg/dev/request-CA9K0gXq.js +719 -0
  66. package/dist/unpkg/dev/request.js +1 -0
  67. package/dist/unpkg/dev/runtime-DGG4CvlW.js +135 -0
  68. package/dist/unpkg/dev/store/-private.js +56 -0
  69. package/dist/unpkg/dev/store.js +558 -0
  70. package/dist/unpkg/dev/types/-private.js +69 -0
  71. package/dist/unpkg/dev/types/cache/aliases.js +0 -0
  72. package/dist/unpkg/dev/types/cache/change.js +0 -0
  73. package/dist/unpkg/dev/types/cache/mutations.js +0 -0
  74. package/dist/unpkg/dev/types/cache/operations.js +0 -0
  75. package/dist/unpkg/dev/types/cache/relationship.js +0 -0
  76. package/dist/unpkg/dev/types/cache.js +0 -0
  77. package/dist/unpkg/dev/types/graph.js +0 -0
  78. package/dist/unpkg/dev/types/identifier.js +61 -0
  79. package/dist/unpkg/dev/types/json/raw.js +0 -0
  80. package/dist/unpkg/dev/types/params.js +0 -0
  81. package/dist/unpkg/dev/types/record.js +191 -0
  82. package/dist/unpkg/dev/types/request.js +77 -0
  83. package/dist/unpkg/dev/types/runtime.js +34 -0
  84. package/dist/unpkg/dev/types/schema/concepts.js +0 -0
  85. package/dist/unpkg/dev/types/schema/fields.js +505 -0
  86. package/dist/unpkg/dev/types/schema/fields.type-test.js +0 -0
  87. package/dist/unpkg/dev/types/schema/schema-service.js +0 -0
  88. package/dist/unpkg/dev/types/spec/document.js +0 -0
  89. package/dist/unpkg/dev/types/spec/error.js +0 -0
  90. package/dist/unpkg/dev/types/spec/json-api-raw.js +0 -0
  91. package/dist/unpkg/dev/types/symbols.js +84 -0
  92. package/dist/unpkg/dev/types/utils.js +0 -0
  93. package/dist/unpkg/dev/types.js +0 -0
  94. package/dist/unpkg/dev/utils/string.js +91 -0
  95. package/dist/unpkg/dev-deprecated/-private-3C1OkYtZ.js +39 -0
  96. package/dist/unpkg/dev-deprecated/build-config/babel-macros.js +1 -0
  97. package/dist/unpkg/dev-deprecated/build-config/canary-features.js +1 -0
  98. package/dist/unpkg/dev-deprecated/build-config/debugging.js +1 -0
  99. package/dist/unpkg/dev-deprecated/build-config/deprecations.js +1 -0
  100. package/dist/unpkg/dev-deprecated/build-config/env.js +1 -0
  101. package/dist/unpkg/dev-deprecated/build-config/macros.js +1 -0
  102. package/dist/unpkg/dev-deprecated/build-config.js +1 -0
  103. package/dist/unpkg/dev-deprecated/configure-BC66sfNO.js +183 -0
  104. package/dist/unpkg/dev-deprecated/configure.js +1 -0
  105. package/dist/unpkg/dev-deprecated/graph/-private.js +3326 -0
  106. package/dist/unpkg/dev-deprecated/index-BBlq5is_.js +11775 -0
  107. package/dist/unpkg/dev-deprecated/index.js +5 -0
  108. package/dist/unpkg/dev-deprecated/reactive/-private.js +1 -0
  109. package/dist/unpkg/dev-deprecated/reactive.js +127 -0
  110. package/dist/unpkg/dev-deprecated/request-CA9K0gXq.js +719 -0
  111. package/dist/unpkg/dev-deprecated/request.js +1 -0
  112. package/dist/unpkg/dev-deprecated/runtime-DfhJzpZH.js +135 -0
  113. package/dist/unpkg/dev-deprecated/store/-private.js +2 -0
  114. package/dist/unpkg/dev-deprecated/store.js +558 -0
  115. package/dist/unpkg/dev-deprecated/types/-private.js +69 -0
  116. package/dist/unpkg/dev-deprecated/types/cache/aliases.js +0 -0
  117. package/dist/unpkg/dev-deprecated/types/cache/change.js +0 -0
  118. package/dist/unpkg/dev-deprecated/types/cache/mutations.js +0 -0
  119. package/dist/unpkg/dev-deprecated/types/cache/operations.js +0 -0
  120. package/dist/unpkg/dev-deprecated/types/cache/relationship.js +0 -0
  121. package/dist/unpkg/dev-deprecated/types/cache.js +0 -0
  122. package/dist/unpkg/dev-deprecated/types/graph.js +0 -0
  123. package/dist/unpkg/dev-deprecated/types/identifier.js +61 -0
  124. package/dist/unpkg/dev-deprecated/types/json/raw.js +0 -0
  125. package/dist/unpkg/dev-deprecated/types/params.js +0 -0
  126. package/dist/unpkg/dev-deprecated/types/record.js +191 -0
  127. package/dist/unpkg/dev-deprecated/types/request.js +77 -0
  128. package/dist/unpkg/dev-deprecated/types/runtime.js +34 -0
  129. package/dist/unpkg/dev-deprecated/types/schema/concepts.js +0 -0
  130. package/dist/unpkg/dev-deprecated/types/schema/fields.js +505 -0
  131. package/dist/unpkg/dev-deprecated/types/schema/fields.type-test.js +0 -0
  132. package/dist/unpkg/dev-deprecated/types/schema/schema-service.js +0 -0
  133. package/dist/unpkg/dev-deprecated/types/spec/document.js +0 -0
  134. package/dist/unpkg/dev-deprecated/types/spec/error.js +0 -0
  135. package/dist/unpkg/dev-deprecated/types/spec/json-api-raw.js +0 -0
  136. package/dist/unpkg/dev-deprecated/types/symbols.js +84 -0
  137. package/dist/unpkg/dev-deprecated/types/utils.js +0 -0
  138. package/dist/unpkg/dev-deprecated/types.js +0 -0
  139. package/dist/unpkg/dev-deprecated/utils/string.js +91 -0
  140. package/dist/unpkg/prod/-private-3C1OkYtZ.js +39 -0
  141. package/dist/unpkg/prod/build-config/babel-macros.js +1 -0
  142. package/dist/unpkg/prod/build-config/canary-features.js +1 -0
  143. package/dist/unpkg/prod/build-config/debugging.js +1 -0
  144. package/dist/unpkg/prod/build-config/deprecations.js +1 -0
  145. package/dist/unpkg/prod/build-config/env.js +1 -0
  146. package/dist/unpkg/prod/build-config/macros.js +1 -0
  147. package/dist/unpkg/prod/build-config.js +1 -0
  148. package/dist/unpkg/prod/configure-C0C1LpG6.js +158 -0
  149. package/dist/unpkg/prod/configure.js +1 -0
  150. package/dist/unpkg/prod/graph/-private.js +2234 -0
  151. package/dist/unpkg/prod/handler-LAyD1Y5l.js +1619 -0
  152. package/dist/unpkg/prod/hooks-BfiqDg3O.js +26 -0
  153. package/dist/unpkg/prod/index.js +481 -0
  154. package/dist/unpkg/prod/promise-state-ipG60SdD.js +6738 -0
  155. package/dist/unpkg/prod/reactive/-private.js +1 -0
  156. package/dist/unpkg/prod/reactive.js +127 -0
  157. package/dist/unpkg/prod/request-CN2LxbYX.js +437 -0
  158. package/dist/unpkg/prod/request.js +1 -0
  159. package/dist/unpkg/prod/store/-private.js +127 -0
  160. package/dist/unpkg/prod/store.js +437 -0
  161. package/dist/unpkg/prod/types/-private.js +49 -0
  162. package/dist/unpkg/prod/types/cache/aliases.js +0 -0
  163. package/dist/unpkg/prod/types/cache/change.js +0 -0
  164. package/dist/unpkg/prod/types/cache/mutations.js +0 -0
  165. package/dist/unpkg/prod/types/cache/operations.js +0 -0
  166. package/dist/unpkg/prod/types/cache/relationship.js +0 -0
  167. package/dist/unpkg/prod/types/cache.js +0 -0
  168. package/dist/unpkg/prod/types/graph.js +0 -0
  169. package/dist/unpkg/prod/types/identifier.js +61 -0
  170. package/dist/unpkg/prod/types/json/raw.js +0 -0
  171. package/dist/unpkg/prod/types/params.js +0 -0
  172. package/dist/unpkg/prod/types/record.js +191 -0
  173. package/dist/unpkg/prod/types/request.js +77 -0
  174. package/dist/unpkg/prod/types/runtime.js +34 -0
  175. package/dist/unpkg/prod/types/schema/concepts.js +0 -0
  176. package/dist/unpkg/prod/types/schema/fields.js +505 -0
  177. package/dist/unpkg/prod/types/schema/fields.type-test.js +0 -0
  178. package/dist/unpkg/prod/types/schema/schema-service.js +0 -0
  179. package/dist/unpkg/prod/types/spec/document.js +0 -0
  180. package/dist/unpkg/prod/types/spec/error.js +0 -0
  181. package/dist/unpkg/prod/types/spec/json-api-raw.js +0 -0
  182. package/dist/unpkg/prod/types/symbols.js +84 -0
  183. package/dist/unpkg/prod/types/utils.js +0 -0
  184. package/dist/unpkg/prod/types.js +0 -0
  185. package/dist/unpkg/prod/utils/string.js +72 -0
  186. package/dist/unpkg/prod-deprecated/-private-3C1OkYtZ.js +39 -0
  187. package/dist/unpkg/prod-deprecated/build-config/babel-macros.js +1 -0
  188. package/dist/unpkg/prod-deprecated/build-config/canary-features.js +1 -0
  189. package/dist/unpkg/prod-deprecated/build-config/debugging.js +1 -0
  190. package/dist/unpkg/prod-deprecated/build-config/deprecations.js +1 -0
  191. package/dist/unpkg/prod-deprecated/build-config/env.js +1 -0
  192. package/dist/unpkg/prod-deprecated/build-config/macros.js +1 -0
  193. package/dist/unpkg/prod-deprecated/build-config.js +1 -0
  194. package/dist/unpkg/prod-deprecated/configure-BQ8CpIcW.js +158 -0
  195. package/dist/unpkg/prod-deprecated/configure.js +1 -0
  196. package/dist/unpkg/prod-deprecated/graph/-private.js +2407 -0
  197. package/dist/unpkg/prod-deprecated/handler-D639oFvl.js +334 -0
  198. package/dist/unpkg/prod-deprecated/hooks-DGvi9teJ.js +26 -0
  199. package/dist/unpkg/prod-deprecated/index.js +481 -0
  200. package/dist/unpkg/prod-deprecated/promise-state-CYvoIPna.js +8458 -0
  201. package/dist/unpkg/prod-deprecated/reactive/-private.js +1 -0
  202. package/dist/unpkg/prod-deprecated/reactive.js +126 -0
  203. package/dist/unpkg/prod-deprecated/request-CN2LxbYX.js +437 -0
  204. package/dist/unpkg/prod-deprecated/request.js +1 -0
  205. package/dist/unpkg/prod-deprecated/store/-private.js +89 -0
  206. package/dist/unpkg/prod-deprecated/store.js +437 -0
  207. package/dist/unpkg/prod-deprecated/types/-private.js +49 -0
  208. package/dist/unpkg/prod-deprecated/types/cache/aliases.js +0 -0
  209. package/dist/unpkg/prod-deprecated/types/cache/change.js +0 -0
  210. package/dist/unpkg/prod-deprecated/types/cache/mutations.js +0 -0
  211. package/dist/unpkg/prod-deprecated/types/cache/operations.js +0 -0
  212. package/dist/unpkg/prod-deprecated/types/cache/relationship.js +0 -0
  213. package/dist/unpkg/prod-deprecated/types/cache.js +0 -0
  214. package/dist/unpkg/prod-deprecated/types/graph.js +0 -0
  215. package/dist/unpkg/prod-deprecated/types/identifier.js +61 -0
  216. package/dist/unpkg/prod-deprecated/types/json/raw.js +0 -0
  217. package/dist/unpkg/prod-deprecated/types/params.js +0 -0
  218. package/dist/unpkg/prod-deprecated/types/record.js +191 -0
  219. package/dist/unpkg/prod-deprecated/types/request.js +77 -0
  220. package/dist/unpkg/prod-deprecated/types/runtime.js +34 -0
  221. package/dist/unpkg/prod-deprecated/types/schema/concepts.js +0 -0
  222. package/dist/unpkg/prod-deprecated/types/schema/fields.js +505 -0
  223. package/dist/unpkg/prod-deprecated/types/schema/fields.type-test.js +0 -0
  224. package/dist/unpkg/prod-deprecated/types/schema/schema-service.js +0 -0
  225. package/dist/unpkg/prod-deprecated/types/spec/document.js +0 -0
  226. package/dist/unpkg/prod-deprecated/types/spec/error.js +0 -0
  227. package/dist/unpkg/prod-deprecated/types/spec/json-api-raw.js +0 -0
  228. package/dist/unpkg/prod-deprecated/types/symbols.js +84 -0
  229. package/dist/unpkg/prod-deprecated/types/utils.js +0 -0
  230. package/dist/unpkg/prod-deprecated/types.js +0 -0
  231. package/dist/unpkg/prod-deprecated/utils/string.js +72 -0
  232. package/logos/README.md +2 -2
  233. package/logos/logo-yellow-slab.svg +1 -0
  234. package/logos/word-mark-black.svg +1 -0
  235. package/logos/word-mark-white.svg +1 -0
  236. package/package.json +11 -3
  237. package/logos/NCC-1701-a-blue.svg +0 -4
  238. package/logos/NCC-1701-a-gold.svg +0 -4
  239. package/logos/NCC-1701-a-gold_100.svg +0 -1
  240. package/logos/NCC-1701-a-gold_base-64.txt +0 -1
  241. package/logos/NCC-1701-a.svg +0 -4
  242. package/logos/docs-badge.svg +0 -2
  243. package/logos/ember-data-logo-dark.svg +0 -12
  244. package/logos/ember-data-logo-light.svg +0 -12
  245. package/logos/social1.png +0 -0
  246. package/logos/social2.png +0 -0
  247. package/logos/warp-drive-logo-dark.svg +0 -4
  248. package/logos/warp-drive-logo-gold.svg +0 -4
@@ -0,0 +1,437 @@
1
+ import { LRUCache } from './utils/string.js';
2
+
3
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
4
+
5
+ /**
6
+ * Interface of a parsed Cache-Control header value.
7
+ *
8
+ * - [MDN Cache-Control Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control)
9
+ */
10
+
11
+ const NUMERIC_KEYS = new Set(['max-age', 's-maxage', 'stale-if-error', 'stale-while-revalidate']);
12
+
13
+ /**
14
+ * Parses a string Cache-Control header value into an object with the following structure:
15
+ *
16
+ * ```ts
17
+ * interface CacheControlValue {
18
+ * immutable?: boolean;
19
+ * 'max-age'?: number;
20
+ * 'must-revalidate'?: boolean;
21
+ * 'must-understand'?: boolean;
22
+ * 'no-cache'?: boolean;
23
+ * 'no-store'?: boolean;
24
+ * 'no-transform'?: boolean;
25
+ * 'only-if-cached'?: boolean;
26
+ * private?: boolean;
27
+ * 'proxy-revalidate'?: boolean;
28
+ * public?: boolean;
29
+ * 's-maxage'?: number;
30
+ * 'stale-if-error'?: number;
31
+ * 'stale-while-revalidate'?: number;
32
+ * }
33
+ * ```
34
+ *
35
+ * See also {@link CacheControlValue} and [Response Directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control#response_directives)
36
+ *
37
+ * @public
38
+ */
39
+ function parseCacheControl(header) {
40
+ return CACHE_CONTROL_CACHE.get(header);
41
+ }
42
+ const CACHE_CONTROL_CACHE = new LRUCache(header => {
43
+ let key = '';
44
+ let value = '';
45
+ let isParsingKey = true;
46
+ const cacheControlValue = {};
47
+ for (let i = 0; i < header.length; i++) {
48
+ const char = header.charAt(i);
49
+ if (char === ',') {
50
+ isParsingKey = true;
51
+ // @ts-expect-error TS incorrectly thinks that optional keys must have a type that includes undefined
52
+ cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true;
53
+ key = '';
54
+ value = '';
55
+ continue;
56
+ } else if (char === '=') {
57
+ isParsingKey = false;
58
+ } else if (char === ' ' || char === `\t` || char === `\n`) {
59
+ continue;
60
+ } else if (isParsingKey) {
61
+ key += char;
62
+ } else {
63
+ value += char;
64
+ }
65
+ if (i === header.length - 1) {
66
+ // @ts-expect-error TS incorrectly thinks that optional keys must have a type that includes undefined
67
+ cacheControlValue[key] = NUMERIC_KEYS.has(key) ? parseCacheControlValue(value) : true;
68
+ }
69
+ }
70
+ return cacheControlValue;
71
+ }, 200);
72
+ function parseCacheControlValue(stringToParse) {
73
+ const parsedValue = Number.parseInt(stringToParse);
74
+ if (Number.isNaN(parsedValue) || parsedValue < 0) {
75
+ return 0;
76
+ }
77
+ return parsedValue;
78
+ }
79
+ function isExpired(cacheKey, request, config) {
80
+ const {
81
+ constraints
82
+ } = config;
83
+ if (constraints?.isExpired) {
84
+ const result = constraints.isExpired(request);
85
+ if (result !== null) {
86
+ return result;
87
+ }
88
+ }
89
+ const {
90
+ headers
91
+ } = request.response;
92
+ if (!headers) {
93
+ // if we have no headers then both the headers based expiration
94
+ // and the time based expiration will be considered expired
95
+ return true;
96
+ }
97
+
98
+ // check for X-WarpDrive-Expires
99
+ const now = Date.now();
100
+ const date = headers.get('Date');
101
+ if (constraints?.headers) {
102
+ if (constraints.headers['X-WarpDrive-Expires']) {
103
+ const xWarpDriveExpires = headers.get('X-WarpDrive-Expires');
104
+ if (xWarpDriveExpires) {
105
+ const expirationTime = new Date(xWarpDriveExpires).getTime();
106
+ const result = now >= expirationTime;
107
+ return result;
108
+ }
109
+ }
110
+
111
+ // check for Cache-Control
112
+ if (constraints.headers['Cache-Control']) {
113
+ const cacheControl = headers.get('Cache-Control');
114
+ const age = headers.get('Age');
115
+ if (cacheControl && age && date) {
116
+ const cacheControlValue = parseCacheControl(cacheControl);
117
+
118
+ // max-age and s-maxage are stored in
119
+ const maxAge = cacheControlValue['max-age'] || cacheControlValue['s-maxage'];
120
+ if (maxAge) {
121
+ // age is stored in seconds
122
+ const ageValue = parseInt(age, 10);
123
+ if (!Number.isNaN(ageValue) && ageValue >= 0) {
124
+ const dateValue = new Date(date).getTime();
125
+ const expirationTime = dateValue + (maxAge - ageValue) * 1000;
126
+ const result = now >= expirationTime;
127
+ return result;
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ // check for Expires
134
+ if (constraints.headers.Expires) {
135
+ const expires = headers.get('Expires');
136
+ if (expires) {
137
+ const expirationTime = new Date(expires).getTime();
138
+ const result = now >= expirationTime;
139
+ return result;
140
+ }
141
+ }
142
+ }
143
+
144
+ // check for Date
145
+ if (!date) {
146
+ return true;
147
+ }
148
+ let expirationTime = config.apiCacheHardExpires;
149
+ const time = new Date(date).getTime();
150
+ const deadline = time + expirationTime;
151
+ const result = now >= deadline;
152
+ return result;
153
+ }
154
+
155
+ /**
156
+ * The constraint options for {@link PolicyConfig.constraints}
157
+ */
158
+
159
+ /**
160
+ * The configuration options for the {@link DefaultCachePolicy}
161
+ *
162
+ * ```ts [app/services/store.ts]
163
+ * import { Store } from '@warp-drive/core';
164
+ * import { DefaultCachePolicy } from '@warp-drive/core/store'; // [!code focus]
165
+ *
166
+ * export default class AppStore extends Store {
167
+ * lifetimes = new DefaultCachePolicy({ // [!code focus:3]
168
+ * // ... PolicyConfig Settings ... //
169
+ * });
170
+ * }
171
+ * ```
172
+ *
173
+ */
174
+
175
+ /**
176
+ * A basic {@link CachePolicy} that can be added to the Store service.
177
+ *
178
+ * ```ts [app/services/store.ts]
179
+ * import { Store } from '@warp-drive/core';
180
+ * import { DefaultCachePolicy } from '@warp-drive/core/store'; // [!code focus]
181
+ *
182
+ * export default class AppStore extends Store {
183
+ * lifetimes = new DefaultCachePolicy({ // [!code focus:5]
184
+ * apiCacheSoftExpires: 30_000,
185
+ * apiCacheHardExpires: 60_000,
186
+ * // ... Other PolicyConfig Settings ... //
187
+ * });
188
+ * }
189
+ * ```
190
+ *
191
+ * :::tip 💡 TIP
192
+ * Date headers do not have millisecond precision, so expiration times should
193
+ * generally be larger than 1000ms.
194
+ * :::
195
+ *
196
+ * See also {@link PolicyConfig} for configuration options.
197
+ *
198
+ * ### The Mechanics
199
+ *
200
+ * This policy determines staleness based on various configurable constraints falling back to a simple
201
+ * check of the time elapsed since the request was last received from the API using the `date` header
202
+ * from the last response.
203
+ *
204
+ * :::tip 💡 TIP
205
+ * The {@link Fetch} handler provided by `@warp-drive/core` will automatically
206
+ * add the `date` header to responses if it is not present.
207
+ * :::
208
+ *
209
+ * - For manual override of reload see {@link CacheOptions.reload | cacheOptions.reload}
210
+ * - For manual override of background reload see {@link CacheOptions.backgroundReload | cacheOptions.backgroundReload}
211
+ *
212
+ * In order expiration is determined by:
213
+ *
214
+ * ```md
215
+ * Is explicitly invalidated by `cacheOptions.reload`
216
+ * ↳ (if falsey) if the request has been explicitly invalidated
217
+ * since the last request (see Automatic Invalidation below)
218
+ * ↳ (if false) (If Active) isExpired function
219
+ * ↳ (if null) (If Active) X-WarpDrive-Expires header
220
+ * ↳ (if null) (If Active) Cache-Control header
221
+ * ↳ (if null) (If Active) Expires header
222
+ * ↳ (if null) Date header + apiCacheHardExpires < current time
223
+ *
224
+ * -- <if above is false, a background request is issued if> --
225
+ *
226
+ * ↳ is invalidated by `cacheOptions.backgroundReload`
227
+ * ↳ (if falsey) Date header + apiCacheSoftExpires < current time
228
+ * ```
229
+ *
230
+ * ### Automatic Invalidation / Entanglement
231
+ *
232
+ * It also invalidates any request with an {@link RequestInfo.op | OpCode} of `"query"`
233
+ * for which {@link CacheOptions.types | cacheOptions.types} was provided
234
+ * when a request with an `OpCode` of `"createRecord"` is successful and also includes
235
+ * a matching type in its own `cacheOptions.types` array.
236
+
237
+ * :::tip 💡 TIP
238
+ * Abstracting this behavior via builders is recommended to ensure consistency.
239
+ * :::
240
+ *
241
+ * ### Testing
242
+ *
243
+ * In Testing environments:
244
+ *
245
+ * - `apiCacheSoftExpires` will always be `false`
246
+ * - `apiCacheHardExpires` will use the `apiCacheSoftExpires` value.
247
+ *
248
+ * This helps reduce flakiness and produce predictably rendered results in test suites.
249
+ *
250
+ * Requests that specifically set `cacheOptions.backgroundReload = true` will
251
+ * still be background reloaded in tests.
252
+ *
253
+ * This behavior can be opted out of by setting `disableTestOptimization = true`
254
+ * in the policy config.
255
+ *
256
+ * @public
257
+ */
258
+ class DefaultCachePolicy {
259
+ /**
260
+ * @internal
261
+ */
262
+
263
+ /**
264
+ * @internal
265
+ */
266
+
267
+ /**
268
+ * @internal
269
+ */
270
+ _getStore(store) {
271
+ let set = this._stores.get(store);
272
+ if (!set) {
273
+ set = {
274
+ invalidated: new Set(),
275
+ types: new Map()
276
+ };
277
+ this._stores.set(store, set);
278
+ }
279
+ return set;
280
+ }
281
+ constructor(config) {
282
+ this._stores = new WeakMap();
283
+ const _config = arguments.length === 1 ? config : arguments[1];
284
+ this.config = _config;
285
+ }
286
+
287
+ /**
288
+ * Invalidate a request by its CacheKey for the given store instance.
289
+ *
290
+ * While the store argument may seem redundant, the CachePolicy
291
+ * is designed to be shared across multiple stores / forks
292
+ * of the store.
293
+ *
294
+ * ```ts
295
+ * store.lifetimes.invalidateRequest(store, cacheKey);
296
+ * ```
297
+ *
298
+ * @public
299
+ */
300
+ invalidateRequest(cacheKey, store) {
301
+ this._getStore(store).invalidated.add(cacheKey);
302
+ }
303
+
304
+ /**
305
+ * Invalidate all requests associated to a specific type
306
+ * for a given store instance.
307
+ *
308
+ * While the store argument may seem redundant, the CachePolicy
309
+ * is designed to be shared across multiple stores / forks
310
+ * of the store.
311
+ *
312
+ * This invalidation is done automatically when using this service
313
+ * for both the {@link CacheHandler} and the [NetworkHandler](/api/@warp-drive/legacy/compat/variables/LegacyNetworkHandler).
314
+ *
315
+ * ```ts
316
+ * store.lifetimes.invalidateRequestsForType(store, 'person');
317
+ * ```
318
+ *
319
+ * @public
320
+ */
321
+ invalidateRequestsForType(type, store) {
322
+ const storeCache = this._getStore(store);
323
+ const set = storeCache.types.get(type);
324
+ const notifications = store.notifications;
325
+ if (set) {
326
+ // TODO batch notifications
327
+ set.forEach(id => {
328
+ storeCache.invalidated.add(id);
329
+ // @ts-expect-error
330
+ notifications.notify(id, 'invalidated', null);
331
+ });
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Invoked when a request has been fulfilled from the configured request handlers.
337
+ * This is invoked by the CacheHandler for both foreground and background requests
338
+ * once the cache has been updated.
339
+ *
340
+ * Note, this is invoked by the {@link CacheHandler} regardless of whether
341
+ * the request has a cache-key.
342
+ *
343
+ * This method should not be invoked directly by consumers.
344
+ *
345
+ * @public
346
+ */
347
+ didRequest(request, response, cacheKey, store) {
348
+ // if this is a successful createRecord request, invalidate the cacheKey for the type
349
+ if (request.op === 'createRecord') {
350
+ const statusNumber = response?.status ?? 0;
351
+ if (statusNumber >= 200 && statusNumber < 400) {
352
+ const types = new Set(request.records?.map(r => r.type));
353
+ const additionalTypes = request.cacheOptions?.types;
354
+ additionalTypes?.forEach(type => {
355
+ types.add(type);
356
+ });
357
+ types.forEach(type => {
358
+ this.invalidateRequestsForType(type, store);
359
+ });
360
+ }
361
+
362
+ // add this document's cacheKey to a map for all associated types
363
+ // it is recommended to only use this for queries
364
+ } else if (cacheKey && request.cacheOptions?.types?.length) {
365
+ const storeCache = this._getStore(store);
366
+ request.cacheOptions?.types.forEach(type => {
367
+ const set = storeCache.types.get(type);
368
+ if (set) {
369
+ set.add(cacheKey);
370
+ storeCache.invalidated.delete(cacheKey);
371
+ } else {
372
+ storeCache.types.set(type, new Set([cacheKey]));
373
+ }
374
+ });
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Invoked to determine if the request may be fulfilled from cache
380
+ * if possible.
381
+ *
382
+ * Note, this is only invoked by the {@link CacheHandler} if the request has
383
+ * a cache-key.
384
+ *
385
+ * If no cache entry is found or the entry is hard expired,
386
+ * the request will be fulfilled from the configured request handlers
387
+ * and the cache will be updated before returning the response.
388
+ *
389
+ * @public
390
+ * @return true if the request is considered hard expired
391
+ */
392
+ isHardExpired(cacheKey, store) {
393
+ // if we are explicitly invalidated, we are hard expired
394
+ const storeCache = this._getStore(store);
395
+ if (storeCache.invalidated.has(cacheKey)) {
396
+ return true;
397
+ }
398
+ const cache = store.cache;
399
+ const cached = cache.peekRequest(cacheKey);
400
+ if (!cached?.response) {
401
+ return true;
402
+ }
403
+ return isExpired(cacheKey, cached, this.config);
404
+ }
405
+
406
+ /**
407
+ * Invoked if `isHardExpired` is false to determine if the request
408
+ * should be update behind the scenes if cache data is already available.
409
+ *
410
+ * Note, this is only invoked by the {@link CacheHandler} if the request has
411
+ * a cache-key.
412
+ *
413
+ * If true, the request will be fulfilled from cache while a backgrounded
414
+ * request is made to update the cache via the configured request handlers.
415
+ *
416
+ * @public
417
+ * @return true if the request is considered soft expired
418
+ */
419
+ isSoftExpired(cacheKey, store) {
420
+ const cache = store.cache;
421
+ const cached = cache.peekRequest(cacheKey);
422
+ if (cached?.response) {
423
+ const date = cached.response.headers.get('date');
424
+ if (!date) {
425
+ return true;
426
+ } else {
427
+ const time = new Date(date).getTime();
428
+ const now = Date.now();
429
+ const deadline = time + this.config.apiCacheSoftExpires;
430
+ const result = now >= deadline;
431
+ return result;
432
+ }
433
+ }
434
+ return true;
435
+ }
436
+ }
437
+ export { DefaultCachePolicy, parseCacheControl };
@@ -0,0 +1,49 @@
1
+ const name = "@warp-drive/core";
2
+ const version = "5.8.0-alpha.40";
3
+
4
+ // in testing mode, we utilize globals to ensure only one copy exists of
5
+ // these maps, due to bugs in ember-auto-import
6
+
7
+ const GlobalRef = globalThis;
8
+ const UniversalCache = GlobalRef.__warpDrive_universalCache = GlobalRef.__warpDrive_universalCache ?? {};
9
+
10
+ // in order to support mirror packages, we ensure that each
11
+ // unique package name has its own global cache
12
+ GlobalRef[name] = GlobalRef[name] ?? {
13
+ __version: version
14
+ };
15
+ const GlobalSink = GlobalRef[name];
16
+ const ModuleScopedCaches = GlobalSink.__warpDrive_ModuleScopedCaches ?? {};
17
+ {
18
+ if (GlobalSink.__warpDrive_hasOtherCopy) {
19
+ throw new Error('Multiple copies of WarpDrive detected, the application will malfunction.');
20
+ }
21
+ GlobalSink.__warpDrive_hasOtherCopy = true;
22
+ }
23
+ function getOrSetGlobal(key, value) {
24
+ {
25
+ return value;
26
+ }
27
+ }
28
+ function peekTransient(key) {
29
+ const globalKey = `(transient) ${key}`;
30
+ return ModuleScopedCaches[globalKey] ?? null;
31
+ }
32
+ function setTransient(key, value) {
33
+ const globalKey = `(transient) ${key}`;
34
+ return ModuleScopedCaches[globalKey] = value;
35
+ }
36
+ function getOrSetUniversal(key, value) {
37
+ {
38
+ return value;
39
+ }
40
+ }
41
+ function peekUniversalTransient(key) {
42
+ const globalKey = `(transient) ${key}`;
43
+ return UniversalCache[globalKey] ?? null;
44
+ }
45
+ function setUniversalTransient(key, value) {
46
+ const globalKey = `(transient) ${key}`;
47
+ return UniversalCache[globalKey] = value;
48
+ }
49
+ export { getOrSetGlobal, getOrSetUniversal, peekTransient, peekUniversalTransient, setTransient, setUniversalTransient };
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,61 @@
1
+ // provided for additional debuggability
2
+ const DEBUG_CLIENT_ORIGINATED = Symbol('record-originated-on-client');
3
+ const DEBUG_KEY_TYPE = Symbol('key-type');
4
+ const DEBUG_STALE_CACHE_OWNER = Symbol('warpDriveStaleCache');
5
+ function ProdSymbol(str, debugStr) {
6
+ return str;
7
+ }
8
+
9
+ // also present in production
10
+ const CACHE_OWNER = ProdSymbol('__$co');
11
+
12
+ /**
13
+ * A referentially stable object with a unique string (lid) that can be used
14
+ * as a reference to request data in the cache.
15
+ *
16
+ * Only requests that are assigned a RequestKey are retrievable/replayable from
17
+ * the cache, though requests without RequestKeys may still update cache state.
18
+ *
19
+ * @public
20
+ */
21
+
22
+ /** @deprecated use {@link RequestKey} */
23
+
24
+ /**
25
+ * Used when an ResourceKey is known to be the stable version
26
+ */
27
+
28
+ /**
29
+ * Used when a ResourceKey was not created locally as part
30
+ * of a call to store.createRecord
31
+ *
32
+ * Distinguishing between this ResourceKey and one for a client created
33
+ * resource that was created with an ID is generally speaking not possible
34
+ * at runtime, so anything with an ID typically narrows to this.
35
+ */
36
+
37
+ /** @deprecated use {@link PersistedResourceKey} */
38
+
39
+ /**
40
+ * Used when a ResourceKey was created locally
41
+ * (by a call to store.createRecord).
42
+ *
43
+ * It is possible in rare circumstances to have a ResourceKey
44
+ * that is not for a new record but does not have an ID. This would
45
+ * happen if a user intentionally created one for use with a secondary-index
46
+ * prior to the record having been fully loaded.
47
+ */
48
+
49
+ /**
50
+ * A referentially stable object with a unique string (lid) that can be used
51
+ * as a reference to data in the cache.
52
+ *
53
+ * Every resource has a unique ResourceKey, and ResourceKeys may refer
54
+ * to data that has never been loaded (for instance, in an async relationship).
55
+ *
56
+ * @public
57
+ */
58
+
59
+ /** @deprecated use {@link ResourceKey} */
60
+
61
+ export { CACHE_OWNER, DEBUG_CLIENT_ORIGINATED, DEBUG_KEY_TYPE, DEBUG_STALE_CACHE_OWNER };
File without changes
File without changes