@warp-drive/core 5.8.0-alpha.9 → 5.8.0-beta.1

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 (258) hide show
  1. package/README.md +22 -38
  2. package/declarations/configure.d.ts +1 -1
  3. package/declarations/graph/-private/-edge-definition.d.ts +12 -2
  4. package/declarations/index.d.ts +14 -9
  5. package/declarations/reactive/-private/default-mode.d.ts +1 -1
  6. package/declarations/reactive/-private/fields/extension.d.ts +1 -1
  7. package/declarations/reactive/-private/fields/managed-array.d.ts +2 -2
  8. package/declarations/reactive/-private/fields/managed-object.d.ts +1 -1
  9. package/declarations/reactive/-private/record.d.ts +10 -1
  10. package/declarations/reactive/-private.d.ts +1 -0
  11. package/declarations/reactive.d.ts +11 -7
  12. package/declarations/request/-private/types.d.ts +1 -1
  13. package/declarations/signals/-leaked.d.ts +2 -0
  14. package/declarations/signals/-private.d.ts +6 -0
  15. package/declarations/{store/-private/new-core-tmp → signals}/promise-state.d.ts +1 -1
  16. package/declarations/{store/-private/new-core-tmp → signals}/request-state.d.ts +6 -6
  17. package/declarations/{store/-private/new-core-tmp → signals}/request-subscription.d.ts +4 -4
  18. package/declarations/store/-private/cache-handler/types.d.ts +2 -16
  19. package/declarations/store/-private/caches/instance-cache.d.ts +1 -1
  20. package/declarations/store/-private/managers/cache-manager.d.ts +1 -14
  21. package/declarations/store/-private/managers/notification-manager.d.ts +1 -1
  22. package/declarations/store/-private/record-arrays/legacy-many-array.d.ts +1 -1
  23. package/declarations/store/-private/record-arrays/resource-array.d.ts +1 -1
  24. package/declarations/store/-private/store-service.d.ts +2 -2
  25. package/declarations/store/-private.d.ts +0 -6
  26. package/declarations/store/deprecated/-private.d.ts +2 -2
  27. package/declarations/store/deprecated/store.d.ts +1 -1
  28. package/declarations/store.d.ts +1 -0
  29. package/declarations/types/cache.d.ts +2 -2
  30. package/declarations/types/record.d.ts +132 -0
  31. package/declarations/types/request.d.ts +22 -8
  32. package/declarations/types/schema/fields.d.ts +26 -13
  33. package/declarations/types/schema/schema-service.d.ts +4 -4
  34. package/declarations/types/spec/document.d.ts +34 -0
  35. package/dist/configure-DPUFCemT.js +1940 -0
  36. package/dist/configure.js +2 -1
  37. package/dist/{request-oqoLC9rz.js → future-BKkJJkj7.js} +1 -48
  38. package/dist/graph/-private.js +15 -5
  39. package/dist/{index-B1cSRj-N.js → index-CQP2NSqg.js} +63 -1812
  40. package/dist/index.js +5 -5
  41. package/dist/reactive/-private.js +1 -1
  42. package/dist/reactive.js +4 -129
  43. package/dist/request.js +49 -1
  44. package/dist/signals/-leaked.js +1 -0
  45. package/dist/store/-private.js +1 -2
  46. package/dist/symbols-3C1OkYtZ.js +39 -0
  47. package/dist/types/-private.js +1 -1
  48. package/dist/types/record.js +127 -0
  49. package/dist/types/request.js +11 -7
  50. package/dist/unpkg/dev/-leaked-Co0EI6Go.js +1939 -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.js +1 -0
  59. package/dist/unpkg/dev/future-DFfOzSoe.js +672 -0
  60. package/dist/unpkg/dev/graph/-private.js +3132 -0
  61. package/dist/unpkg/dev/index-BzcBOnw9.js +9392 -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 +3 -0
  65. package/dist/unpkg/dev/request.js +49 -0
  66. package/dist/unpkg/dev/runtime-E1M51_-O.js +135 -0
  67. package/dist/unpkg/dev/signals/-leaked.js +1 -0
  68. package/dist/unpkg/dev/store/-private.js +55 -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/-leaked-DjMeRqdU.js +1939 -0
  96. package/dist/unpkg/dev-deprecated/-private-3C1OkYtZ.js +39 -0
  97. package/dist/unpkg/dev-deprecated/build-config/babel-macros.js +1 -0
  98. package/dist/unpkg/dev-deprecated/build-config/canary-features.js +1 -0
  99. package/dist/unpkg/dev-deprecated/build-config/debugging.js +1 -0
  100. package/dist/unpkg/dev-deprecated/build-config/deprecations.js +1 -0
  101. package/dist/unpkg/dev-deprecated/build-config/env.js +1 -0
  102. package/dist/unpkg/dev-deprecated/build-config/macros.js +1 -0
  103. package/dist/unpkg/dev-deprecated/build-config.js +1 -0
  104. package/dist/unpkg/dev-deprecated/configure.js +1 -0
  105. package/dist/unpkg/dev-deprecated/future-DFfOzSoe.js +672 -0
  106. package/dist/unpkg/dev-deprecated/graph/-private.js +3327 -0
  107. package/dist/unpkg/dev-deprecated/index-6TnTv-WG.js +10007 -0
  108. package/dist/unpkg/dev-deprecated/index.js +5 -0
  109. package/dist/unpkg/dev-deprecated/reactive/-private.js +1 -0
  110. package/dist/unpkg/dev-deprecated/reactive.js +3 -0
  111. package/dist/unpkg/dev-deprecated/request.js +49 -0
  112. package/dist/unpkg/dev-deprecated/runtime-DAu5b0IR.js +135 -0
  113. package/dist/unpkg/dev-deprecated/signals/-leaked.js +1 -0
  114. package/dist/unpkg/dev-deprecated/store/-private.js +1 -0
  115. package/dist/unpkg/dev-deprecated/store.js +558 -0
  116. package/dist/unpkg/dev-deprecated/types/-private.js +69 -0
  117. package/dist/unpkg/dev-deprecated/types/cache/aliases.js +0 -0
  118. package/dist/unpkg/dev-deprecated/types/cache/change.js +0 -0
  119. package/dist/unpkg/dev-deprecated/types/cache/mutations.js +0 -0
  120. package/dist/unpkg/dev-deprecated/types/cache/operations.js +0 -0
  121. package/dist/unpkg/dev-deprecated/types/cache/relationship.js +0 -0
  122. package/dist/unpkg/dev-deprecated/types/cache.js +0 -0
  123. package/dist/unpkg/dev-deprecated/types/graph.js +0 -0
  124. package/dist/unpkg/dev-deprecated/types/identifier.js +61 -0
  125. package/dist/unpkg/dev-deprecated/types/json/raw.js +0 -0
  126. package/dist/unpkg/dev-deprecated/types/params.js +0 -0
  127. package/dist/unpkg/dev-deprecated/types/record.js +191 -0
  128. package/dist/unpkg/dev-deprecated/types/request.js +77 -0
  129. package/dist/unpkg/dev-deprecated/types/runtime.js +34 -0
  130. package/dist/unpkg/dev-deprecated/types/schema/concepts.js +0 -0
  131. package/dist/unpkg/dev-deprecated/types/schema/fields.js +505 -0
  132. package/dist/unpkg/dev-deprecated/types/schema/fields.type-test.js +0 -0
  133. package/dist/unpkg/dev-deprecated/types/schema/schema-service.js +0 -0
  134. package/dist/unpkg/dev-deprecated/types/spec/document.js +0 -0
  135. package/dist/unpkg/dev-deprecated/types/spec/error.js +0 -0
  136. package/dist/unpkg/dev-deprecated/types/spec/json-api-raw.js +0 -0
  137. package/dist/unpkg/dev-deprecated/types/symbols.js +84 -0
  138. package/dist/unpkg/dev-deprecated/types/utils.js +0 -0
  139. package/dist/unpkg/dev-deprecated/types.js +0 -0
  140. package/dist/unpkg/dev-deprecated/utils/string.js +91 -0
  141. package/dist/unpkg/prod/-leaked-DUONXQDB.js +1676 -0
  142. package/dist/unpkg/prod/-private-sql1_mdx.js +39 -0
  143. package/dist/unpkg/prod/build-config/babel-macros.js +1 -0
  144. package/dist/unpkg/prod/build-config/canary-features.js +1 -0
  145. package/dist/unpkg/prod/build-config/debugging.js +1 -0
  146. package/dist/unpkg/prod/build-config/deprecations.js +1 -0
  147. package/dist/unpkg/prod/build-config/env.js +1 -0
  148. package/dist/unpkg/prod/build-config/macros.js +1 -0
  149. package/dist/unpkg/prod/build-config.js +1 -0
  150. package/dist/unpkg/prod/configure.js +2 -0
  151. package/dist/unpkg/prod/graph/-private.js +2235 -0
  152. package/dist/unpkg/prod/handler-EU_8ncB2.js +1619 -0
  153. package/dist/unpkg/prod/index.js +483 -0
  154. package/dist/unpkg/prod/promise-cache-DIT8Ypjq.js +19 -0
  155. package/dist/unpkg/prod/reactive/-private.js +1 -0
  156. package/dist/unpkg/prod/reactive.js +30 -0
  157. package/dist/unpkg/prod/request-BrJSCG6r.js +421 -0
  158. package/dist/unpkg/prod/request.js +2 -0
  159. package/dist/unpkg/prod/schema-BSkHyoWz.js +5219 -0
  160. package/dist/unpkg/prod/signals/-leaked.js +1 -0
  161. package/dist/unpkg/prod/store/-private.js +126 -0
  162. package/dist/unpkg/prod/store.js +437 -0
  163. package/dist/unpkg/prod/types/-private.js +49 -0
  164. package/dist/unpkg/prod/types/cache/aliases.js +0 -0
  165. package/dist/unpkg/prod/types/cache/change.js +0 -0
  166. package/dist/unpkg/prod/types/cache/mutations.js +0 -0
  167. package/dist/unpkg/prod/types/cache/operations.js +0 -0
  168. package/dist/unpkg/prod/types/cache/relationship.js +0 -0
  169. package/dist/unpkg/prod/types/cache.js +0 -0
  170. package/dist/unpkg/prod/types/graph.js +0 -0
  171. package/dist/unpkg/prod/types/identifier.js +61 -0
  172. package/dist/unpkg/prod/types/json/raw.js +0 -0
  173. package/dist/unpkg/prod/types/params.js +0 -0
  174. package/dist/unpkg/prod/types/record.js +191 -0
  175. package/dist/unpkg/prod/types/request.js +77 -0
  176. package/dist/unpkg/prod/types/runtime.js +34 -0
  177. package/dist/unpkg/prod/types/schema/concepts.js +0 -0
  178. package/dist/unpkg/prod/types/schema/fields.js +505 -0
  179. package/dist/unpkg/prod/types/schema/fields.type-test.js +0 -0
  180. package/dist/unpkg/prod/types/schema/schema-service.js +0 -0
  181. package/dist/unpkg/prod/types/spec/document.js +0 -0
  182. package/dist/unpkg/prod/types/spec/error.js +0 -0
  183. package/dist/unpkg/prod/types/spec/json-api-raw.js +0 -0
  184. package/dist/unpkg/prod/types/symbols.js +84 -0
  185. package/dist/unpkg/prod/types/utils.js +0 -0
  186. package/dist/unpkg/prod/types.js +0 -0
  187. package/dist/unpkg/prod/utils/string.js +72 -0
  188. package/dist/unpkg/prod-deprecated/-leaked-DRNv9VIX.js +1676 -0
  189. package/dist/unpkg/prod-deprecated/-private-3C1OkYtZ.js +39 -0
  190. package/dist/unpkg/prod-deprecated/build-config/babel-macros.js +1 -0
  191. package/dist/unpkg/prod-deprecated/build-config/canary-features.js +1 -0
  192. package/dist/unpkg/prod-deprecated/build-config/debugging.js +1 -0
  193. package/dist/unpkg/prod-deprecated/build-config/deprecations.js +1 -0
  194. package/dist/unpkg/prod-deprecated/build-config/env.js +1 -0
  195. package/dist/unpkg/prod-deprecated/build-config/macros.js +1 -0
  196. package/dist/unpkg/prod-deprecated/build-config.js +1 -0
  197. package/dist/unpkg/prod-deprecated/configure.js +2 -0
  198. package/dist/unpkg/prod-deprecated/graph/-private.js +2408 -0
  199. package/dist/unpkg/prod-deprecated/handler-CCIu4sQ3.js +334 -0
  200. package/dist/unpkg/prod-deprecated/hooks-Dv4Np0MY.js +26 -0
  201. package/dist/unpkg/prod-deprecated/index.js +483 -0
  202. package/dist/unpkg/prod-deprecated/promise-cache-DIT8Ypjq.js +19 -0
  203. package/dist/unpkg/prod-deprecated/reactive/-private.js +1 -0
  204. package/dist/unpkg/prod-deprecated/reactive.js +5 -0
  205. package/dist/unpkg/prod-deprecated/request-BrJSCG6r.js +421 -0
  206. package/dist/unpkg/prod-deprecated/request.js +2 -0
  207. package/dist/unpkg/prod-deprecated/schema-CJcjHv0E.js +6939 -0
  208. package/dist/unpkg/prod-deprecated/signals/-leaked.js +1 -0
  209. package/dist/unpkg/prod-deprecated/store/-private.js +88 -0
  210. package/dist/unpkg/prod-deprecated/store.js +437 -0
  211. package/dist/unpkg/prod-deprecated/types/-private.js +49 -0
  212. package/dist/unpkg/prod-deprecated/types/cache/aliases.js +0 -0
  213. package/dist/unpkg/prod-deprecated/types/cache/change.js +0 -0
  214. package/dist/unpkg/prod-deprecated/types/cache/mutations.js +0 -0
  215. package/dist/unpkg/prod-deprecated/types/cache/operations.js +0 -0
  216. package/dist/unpkg/prod-deprecated/types/cache/relationship.js +0 -0
  217. package/dist/unpkg/prod-deprecated/types/cache.js +0 -0
  218. package/dist/unpkg/prod-deprecated/types/graph.js +0 -0
  219. package/dist/unpkg/prod-deprecated/types/identifier.js +61 -0
  220. package/dist/unpkg/prod-deprecated/types/json/raw.js +0 -0
  221. package/dist/unpkg/prod-deprecated/types/params.js +0 -0
  222. package/dist/unpkg/prod-deprecated/types/record.js +191 -0
  223. package/dist/unpkg/prod-deprecated/types/request.js +77 -0
  224. package/dist/unpkg/prod-deprecated/types/runtime.js +34 -0
  225. package/dist/unpkg/prod-deprecated/types/schema/concepts.js +0 -0
  226. package/dist/unpkg/prod-deprecated/types/schema/fields.js +505 -0
  227. package/dist/unpkg/prod-deprecated/types/schema/fields.type-test.js +0 -0
  228. package/dist/unpkg/prod-deprecated/types/schema/schema-service.js +0 -0
  229. package/dist/unpkg/prod-deprecated/types/spec/document.js +0 -0
  230. package/dist/unpkg/prod-deprecated/types/spec/error.js +0 -0
  231. package/dist/unpkg/prod-deprecated/types/spec/json-api-raw.js +0 -0
  232. package/dist/unpkg/prod-deprecated/types/symbols.js +84 -0
  233. package/dist/unpkg/prod-deprecated/types/utils.js +0 -0
  234. package/dist/unpkg/prod-deprecated/types.js +0 -0
  235. package/dist/unpkg/prod-deprecated/utils/string.js +72 -0
  236. package/logos/README.md +2 -2
  237. package/logos/logo-yellow-slab.svg +1 -0
  238. package/logos/word-mark-black.svg +1 -0
  239. package/logos/word-mark-white.svg +1 -0
  240. package/package.json +11 -3
  241. package/declarations/store/-private/new-core-tmp/expensive-subscription.d.ts +0 -24
  242. package/dist/configure-C3x8YXzL.js +0 -181
  243. package/logos/NCC-1701-a-blue.svg +0 -4
  244. package/logos/NCC-1701-a-gold.svg +0 -4
  245. package/logos/NCC-1701-a-gold_100.svg +0 -1
  246. package/logos/NCC-1701-a-gold_base-64.txt +0 -1
  247. package/logos/NCC-1701-a.svg +0 -4
  248. package/logos/docs-badge.svg +0 -2
  249. package/logos/ember-data-logo-dark.svg +0 -12
  250. package/logos/ember-data-logo-light.svg +0 -12
  251. package/logos/social1.png +0 -0
  252. package/logos/social2.png +0 -0
  253. package/logos/warp-drive-logo-dark.svg +0 -4
  254. package/logos/warp-drive-logo-gold.svg +0 -4
  255. /package/declarations/{store/-private/new-core-tmp → signals}/reactivity/configure.d.ts +0 -0
  256. /package/declarations/{store/-private/new-core-tmp → signals}/reactivity/internal.d.ts +0 -0
  257. /package/declarations/{store/-private/new-core-tmp → signals}/reactivity/signal.d.ts +0 -0
  258. /package/dist/{symbols-sql1_mdx.js → unpkg/dev/-private-sql1_mdx.js} +0 -0
@@ -0,0 +1,1940 @@
1
+ import { getOrSetGlobal, peekTransient, setTransient } from './types/-private.js';
2
+ import { macroCondition, getGlobalConfig } from '@embroider/macros';
3
+ import './types/request.js';
4
+ import { g as getPromiseResult, s as setPromiseResult } from "./future-BKkJJkj7.js";
5
+
6
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
7
+
8
+ const ARRAY_SIGNAL = getOrSetGlobal('#[]', Symbol('#[]'));
9
+ const OBJECT_SIGNAL = getOrSetGlobal('#{}', Symbol('#{}'));
10
+
11
+ /**
12
+ * Requirements:
13
+ *
14
+ * Signal:
15
+ *
16
+ * - signal: a way of creating a reference that we can dirty when we desire to notify
17
+ * - @signal: a way of creating an accessor on an object that subscribes to a signal on access
18
+ * and notifies the signal on set, or of upgrading a descriptor to be such an accessor
19
+ * - defineSignal: a way of creating a signal on an object
20
+ * - notifySignal: a way of notifying the underlying signal that it has been dirtied
21
+ * - peekSignal: a way of inspecting the signal without notifying it
22
+ *
23
+ * - gate: a memoized getter function that re-runs when on access if its signal is dirty
24
+ * conceptually, a gate is a tightly coupled signal and memo
25
+ * - @gate: a way of creating a gate on an object or upgrading a descriptor with a getter
26
+ * to be a gate
27
+ * - defineGate: a way of creating a gate on an object
28
+ * - notifySignal: a way of notifying the signal for a gate that it has been dirtied
29
+ *
30
+ * - memo:
31
+ * - @memo: a way of creating a memoized getter on an object or upgrading a descriptor with a getter
32
+ * to be a memo
33
+ * - defineMemo: a way of creating a memo on an object
34
+ *
35
+ * - signalStore: storage bucket for signals associated to an object
36
+ * - withSignalStore: a way of pre-creating a signal store on an object
37
+ *
38
+ *
39
+ * @internal
40
+ */
41
+
42
+ /**
43
+ * An Opaque type that represents a framework specific or TC39 signal.
44
+ *
45
+ * It may be an array of signals or a single signal.
46
+ *
47
+ * @private
48
+ */
49
+
50
+ /**
51
+ * The hooks which MUST be configured in order to use reactive arrays,
52
+ * resources and documents with framework specfic signals or TC39 signals.
53
+ *
54
+ * Support for multiple frameworks simultaneously can be done via
55
+ * this abstraction by returning multiple signals from the `createSignal`
56
+ * method, and consuming the correct one via the correct framework via
57
+ * the `consumeSignal` and `notifySignal` methods.
58
+ *
59
+ * Unlike many signals implementations, WarpDrive does not wrap values as
60
+ * signals directly, but instead uses signals to alert the reactive layer
61
+ * to changes in the underlying cache. E.g. a signal is associated to a value,
62
+ * but does not serve as the cache for that value directly. We refer to this as
63
+ * a "gate", the pattern has also been called "side-signals".
64
+ *
65
+ * A no-op implementation is allowed, though it may lead to performance issues
66
+ * in locations that use createMemo as no memoization would be done. This is
67
+ * typically desirable only when integrating with a framework that does its own
68
+ * memoization and does not integrate with any signals-like primitive. For these
69
+ * scenarios you may also be interested in integrating with the {@link NotificationManager}
70
+ * more directly.
71
+ *
72
+ * @public
73
+ */
74
+
75
+ /**
76
+ * Contains information a {@link SignalHooks} implementation may want
77
+ * to use, such as the specialized key used for the signal
78
+ * representing an array's contents / length.
79
+ *
80
+ * ```ts
81
+ * interface HooksOptions {
82
+ * wellknown: {
83
+ * Array: symbol | string;
84
+ * }
85
+ * }
86
+ * ```
87
+ *
88
+ * @public
89
+ */
90
+
91
+ /**
92
+ * Configures the signals implementation to use. Supports multiple
93
+ * implementations simultaneously.
94
+ *
95
+ * See {@link HooksOptions} for the options passed to the provided function
96
+ * when called.
97
+ *
98
+ * See {@link SignalHooks} for the implementation the callback function should
99
+ * return.
100
+ *
101
+ * @public
102
+ * @param buildConfig - a function that takes options and returns a configuration object
103
+ */
104
+ function setupSignals(buildConfig) {
105
+ // We want to assert this but can't because too many package manager
106
+ // and bundler bugs exist that cause this to be called multiple times
107
+ // for what should be a single call.
108
+ // assert(`Cannot override configured signal hooks`, peekTransient('signalHooks') === null);
109
+ const hooks = buildConfig({
110
+ wellknown: {
111
+ Array: ARRAY_SIGNAL
112
+ }
113
+ });
114
+ setTransient('signalHooks', hooks);
115
+ }
116
+
117
+ /**
118
+ * Internal method for consuming the configured `createSignal` hook
119
+ *
120
+ * @private
121
+ */
122
+ function createSignal(obj, key) {
123
+ const signalHooks = peekTransient('signalHooks');
124
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
125
+ if (!test) {
126
+ throw new Error(`Signal hooks not configured`);
127
+ }
128
+ })(signalHooks) : {};
129
+ return signalHooks.createSignal(obj, key);
130
+ }
131
+
132
+ /**
133
+ * Internal method for consuming the configured `consumeSignal` hook
134
+ *
135
+ * @private
136
+ */
137
+ function consumeSignal(signal) {
138
+ const signalHooks = peekTransient('signalHooks');
139
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
140
+ if (!test) {
141
+ throw new Error(`Signal hooks not configured`);
142
+ }
143
+ })(signalHooks) : {};
144
+ return signalHooks.consumeSignal(signal);
145
+ }
146
+
147
+ /**
148
+ * Internal method for consuming the configured `notifySignal` hook
149
+ *
150
+ * @private
151
+ */
152
+ function notifySignal(signal) {
153
+ const signalHooks = peekTransient('signalHooks');
154
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
155
+ if (!test) {
156
+ throw new Error(`Signal hooks not configured`);
157
+ }
158
+ })(signalHooks) : {};
159
+ return signalHooks.notifySignal(signal);
160
+ }
161
+ function createMemo(object, key, fn) {
162
+ const signalHooks = peekTransient('signalHooks');
163
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
164
+ if (!test) {
165
+ throw new Error(`Signal hooks not configured`);
166
+ }
167
+ })(signalHooks) : {};
168
+ return signalHooks.createMemo(object, key, fn);
169
+ }
170
+ function willSyncFlushWatchers() {
171
+ const signalHooks = peekTransient('signalHooks');
172
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
173
+ if (!test) {
174
+ throw new Error(`Signal hooks not configured`);
175
+ }
176
+ })(signalHooks) : {};
177
+ return signalHooks.willSyncFlushWatchers();
178
+ }
179
+ function waitFor(promise) {
180
+ const signalHooks = peekTransient('signalHooks');
181
+ if (signalHooks?.waitFor) {
182
+ return signalHooks.waitFor(promise);
183
+ }
184
+ return promise;
185
+ }
186
+ const INITIALIZER_PROTO = {
187
+ isInitializer: true
188
+ };
189
+ function makeInitializer(fn) {
190
+ // we use a prototype to ensure that the initializer is not enumerable
191
+ // and does not interfere with the signal's value.
192
+ return Object.assign(Object.create(INITIALIZER_PROTO), {
193
+ value: fn
194
+ });
195
+ }
196
+ function isInitializer(obj) {
197
+ return typeof obj === 'object' && obj !== null && Object.getPrototypeOf(obj) === INITIALIZER_PROTO;
198
+ }
199
+
200
+ /**
201
+ * A WarpDriveSignal is a wrapper around a framework specific or TC39 signal
202
+ * that enables us to store and manage the signal in a universal way.
203
+ *
204
+ * WarpDrive uses signals to manage three separate concepts:
205
+ *
206
+ * - as a `storage` for a value local to the object that we want to be reactive
207
+ * (see `@local` schema field for an example)
208
+ * - as a `gate` for a memoized getter that we want to act as a reactive property
209
+ * but whose value is computed/pulled from a non-reactive source elsewhere
210
+ * and whose latest value is stored in the signal
211
+ * (see `field` schema field for an example)
212
+ * - as a `gate` with a manually managed value updated on pull when `isStale` is true
213
+ *
214
+ *
215
+ * It offers
216
+ *
217
+ * - a non-reactive way to access/update the current value
218
+ * - a non-reactive way to mark the signal as dirtied
219
+ * - a non-reactive way to store content for why the signal was dirtied
220
+ * - access to the underlying Signal(s) in-use
221
+ *
222
+ * For debugging:
223
+ * - the "key" or "name" of the signal
224
+ * - the "object identity" or "context" to which the signal is attached
225
+ *
226
+ * @private
227
+ */
228
+
229
+ /**
230
+ * We attach signals to their context object via
231
+ * a Map attached to the object via this symbol.
232
+ *
233
+ * This allows us to store multiple signals
234
+ * on the same object with smaller memory
235
+ * overhead and no WeakMap lookups.
236
+ *
237
+ * Performance sensitive objects should
238
+ * pre-warm their shape by assigning this
239
+ * during initialization.
240
+ *
241
+ * ```ts
242
+ * initializeSignalStore(obj);
243
+ * ```
244
+ *
245
+ * @private
246
+ */
247
+ const Signals = getOrSetGlobal('Signals', Symbol('Signals'));
248
+
249
+ /**
250
+ * A util that will create a signal store on the object
251
+ * if it does not already exist and returns the associated
252
+ * signal store.
253
+ *
254
+ * @private
255
+ */
256
+ function withSignalStore(obj) {
257
+ if (!obj[Signals]) {
258
+ initializeSignalStore(obj);
259
+ }
260
+ return obj[Signals];
261
+ }
262
+
263
+ /**
264
+ * A util that will create a signal store on the object
265
+ * if it does not already exist.
266
+ *
267
+ * Useful for pre-warming the shape of an object to ensure
268
+ * a key-transition to add it is not required later.
269
+ *
270
+ * @private
271
+ */
272
+ function initializeSignalStore(obj) {
273
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
274
+ if (!test) {
275
+ throw new Error(`Signal store already exists on object`);
276
+ }
277
+ })(!obj[Signals]) : {};
278
+ obj[Signals] = new Map();
279
+ }
280
+ function createInternalSignal(signals, obj, key, initialValue) {
281
+ const warpDriveSignal = {
282
+ key,
283
+ context: obj,
284
+ signal: createSignal(obj, key),
285
+ value: isInitializer(initialValue) ? initialValue.value.call(obj) : initialValue,
286
+ isStale: false
287
+ };
288
+ signals.set(key, warpDriveSignal);
289
+ return warpDriveSignal;
290
+ }
291
+ function getOrCreateInternalSignal(signals, obj, key, initialValue) {
292
+ let signal = peekInternalSignal(signals, key);
293
+ if (!signal) {
294
+ signal = createInternalSignal(signals, obj, key, initialValue);
295
+ }
296
+ return signal;
297
+ }
298
+ function createInternalMemo(signals, object, key, fn) {
299
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
300
+ if (!test) {
301
+ throw new Error(`Expected no signal/memo to exist for key "${String(key)}"`);
302
+ }
303
+ })(!peekInternalSignal(signals, key)) : {};
304
+ if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
305
+ return withFrame(signals, object, key, fn);
306
+ } else {
307
+ const memo = createMemo(object, key, fn);
308
+ signals.set(key, memo);
309
+ return memo;
310
+ }
311
+ }
312
+ function peekInternalSignal(signals, key) {
313
+ return signals?.get(key);
314
+ }
315
+ function consumeInternalSignal(signal) {
316
+ TrackingFrame?.signals.add(signal);
317
+ consumeSignal(signal.signal);
318
+ }
319
+ function notifyInternalSignal(signal) {
320
+ if (signal) {
321
+ signal.isStale = true;
322
+ notifySignal(signal.signal);
323
+ }
324
+ }
325
+ let TrackingFrame = null;
326
+
327
+ /**
328
+ * This is currently just for signals debugging, but it could be used in production
329
+ * if we wanted to eliminate the need for frameworks to implement createMemo / to
330
+ * allow us to add our own Watcher.
331
+ *
332
+ * @internal
333
+ */
334
+ function withFrame(signals, object, key, fn) {
335
+ const frameSignals = new Set();
336
+ const frameFn = () => {
337
+ if (frameSignals.size) {
338
+ frameSignals.clear();
339
+ }
340
+ TrackingFrame = {
341
+ object,
342
+ key,
343
+ signals: frameSignals,
344
+ parent: TrackingFrame
345
+ };
346
+ try {
347
+ return fn();
348
+ } finally {
349
+ TrackingFrame = TrackingFrame.parent;
350
+ }
351
+ };
352
+ const memo = createMemo(object, key, frameFn);
353
+ // @ts-expect-error
354
+ memo.signals = frameSignals;
355
+ signals.set(key, memo);
356
+ return memo;
357
+ }
358
+ function isMemo(obj) {
359
+ // @ts-expect-error
360
+ return typeof obj === 'function' && obj.signals instanceof Set;
361
+ }
362
+ if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
363
+ // @ts-expect-error adding to global API
364
+ globalThis.debugWarpDriveSignals = (obj, key) => {
365
+ const signals = obj[Signals];
366
+ if (!signals) {
367
+ log('The object has no associated signals');
368
+ return false;
369
+ }
370
+ if (key) {
371
+ const signal = signals.get(key);
372
+ if (!signal) {
373
+ log(`No signal found for key "${String(key)}"`);
374
+ return false;
375
+ }
376
+ log(signal);
377
+ if (isMemo(signal)) {
378
+ colorizeLines(printMemo(signal, key));
379
+ return true;
380
+ } else {
381
+ colorizeLines(printSignal(signal, key));
382
+ return true;
383
+ }
384
+ }
385
+ const lines = [];
386
+ for (const [k, signal] of signals) {
387
+ if (isMemo(signal)) continue;
388
+ printSignal(signal, k, lines);
389
+ }
390
+ for (const [k, signal] of signals) {
391
+ if (isMemo(signal)) {
392
+ printMemo(signal, k, lines);
393
+ }
394
+ }
395
+ log(signals);
396
+ colorizeLines(lines);
397
+ return true;
398
+ };
399
+ }
400
+ const LightColors = {
401
+ red: 'color: red;',
402
+ green: 'color: green;',
403
+ reset: 'color: inherit;'
404
+ };
405
+ const DarkColors = {
406
+ red: 'color: red;',
407
+ green: 'color: lightgreen;',
408
+ reset: 'color: inherit;'
409
+ };
410
+ function isLightMode() {
411
+ if (window?.matchMedia?.('(prefers-color-scheme: light)').matches) {
412
+ return true;
413
+ }
414
+ return false;
415
+ }
416
+ const RED = {};
417
+ const GREEN = {};
418
+ const RESET = {};
419
+ const EOL = {};
420
+ function colorizeLines(lines) {
421
+ const Colors = isLightMode() ? LightColors : DarkColors;
422
+ const colors = [];
423
+ let line = '';
424
+ for (const str of lines) {
425
+ if (str === RED) {
426
+ colors.push(Colors.red);
427
+ line += '%c';
428
+ } else if (str === GREEN) {
429
+ colors.push(Colors.green);
430
+ line += '%c';
431
+ } else if (str === RESET) {
432
+ colors.push(Colors.reset);
433
+ line += '%c';
434
+ } else if (str === EOL) {
435
+ line += '\n';
436
+ } else {
437
+ line += str;
438
+ }
439
+ }
440
+ log(line, ...colors);
441
+ }
442
+ function log(...args) {
443
+ // eslint-disable-next-line no-console
444
+ console.log(...args);
445
+ }
446
+ function isDirty(signal) {
447
+ return signal.isStale;
448
+ }
449
+ function isDirtyMemo(memo) {
450
+ // iterate simple signals first to get fastest answer
451
+ for (const signal of memo.signals) {
452
+ if (isMemo(signal)) continue;
453
+ if (isDirty(signal)) {
454
+ return true;
455
+ }
456
+ }
457
+ for (const signal of memo.signals) {
458
+ if (isMemo(signal)) {
459
+ return isDirtyMemo(signal);
460
+ }
461
+ }
462
+ return false;
463
+ }
464
+ function printSignal(signal, key, lines = [], depth = 0) {
465
+ const _dirty = isDirty(signal);
466
+ lines.push(`${''.padStart(depth * 2, ' ')}${_dirty ? '❌' : '✅'} `, _dirty ? RED : GREEN, `${String(key)}`, RESET, EOL);
467
+ return lines;
468
+ }
469
+ function printMemo(memo, key, lines = [], depth = 0) {
470
+ const _dirty = isDirtyMemo(memo);
471
+ lines.push(`${''.padStart(depth * 2, ' ')}${_dirty ? '❌' : '✅'} `, _dirty ? RED : GREEN, `<memo> ${String(key)}`, RESET, `: (consumes ${memo.signals.size} signals)`, EOL);
472
+ for (const signal of memo.signals) {
473
+ if (isMemo(signal)) continue;
474
+ printSignal(signal, signal.key, lines, depth + 1);
475
+ }
476
+ for (const signal of memo.signals) {
477
+ if (isMemo(signal)) {
478
+ printMemo(signal, signal.key, lines, depth + 1);
479
+ }
480
+ }
481
+ return lines;
482
+ }
483
+ function entangleSignal(signals, obj, key, initialValue) {
484
+ let internalSignal = peekInternalSignal(signals, key);
485
+ if (!internalSignal) {
486
+ internalSignal = createInternalSignal(signals, obj, key, initialValue);
487
+ }
488
+ consumeInternalSignal(internalSignal);
489
+ return internalSignal;
490
+ }
491
+ function entangleInitiallyStaleSignal(signals, obj, key, initialValue) {
492
+ let internalSignal = peekInternalSignal(signals, key);
493
+ if (!internalSignal) {
494
+ internalSignal = createInternalSignal(signals, obj, key, initialValue);
495
+ internalSignal.isStale = true; // mark it as stale
496
+ }
497
+ consumeInternalSignal(internalSignal);
498
+ return internalSignal;
499
+ }
500
+ function createSignalDescriptor(key, intialValue) {
501
+ return {
502
+ enumerable: true,
503
+ configurable: false,
504
+ get() {
505
+ const signals = withSignalStore(this);
506
+ const internalSignal = entangleSignal(signals, this, key, intialValue);
507
+ internalSignal.isStale = false; // reset stale state
508
+ return internalSignal.value;
509
+ },
510
+ set(value) {
511
+ const signals = withSignalStore(this);
512
+ const internalSignal = getOrCreateInternalSignal(signals, this, key, intialValue);
513
+ if (internalSignal.value !== value) {
514
+ internalSignal.value = value;
515
+ notifyInternalSignal(internalSignal);
516
+ }
517
+ }
518
+ };
519
+ }
520
+
521
+ /**
522
+ * define an enumerable signal property.
523
+ *
524
+ * Akin to Object.defineProperty.
525
+ *
526
+ * The signal will be lazily created when accessed and scoped to the
527
+ * instance of the object.
528
+ *
529
+ * @private
530
+ */
531
+ function defineSignal(obj, key, v) {
532
+ Object.defineProperty(obj, key, createSignalDescriptor(key, v));
533
+ }
534
+
535
+ /**
536
+ * Define a non-enumerable signal property.
537
+ *
538
+ * @private
539
+ */
540
+ function defineNonEnumerableSignal(obj, key, v) {
541
+ const desc = createSignalDescriptor(key, v);
542
+ desc.enumerable = false;
543
+ Object.defineProperty(obj, key, desc);
544
+ }
545
+ /**
546
+ * Decorator version of creating a signal.
547
+ */
548
+ function signal(target, key, descriptor) {
549
+ // Error on `@signal()`, `@signal(...args)``
550
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
551
+ if (!test) {
552
+ throw new Error('You attempted to use @signal(), which is not necessary nor supported. Remove the parentheses and you will be good to go!');
553
+ }
554
+ })(target !== undefined) : {};
555
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
556
+ if (!test) {
557
+ throw new Error(`You attempted to use @signal on with ${arguments.length > 1 ? 'arguments' : 'an argument'} ( @signal(${Array.from(arguments).map(d => `'${d}'`).join(', ')}) ), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@signal`'}`);
558
+ }
559
+ })(typeof target === 'object' && typeof key === 'string' && typeof descriptor === 'object' && arguments.length === 3) : {};
560
+ return createSignalDescriptor(key, descriptor.initializer ? makeInitializer(descriptor.initializer) : null);
561
+ }
562
+
563
+ /**
564
+ * Decorator version of creating a memoized getter
565
+ */
566
+ function memoized(target, key, descriptor) {
567
+ // Error on `@memoized()`, `@memoized(...args)`, and `@memoized propName = value;`
568
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
569
+ if (!test) {
570
+ throw new Error('You attempted to use @memoized(), which is not necessary nor supported. Remove the parentheses and you will be good to go!');
571
+ }
572
+ })(target !== undefined) : {};
573
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
574
+ if (!test) {
575
+ throw new Error(`You attempted to use @memoized on with ${arguments.length > 1 ? 'arguments' : 'an argument'} ( @memoized(${Array.from(arguments).map(d => `'${d}'`).join(', ')}), which is not supported. Dependencies are automatically tracked, so you can just use ${'`@memoized`'}`);
576
+ }
577
+ })(typeof target === 'object' && typeof key === 'string' && typeof descriptor === 'object' && arguments.length === 3) : {};
578
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
579
+ if (!test) {
580
+ throw new Error(`The @memoized decorator must be applied to getters. '${key}' is not a getter.`);
581
+ }
582
+ })(typeof descriptor.get === 'function') : {};
583
+
584
+ // eslint-disable-next-line @typescript-eslint/unbound-method
585
+ const getter = descriptor.get;
586
+ descriptor.get = function () {
587
+ const signals = withSignalStore(this);
588
+ let memoSignal = signals.get(key);
589
+ if (!memoSignal) {
590
+ memoSignal = createInternalMemo(signals, this, key, getter.bind(this));
591
+ }
592
+ return memoSignal();
593
+ };
594
+ return descriptor;
595
+ }
596
+
597
+ /**
598
+ * Decorator version of creating a gate.
599
+ *
600
+ * @private
601
+ */
602
+ function gate(_target, key, desc) {
603
+ // eslint-disable-next-line @typescript-eslint/unbound-method
604
+ const getter = desc.get;
605
+ // eslint-disable-next-line @typescript-eslint/unbound-method
606
+ const setter = desc.set;
607
+ const isLocal = desc.isLocal;
608
+ desc.get = function () {
609
+ const signals = withSignalStore(this);
610
+ let internalSignal = peekInternalSignal(signals, key);
611
+ if (!internalSignal) {
612
+ internalSignal = createInternalSignal(signals, this, key, getter.call(this));
613
+ } else if (internalSignal.isStale) {
614
+ internalSignal.isStale = false;
615
+ internalSignal.value = getter.call(this);
616
+ }
617
+ consumeInternalSignal(internalSignal);
618
+ return internalSignal.value;
619
+ };
620
+ if (setter) {
621
+ desc.set = function (v) {
622
+ const signals = withSignalStore(this);
623
+ let internalSignal = peekInternalSignal(signals, key);
624
+ if (!internalSignal) {
625
+ // we can't use `v` as initialValue here because setters don't
626
+ // return the value and the final value may be different
627
+ // than what the setter was called with.
628
+ internalSignal = createInternalSignal(signals, this, key, undefined);
629
+ internalSignal.isStale = true;
630
+ }
631
+ setter.call(this, v);
632
+ // when a gate is set, we do not notify the signal
633
+ // as its update is controlled externally.
634
+ // unless it specifically sets itself to be locally managed
635
+ if (isLocal) {
636
+ internalSignal.isStale = true;
637
+ notifyInternalSignal(internalSignal);
638
+ }
639
+ };
640
+ }
641
+ return desc;
642
+ }
643
+ function defineGate(obj, key, desc) {
644
+ const options = Object.assign({
645
+ enumerable: true,
646
+ configurable: false
647
+ }, gate(obj, key, desc));
648
+ Object.defineProperty(obj, key, options);
649
+ }
650
+ const RequestCache = new WeakMap();
651
+ function isAbortError(error) {
652
+ return error instanceof DOMException && error.name === 'AbortError';
653
+ }
654
+ function upgradeLoadingState(state) {
655
+ return state;
656
+ }
657
+ async function watchStream(stream, loadingState) {
658
+ const state = upgradeLoadingState(loadingState);
659
+ const reader = stream.getReader();
660
+ let bytesLoaded = 0;
661
+ let shouldForward = state._stream !== null && state._stream.readable.locked;
662
+ let isForwarding = shouldForward;
663
+ let writer = state._stream?.writable.getWriter();
664
+ const buffer = [];
665
+ state._isPending = false;
666
+ state._isStarted = true;
667
+ state._startTime = performance.now();
668
+ while (true) {
669
+ const {
670
+ value,
671
+ done
672
+ } = await reader.read();
673
+ if (done) {
674
+ break;
675
+ }
676
+ bytesLoaded += value.byteLength;
677
+ state._bytesLoaded = bytesLoaded;
678
+ state._lastPacketTime = performance.now();
679
+ shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
680
+ if (shouldForward) {
681
+ if (!isForwarding) {
682
+ isForwarding = true;
683
+ writer = state._stream.writable.getWriter();
684
+ for (const item of buffer) {
685
+ await writer.ready;
686
+ await writer.write(item);
687
+ }
688
+ buffer.length = 0;
689
+ }
690
+ await writer.ready;
691
+ await writer.write(value);
692
+ } else {
693
+ buffer.push(value);
694
+ }
695
+ }
696
+
697
+ // if we are still forwarding, we need to close the writer
698
+ if (isForwarding) {
699
+ await writer.ready;
700
+ await writer.close();
701
+ } else if (state._stream) {
702
+ // if we are not forwarding, we need to cancel the stream
703
+ await state._stream.readable.cancel('The Stream Has Already Ended');
704
+ state._stream = null;
705
+ }
706
+ const endTime = performance.now();
707
+ state._endTime = endTime;
708
+ state._isComplete = true;
709
+ state._isStarted = false;
710
+ }
711
+
712
+ /**
713
+ * Lazily consumes the stream of a request, providing a number of
714
+ * reactive properties that can be used to build UIs that respond
715
+ * to the progress of a request.
716
+ *
717
+ * @hideconstructor
718
+ */
719
+ class RequestLoadingState {
720
+ /** @internal */
721
+
722
+ /** @internal */
723
+
724
+ /** @internal */
725
+
726
+ /** @internal */
727
+
728
+ /** @internal */
729
+
730
+ /** @internal */
731
+
732
+ /** @internal */
733
+
734
+ /** @internal */
735
+
736
+ /** @internal */
737
+
738
+ /** @internal */
739
+
740
+ /** @internal */
741
+
742
+ /** @internal */
743
+ _stream = null;
744
+ /** @internal */
745
+ _future;
746
+ /** @internal */
747
+ _triggered = false;
748
+ /** @internal */
749
+ _trigger() {
750
+ if (this._triggered) {
751
+ return;
752
+ }
753
+ this._triggered = true;
754
+ const future = this._future;
755
+ const promise = future.getStream();
756
+ if (promise.sizeHint) {
757
+ this._sizeHint = promise.sizeHint;
758
+ }
759
+ this.promise = promise.then(stream => {
760
+ if (!stream) {
761
+ this._isPending = false;
762
+ this._isComplete = true;
763
+ return;
764
+ }
765
+ return watchStream(stream, this);
766
+ }, error => {
767
+ this._isPending = false;
768
+ this._isStarted = false;
769
+ if (isAbortError(error)) {
770
+ this._isCancelled = true;
771
+ this._isComplete = true;
772
+ }
773
+ this._isErrored = true;
774
+ this._error = error;
775
+ });
776
+ }
777
+ promise = null;
778
+ get isPending() {
779
+ this._trigger();
780
+ return this._isPending;
781
+ }
782
+ get sizeHint() {
783
+ this._trigger();
784
+ return this._sizeHint;
785
+ }
786
+ get stream() {
787
+ this._trigger();
788
+ if (!this._stream) {
789
+ if (this._isComplete || this._isCancelled || this._isErrored) {
790
+ return null;
791
+ }
792
+ this._stream = new TransformStream();
793
+ }
794
+ return this._stream.readable;
795
+ }
796
+ get isStarted() {
797
+ this._trigger();
798
+ return this._isStarted;
799
+ }
800
+ get bytesLoaded() {
801
+ this._trigger();
802
+ return this._bytesLoaded;
803
+ }
804
+ get startTime() {
805
+ this._trigger();
806
+ return this._startTime;
807
+ }
808
+ get endTime() {
809
+ this._trigger();
810
+ return this._endTime;
811
+ }
812
+ get lastPacketTime() {
813
+ this._trigger();
814
+ return this._lastPacketTime;
815
+ }
816
+ get isComplete() {
817
+ this._trigger();
818
+ return this._isComplete;
819
+ }
820
+ get isCancelled() {
821
+ this._trigger();
822
+ return this._isCancelled;
823
+ }
824
+ get isErrored() {
825
+ this._trigger();
826
+ return this._isErrored;
827
+ }
828
+ get error() {
829
+ this._trigger();
830
+ return this._error;
831
+ }
832
+ get elapsedTime() {
833
+ return (this.endTime || this.lastPacketTime) - this.startTime;
834
+ }
835
+ get completedRatio() {
836
+ return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
837
+ }
838
+ get remainingRatio() {
839
+ return 1 - this.completedRatio;
840
+ }
841
+ get duration() {
842
+ return this.endTime - this.startTime;
843
+ }
844
+ get speed() {
845
+ // bytes per second
846
+ return this.bytesLoaded / (this.elapsedTime / 1000);
847
+ }
848
+ constructor(future) {
849
+ this._future = future;
850
+ }
851
+ abort = () => {
852
+ this._future.abort();
853
+ };
854
+ }
855
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isPending', true);
856
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isStarted', false);
857
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isComplete', false);
858
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isCancelled', false);
859
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_isErrored', false);
860
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_error', null);
861
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_sizeHint', 0);
862
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_bytesLoaded', 0);
863
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_startTime', 0);
864
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_endTime', 0);
865
+ defineNonEnumerableSignal(RequestLoadingState.prototype, '_lastPacketTime', 0);
866
+
867
+ /**
868
+ * The state of a request in the "pending"
869
+ * state. This is the default initial state.
870
+ *
871
+ * Extends the {@link PendingPromise} interface.
872
+ *
873
+ */
874
+
875
+ /**
876
+ * The state of a request in the "fulfilled" state.
877
+ * This is the state of a request that has resolved
878
+ * successfully.
879
+ *
880
+ * Extends the {@link ResolvedPromise} interface.
881
+ *
882
+ */
883
+
884
+ /**
885
+ * The state of a request in the "rejected" state.
886
+ * This is the state of a request that has rejected
887
+ * with an error.
888
+ *
889
+ * Extends the {@link RejectedPromise} interface.
890
+ *
891
+ */
892
+
893
+ /**
894
+ * The state of a request in the "cancelled" state.
895
+ * This is the state of a promise that has been
896
+ * cancelled.
897
+ *
898
+ */
899
+
900
+ /**
901
+ * RequestState extends the concept of {@link PromiseState} to provide a reactive
902
+ * wrapper for a request {@link Future} which allows you write declarative code
903
+ * around a Future's control flow.
904
+ *
905
+ * It is useful in both Template and JavaScript contexts, allowing you
906
+ * to quickly derive behaviors and data from pending, error and success
907
+ * states.
908
+ *
909
+ * The key difference between a {@link Promise} and a Future is that Futures provide
910
+ * access to a {@link ReadableStream | stream} of their content, the {@link RequestKey} of the request (if any)
911
+ * as well as the ability to attempt to {@link Future.abort | abort} the request.
912
+ *
913
+ * ```ts
914
+ * interface Future<T> extends Promise<T>> {
915
+ * getStream(): Promise<ReadableStream>;
916
+ * abort(): void;
917
+ * lid: RequestKey | null;
918
+ * }
919
+ * ```
920
+ *
921
+ * These additional APIs allow us to craft even richer state experiences.
922
+ *
923
+ * To get the state of a request, use {@link getRequestState}.
924
+ *
925
+ * See also:
926
+ * - {@link PendingRequest}
927
+ * - {@link ResolvedRequest}
928
+ * - {@link RejectedRequest}
929
+ * - {@link CancelledRequest}
930
+ *
931
+ */
932
+
933
+ const RequestStateProto = {};
934
+ function performRefresh(requester, request, isReload) {
935
+ const req = Object.assign({}, request);
936
+ const cacheOptions = Object.assign({}, req.cacheOptions);
937
+ if (isReload) {
938
+ // force direct to network
939
+ cacheOptions.reload = true;
940
+ } else if (isReload === false) {
941
+ // delete reload to ensure we use backgroundReload / policy
942
+ delete cacheOptions.reload;
943
+ cacheOptions.backgroundReload = true;
944
+ } else {
945
+ // delete props to ensure we use the policy
946
+ delete cacheOptions.backgroundReload;
947
+ delete cacheOptions.reload;
948
+ }
949
+ req.cacheOptions = cacheOptions;
950
+ return requester.request(req);
951
+ }
952
+
953
+ // TODO introduce a new mechanism for defining multiple properties
954
+ // that share a common signal
955
+ defineSignal(RequestStateProto, 'reason', null);
956
+ defineSignal(RequestStateProto, 'value', null);
957
+ defineSignal(RequestStateProto, 'result', null);
958
+ defineSignal(RequestStateProto, 'error', null);
959
+ defineSignal(RequestStateProto, 'status', 'pending');
960
+ defineSignal(RequestStateProto, 'isPending', true);
961
+ defineSignal(RequestStateProto, 'isLoading', true);
962
+ defineSignal(RequestStateProto, 'isSuccess', false);
963
+ defineSignal(RequestStateProto, 'isError', false);
964
+ defineSignal(RequestStateProto, 'request', null);
965
+ defineSignal(RequestStateProto, 'response', null);
966
+ Object.defineProperty(RequestStateProto, 'isCancelled', {
967
+ get() {
968
+ return this.isError && isAbortError(this.reason);
969
+ }
970
+ });
971
+ Object.defineProperty(RequestStateProto, 'loadingState', {
972
+ get() {
973
+ if (!this._loadingState) {
974
+ this._loadingState = new RequestLoadingState(this._request);
975
+ }
976
+ return this._loadingState;
977
+ }
978
+ });
979
+ function createRequestState(future) {
980
+ const state = getPromiseResult(future);
981
+ const promiseState = Object.create(RequestStateProto);
982
+ promiseState._request = future;
983
+ // @ts-expect-error - we still attach it for PendingState
984
+ promiseState.reload = () => {
985
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
986
+ if (!test) {
987
+ throw new Error(`Cannot reload a request that is still pending. Await or abort the original request first.`);
988
+ }
989
+ })(!promiseState.isPending) : {};
990
+ return performRefresh(future.requester, promiseState.request, true);
991
+ };
992
+
993
+ // @ts-expect-error - we still attach it for PendingState
994
+ promiseState.refresh = (usePolicy = false) => {
995
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
996
+ if (!test) {
997
+ throw new Error(`Cannot refresh a request that is still pending. Await or abort the original request first.`);
998
+ }
999
+ })(!promiseState.isPending) : {};
1000
+ return performRefresh(future.requester, promiseState.request, usePolicy === true ? null : false);
1001
+ };
1002
+ if (state) {
1003
+ if (state.isError) {
1004
+ promiseState.error = state.result;
1005
+ promiseState.reason = state.result;
1006
+ promiseState.status = 'rejected';
1007
+ promiseState.isError = true;
1008
+ promiseState.isPending = false;
1009
+ promiseState.isLoading = false;
1010
+ promiseState.request = state.result.request;
1011
+ promiseState.response = state.result.response;
1012
+ } else {
1013
+ promiseState.result = state.result.content;
1014
+ promiseState.value = state.result.content;
1015
+ promiseState.status = 'fulfilled';
1016
+ promiseState.isSuccess = true;
1017
+ promiseState.isPending = false;
1018
+ promiseState.isLoading = false;
1019
+ promiseState.request = state.result.request;
1020
+ promiseState.response = state.result.response;
1021
+ }
1022
+ } else {
1023
+ void future.then(result => {
1024
+ setPromiseResult(future, {
1025
+ isError: false,
1026
+ result
1027
+ });
1028
+ promiseState.result = result.content;
1029
+ promiseState.value = result.content;
1030
+ promiseState.status = 'fulfilled';
1031
+ promiseState.isSuccess = true;
1032
+ promiseState.isPending = false;
1033
+ promiseState.isLoading = false;
1034
+ promiseState.request = result.request;
1035
+ promiseState.response = result.response;
1036
+ }, error => {
1037
+ setPromiseResult(future, {
1038
+ isError: true,
1039
+ result: error
1040
+ });
1041
+ promiseState.error = error;
1042
+ promiseState.reason = error;
1043
+ promiseState.status = 'rejected';
1044
+ promiseState.isError = true;
1045
+ promiseState.isPending = false;
1046
+ promiseState.isLoading = false;
1047
+ promiseState.request = error.request;
1048
+ promiseState.response = error.response;
1049
+ });
1050
+ }
1051
+ return promiseState;
1052
+ }
1053
+
1054
+ /**
1055
+ * `getRequestState` can be used in both JavaScript and Template contexts.
1056
+ *
1057
+ * ```ts
1058
+ * import { getRequestState } from '@warp-drive/ember';
1059
+ *
1060
+ * const state = getRequestState(future);
1061
+ * ```
1062
+ *
1063
+ * For instance, we could write a getter on a component that updates whenever
1064
+ * the request state advances or the future changes, by combining the function
1065
+ * with the use of `@cached`
1066
+ *
1067
+ * ```ts
1068
+ * class Component {
1069
+ * @cached
1070
+ * get title() {
1071
+ * const state = getRequestState(this.args.request);
1072
+ * if (state.isPending) {
1073
+ * return 'loading...';
1074
+ * }
1075
+ * if (state.isError) { return null; }
1076
+ * return state.result.title;
1077
+ * }
1078
+ * }
1079
+ * ```
1080
+ *
1081
+ * Or in a template as a helper:
1082
+ *
1083
+ * ```gjs
1084
+ * import { getRequestState } from '@warp-drive/ember';
1085
+ *
1086
+ * <template>
1087
+ * {{#let (getRequestState @request) as |state|}}
1088
+ * {{#if state.isPending}}
1089
+ * <Spinner />
1090
+ * {{else if state.isError}}
1091
+ * <ErrorForm @error={{state.error}} />
1092
+ * {{else}}
1093
+ * <h1>{{state.result.title}}</h1>
1094
+ * {{/if}}
1095
+ * {{/let}}
1096
+ * </template>
1097
+ * ```
1098
+ *
1099
+ * If looking to use in a template, consider also the `<Request />` component
1100
+ * which offers a number of additional capabilities for requests *beyond* what
1101
+ * `RequestState` provides.
1102
+ *
1103
+ */
1104
+ function getRequestState(future) {
1105
+ let state = RequestCache.get(future);
1106
+ if (!state) {
1107
+ state = createRequestState(future);
1108
+ RequestCache.set(future, state);
1109
+ }
1110
+ return state;
1111
+ }
1112
+ function decorateMethodV2(prototype, prop, decorators) {
1113
+ const origDesc = Object.getOwnPropertyDescriptor(prototype, prop);
1114
+ let desc = {
1115
+ ...origDesc
1116
+ };
1117
+ for (let decorator of decorators) {
1118
+ desc = decorator(prototype, prop, desc) || desc;
1119
+ }
1120
+ if (desc.initializer !== void 0) {
1121
+ desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
1122
+ desc.initializer = void 0;
1123
+ }
1124
+ Object.defineProperty(prototype, prop, desc);
1125
+ }
1126
+ const DEFAULT_DEADLINE = 30_000;
1127
+ const DISPOSE = Symbol.dispose || Symbol.for('dispose');
1128
+ function isNeverString(val) {
1129
+ return val;
1130
+ }
1131
+
1132
+ /**
1133
+ * Utilities to assist in recovering from the error.
1134
+ */
1135
+
1136
+ /** @deprecated use {@link RecoveryFeatures} */
1137
+
1138
+ /**
1139
+ * Utilities for keeping the request fresh
1140
+ */
1141
+
1142
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1143
+
1144
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1145
+
1146
+ /**
1147
+ * A reactive class
1148
+ *
1149
+ * @hideconstructor
1150
+ */
1151
+ class RequestSubscription {
1152
+ /**
1153
+ * Whether the browser reports that the network is online.
1154
+ */
1155
+
1156
+ /**
1157
+ * Whether the browser reports that the tab is hidden.
1158
+ */
1159
+
1160
+ /**
1161
+ * Whether the component is currently refreshing the request.
1162
+ */
1163
+
1164
+ /**
1165
+ * The most recent blocking request that was made, typically
1166
+ * the result of a reload.
1167
+ *
1168
+ * This will never be the original request passed as an arg to
1169
+ * the component.
1170
+ *
1171
+ * @internal
1172
+ */
1173
+
1174
+ /**
1175
+ * The most recent request that was made, typically due to either a
1176
+ * reload or a refresh.
1177
+ *
1178
+ * This will never be the original request passed as an arg to
1179
+ * the component.
1180
+ *
1181
+ * @internal
1182
+ */
1183
+
1184
+ /**
1185
+ * The time at which the network was reported as offline.
1186
+ *
1187
+ * @internal
1188
+ */
1189
+
1190
+ /** @internal */
1191
+
1192
+ /** @internal */
1193
+
1194
+ /** @internal */
1195
+
1196
+ /** @internal */
1197
+
1198
+ /** @internal */
1199
+
1200
+ /**
1201
+ * The event listener for network status changes,
1202
+ * cached to use the reference for removal.
1203
+ *
1204
+ * @internal
1205
+ */
1206
+
1207
+ /**
1208
+ * The event listener for visibility status changes,
1209
+ * cached to use the reference for removal.
1210
+ *
1211
+ * @internal
1212
+ */
1213
+
1214
+ /**
1215
+ * The last request passed as an arg to the component,
1216
+ * cached for comparison.
1217
+ *
1218
+ * @internal
1219
+ */
1220
+
1221
+ /**
1222
+ * The last query passed as an arg to the component,
1223
+ * cached for comparison.
1224
+ *
1225
+ * @internal
1226
+ */
1227
+
1228
+ /** @internal */
1229
+
1230
+ /** @internal */
1231
+
1232
+ /** @internal */
1233
+
1234
+ /**
1235
+ * The Store this subscription subscribes to or the RequestManager
1236
+ * which issues this request.
1237
+ */
1238
+
1239
+ /**
1240
+ * The Store or RequestManager that the last subscription is attached to.
1241
+ *
1242
+ * This differs from 'store' because a <Request /> may be passed a
1243
+ * request originating from a different store than the <Request />
1244
+ * component would use if it were to issue the request itself.
1245
+ *
1246
+ * @internal
1247
+ */
1248
+ _requester;
1249
+ constructor(store, args) {
1250
+ this._args = args;
1251
+ this.store = store;
1252
+ this._subscribedTo = null;
1253
+ this._subscription = null;
1254
+ this._intervalStart = null;
1255
+ this._invalidated = false;
1256
+ this._nextInterval = null;
1257
+ this._requester = null;
1258
+ this.isDestroyed = false;
1259
+ this[DISPOSE] = _DISPOSE;
1260
+ this._installListeners();
1261
+ void this._beginPolling();
1262
+ }
1263
+
1264
+ /**
1265
+ * @internal
1266
+ */
1267
+ async _beginPolling() {
1268
+ // await the initial request
1269
+ try {
1270
+ if (!this.isIdle) {
1271
+ await this.request;
1272
+ }
1273
+ } catch {
1274
+ // ignore errors here, we just want to wait for the request to finish
1275
+ } finally {
1276
+ if (!this.isDestroyed) {
1277
+ void this._scheduleInterval();
1278
+ }
1279
+ }
1280
+ }
1281
+ get isIdle() {
1282
+ const {
1283
+ request,
1284
+ query
1285
+ } = this._args;
1286
+ return Boolean(!request && !query);
1287
+ }
1288
+ static {
1289
+ decorateMethodV2(this.prototype, "isIdle", [memoized]);
1290
+ }
1291
+ get autorefreshTypes() {
1292
+ const {
1293
+ autorefresh
1294
+ } = this._args;
1295
+ let types;
1296
+ if (autorefresh === true) {
1297
+ types = ['online', 'invalid'];
1298
+ } else if (typeof autorefresh === 'string') {
1299
+ types = autorefresh.split(',');
1300
+ } else {
1301
+ types = [];
1302
+ }
1303
+ return new Set(types);
1304
+ }
1305
+
1306
+ // we only run this function on component creation
1307
+ // and when an update is triggered, so it does not
1308
+ // react to changes in the autorefreshThreshold
1309
+ // or autorefresh args.
1310
+ //
1311
+ // if we need to react to those changes, we can
1312
+ // use a modifier or internal component or some
1313
+ // such to trigger a re-run of this function.
1314
+ /** @internal */
1315
+ static {
1316
+ decorateMethodV2(this.prototype, "autorefreshTypes", [memoized]);
1317
+ }
1318
+ async _scheduleInterval() {
1319
+ const {
1320
+ autorefreshThreshold
1321
+ } = this._args;
1322
+ const hasValidThreshold = typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0;
1323
+ if (
1324
+ // dont schedule in SSR
1325
+ typeof window === 'undefined' ||
1326
+ // dont schedule without a threshold
1327
+ !hasValidThreshold ||
1328
+ // dont schedule if we weren't told to
1329
+ !this.autorefreshTypes.has('interval') ||
1330
+ // dont schedule if we're already scheduled
1331
+ this._intervalStart !== null) {
1332
+ return;
1333
+ }
1334
+
1335
+ // if we have a current request, wait for it to finish
1336
+ // before scheduling the next one
1337
+ if (this._latestRequest) {
1338
+ try {
1339
+ await this._latestRequest;
1340
+ } catch {
1341
+ // ignore errors here, we just want to wait for the request to finish
1342
+ }
1343
+ if (this.isDestroyed) {
1344
+ return;
1345
+ }
1346
+ }
1347
+
1348
+ // setup the next interval
1349
+ this._intervalStart = Date.now();
1350
+ this._nextInterval = setTimeout(() => {
1351
+ this._maybeUpdate();
1352
+ }, autorefreshThreshold);
1353
+ }
1354
+
1355
+ /** @internal */
1356
+ _clearInterval() {
1357
+ if (this._nextInterval) {
1358
+ clearTimeout(this._nextInterval);
1359
+ this._intervalStart = null;
1360
+ }
1361
+ }
1362
+ /**
1363
+ * @internal
1364
+ */
1365
+ _updateSubscriptions() {
1366
+ if (this.isIdle) {
1367
+ return;
1368
+ }
1369
+ const requestId = this._request.lid;
1370
+
1371
+ // if we're already subscribed to this request, we don't need to do anything
1372
+ if (this._subscribedTo === requestId) {
1373
+ return;
1374
+ }
1375
+
1376
+ // if we're subscribed to a different request, we need to unsubscribe
1377
+ this._removeSubscriptions();
1378
+
1379
+ // if we have a request, we need to subscribe to it
1380
+ const store = this._getRequester();
1381
+ this._requester = store;
1382
+ if (requestId && isStore(store)) {
1383
+ this._subscribedTo = requestId;
1384
+ this._subscription = store.notifications.subscribe(requestId, (_id, op) => {
1385
+ // ignore subscription events that occur while our own component's request
1386
+ // is occurring
1387
+ if (this._isUpdating) {
1388
+ return;
1389
+ }
1390
+ switch (op) {
1391
+ case 'invalidated':
1392
+ {
1393
+ // if we're subscribed to invalidations, we need to update
1394
+ if (this.autorefreshTypes.has('invalid')) {
1395
+ this._invalidated = true;
1396
+ this._maybeUpdate();
1397
+ }
1398
+ break;
1399
+ }
1400
+ case 'state':
1401
+ {
1402
+ const latest = store.requestManager._deduped.get(requestId);
1403
+ const priority = latest?.priority;
1404
+ const state = this.reqState;
1405
+ if (!priority) {
1406
+ // if there is no priority, we have completed whatever request
1407
+ // was occurring and so we are no longer refreshing (if we were)
1408
+ this.isRefreshing = false;
1409
+ } else if (priority.blocking && !state.isLoading) {
1410
+ // if we are blocking, there is an active request for this identity
1411
+ // that MUST be fulfilled from network (not cache).
1412
+ // Thus this is not "refreshing" because we should clear out and
1413
+ // block on this request.
1414
+ //
1415
+ // we receive state notifications when either a request initiates
1416
+ // or completes.
1417
+ //
1418
+ // In the completes case: we may receive the state notification
1419
+ // slightly before the request is finalized because the NotificationManager
1420
+ // may sync flush it (and thus deliver it before the microtask completes)
1421
+ //
1422
+ // In the initiates case: we aren't supposed to receive one unless there
1423
+ // is no other request in flight for this identity.
1424
+ //
1425
+ // However, there is a race condition here where the completed
1426
+ // notification can trigger an update that generates a new request
1427
+ // thus giving us an initiated notification before the older request
1428
+ // finalizes.
1429
+ //
1430
+ // When this occurs, if the triggered update happens to have caused
1431
+ // a new request to be made for the same identity AND that request
1432
+ // is the one passed into this component as the @request arg, then
1433
+ // getRequestState will return the state of the new request.
1434
+ // We can detect this by checking if the request state is "loading"
1435
+ // as outside of this case we would have a completed request.
1436
+ //
1437
+ // That is the reason for the `&& !state.isLoading` check above.
1438
+
1439
+ // TODO should we just treat this as refreshing?
1440
+ this.isRefreshing = false;
1441
+ this._maybeUpdate('policy', true);
1442
+ } else {
1443
+ this.isRefreshing = true;
1444
+ }
1445
+ }
1446
+ }
1447
+ });
1448
+ }
1449
+ }
1450
+
1451
+ /**
1452
+ * @internal
1453
+ */
1454
+ _removeSubscriptions() {
1455
+ const store = this._requester;
1456
+ if (this._subscription && store && isStore(store)) {
1457
+ store.notifications.unsubscribe(this._subscription);
1458
+ this._subscribedTo = null;
1459
+ this._subscription = null;
1460
+ this._requester = null;
1461
+ }
1462
+ }
1463
+
1464
+ /**
1465
+ * Install the event listeners for network and visibility changes.
1466
+ * This is only done in browser environments with a global `window`.
1467
+ *
1468
+ * @internal
1469
+ */
1470
+ _installListeners() {
1471
+ if (typeof window === 'undefined') {
1472
+ return;
1473
+ }
1474
+ this.isOnline = window.navigator.onLine;
1475
+ this._unavailableStart = this.isOnline ? null : Date.now();
1476
+ this.isHidden = document.visibilityState === 'hidden';
1477
+ this._onlineChanged = event => {
1478
+ this.isOnline = event.type === 'online';
1479
+ if (event.type === 'offline' && this._unavailableStart === null) {
1480
+ this._unavailableStart = Date.now();
1481
+ }
1482
+ this._maybeUpdate();
1483
+ };
1484
+ this._backgroundChanged = () => {
1485
+ const isHidden = document.visibilityState === 'hidden';
1486
+ this.isHidden = isHidden;
1487
+ if (isHidden && this._unavailableStart === null) {
1488
+ this._unavailableStart = Date.now();
1489
+ }
1490
+ this._maybeUpdate();
1491
+ };
1492
+ window.addEventListener('online', this._onlineChanged, {
1493
+ passive: true,
1494
+ capture: true
1495
+ });
1496
+ window.addEventListener('offline', this._onlineChanged, {
1497
+ passive: true,
1498
+ capture: true
1499
+ });
1500
+ document.addEventListener('visibilitychange', this._backgroundChanged, {
1501
+ passive: true,
1502
+ capture: true
1503
+ });
1504
+ }
1505
+
1506
+ /**
1507
+ * If the network is online and the tab is visible, either reload or refresh the request
1508
+ * based on the component's configuration and the requested update mode.
1509
+ *
1510
+ * Valid modes are:
1511
+ *
1512
+ * - `'reload'`: Force a reload of the request.
1513
+ * - `'refresh'`: Refresh the request in the background.
1514
+ * - `'policy'`: Make the request, letting the store's configured CachePolicy decide whether to reload, refresh, or do nothing.
1515
+ * - `undefined`: Make the request using the component's autorefreshBehavior setting if the autorefreshThreshold has passed.
1516
+ *
1517
+ * @internal
1518
+ */
1519
+ _maybeUpdate(mode, silent) {
1520
+ if (this.isIdle) {
1521
+ return;
1522
+ }
1523
+ const {
1524
+ reqState
1525
+ } = this;
1526
+ if (reqState.isPending) {
1527
+ return;
1528
+ }
1529
+ const canAttempt = Boolean(this.isOnline && !this.isHidden && (mode || this.autorefreshTypes.size));
1530
+ if (!canAttempt) {
1531
+ if (!silent && mode && mode !== '_invalidated') {
1532
+ throw new Error(`Reload not available: the network is not online or the tab is hidden`);
1533
+ }
1534
+ return;
1535
+ }
1536
+ const {
1537
+ autorefreshTypes
1538
+ } = this;
1539
+ let shouldAttempt = this._invalidated || Boolean(mode);
1540
+ if (!shouldAttempt && autorefreshTypes.has('online')) {
1541
+ const {
1542
+ _unavailableStart
1543
+ } = this;
1544
+ const {
1545
+ autorefreshThreshold
1546
+ } = this._args;
1547
+ const deadline = typeof autorefreshThreshold === 'number' ? autorefreshThreshold : DEFAULT_DEADLINE;
1548
+ shouldAttempt = Boolean(_unavailableStart && Date.now() - _unavailableStart > deadline);
1549
+ }
1550
+ if (!shouldAttempt && autorefreshTypes.has('interval')) {
1551
+ const {
1552
+ _intervalStart
1553
+ } = this;
1554
+ const {
1555
+ autorefreshThreshold
1556
+ } = this._args;
1557
+ if (_intervalStart && typeof autorefreshThreshold === 'number' && autorefreshThreshold > 0) {
1558
+ shouldAttempt = Boolean(Date.now() - _intervalStart >= autorefreshThreshold);
1559
+ }
1560
+ }
1561
+ this._unavailableStart = null;
1562
+ this._invalidated = false;
1563
+ if (shouldAttempt) {
1564
+ this._clearInterval();
1565
+ this._isUpdating = true;
1566
+ const realMode = mode === '_invalidated' ? null : mode;
1567
+ const val = realMode ?? this._args.autorefreshBehavior ?? 'policy';
1568
+
1569
+ // if the future was generated by an older store version, it may not have
1570
+ // a requester set. In this case we append it to ensure that reload and
1571
+ // refresh will work appropriately.
1572
+ const requester = this._getRequester();
1573
+ if (!reqState._request.requester) {
1574
+ reqState._request.requester = requester;
1575
+ }
1576
+ switch (val) {
1577
+ case 'reload':
1578
+ this._latestRequest = reqState.reload();
1579
+ break;
1580
+ case 'refresh':
1581
+ this._latestRequest = reqState.refresh();
1582
+ break;
1583
+ case 'policy':
1584
+ this._latestRequest = reqState.refresh(true);
1585
+ break;
1586
+ default:
1587
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1588
+ {
1589
+ throw new Error(`Invalid ${mode ? 'update mode' : '@autorefreshBehavior'} for <Request />: ${isNeverString(val)}`);
1590
+ }
1591
+ })() : {};
1592
+ }
1593
+ if (val !== 'refresh') {
1594
+ this._localRequest = this._latestRequest;
1595
+ }
1596
+ void this._scheduleInterval();
1597
+ void this._latestRequest.finally(() => {
1598
+ this._isUpdating = false;
1599
+ });
1600
+ }
1601
+ }
1602
+
1603
+ /**
1604
+ * @internal
1605
+ */
1606
+ _getRequester() {
1607
+ // Note: we check for the requester's presence
1608
+ // as well as the request's presence because we may
1609
+ // be subscribed to a request issued by a store from an older
1610
+ // version of the library that didn't yet set requester.
1611
+ if (this._args.request?.requester) {
1612
+ return this._args.request.requester;
1613
+ }
1614
+ return this.store;
1615
+ }
1616
+
1617
+ /**
1618
+ * Retry the request, reloading it from the server.
1619
+ */
1620
+ retry = async () => {
1621
+ this._maybeUpdate('reload');
1622
+ await this._localRequest;
1623
+ };
1624
+
1625
+ /**
1626
+ * Refresh the request, updating it in the background.
1627
+ */
1628
+ refresh = async () => {
1629
+ this._maybeUpdate('refresh');
1630
+ await this._latestRequest;
1631
+ };
1632
+
1633
+ /**
1634
+ * features to yield to the error slot of a component
1635
+ */
1636
+ get errorFeatures() {
1637
+ return {
1638
+ isHidden: this.isHidden,
1639
+ isOnline: this.isOnline,
1640
+ retry: this.retry
1641
+ };
1642
+ }
1643
+
1644
+ /**
1645
+ * features to yield to the content slot of a component
1646
+ */
1647
+ static {
1648
+ decorateMethodV2(this.prototype, "errorFeatures", [memoized]);
1649
+ }
1650
+ get contentFeatures() {
1651
+ const feat = {
1652
+ isHidden: this.isHidden,
1653
+ isOnline: this.isOnline,
1654
+ reload: this.retry,
1655
+ refresh: this.refresh,
1656
+ isRefreshing: this.isRefreshing,
1657
+ latestRequest: this._latestRequest
1658
+ };
1659
+ if (feat.isRefreshing) {
1660
+ feat.abort = () => {
1661
+ this._latestRequest?.abort();
1662
+ };
1663
+ }
1664
+ return feat;
1665
+ }
1666
+
1667
+ /**
1668
+ * @internal
1669
+ */
1670
+ static {
1671
+ decorateMethodV2(this.prototype, "contentFeatures", [memoized]);
1672
+ }
1673
+ get _request() {
1674
+ const {
1675
+ request,
1676
+ query
1677
+ } = this._args;
1678
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1679
+ if (!test) {
1680
+ throw new Error(`Cannot use both @request and @query args with the <Request> component`);
1681
+ }
1682
+ })(!request || !query) : {};
1683
+ const {
1684
+ _localRequest,
1685
+ _originalRequest,
1686
+ _originalQuery
1687
+ } = this;
1688
+ const isOriginalRequest = request === _originalRequest && query === _originalQuery;
1689
+ if (_localRequest && isOriginalRequest) {
1690
+ return _localRequest;
1691
+ }
1692
+
1693
+ // update state checks for the next time
1694
+ this._originalQuery = query;
1695
+ this._originalRequest = request;
1696
+ if (request) {
1697
+ return request;
1698
+ }
1699
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1700
+ if (!test) {
1701
+ throw new Error(`You must provide either @request or an @query arg with the <Request> component`);
1702
+ }
1703
+ })(query) : {};
1704
+ return this.store.request(query);
1705
+ }
1706
+ static {
1707
+ decorateMethodV2(this.prototype, "_request", [memoized]);
1708
+ }
1709
+ get request() {
1710
+ if (macroCondition(getGlobalConfig().WarpDrive.env.DEBUG)) {
1711
+ try {
1712
+ const request = this._request;
1713
+ this._updateSubscriptions();
1714
+ return request;
1715
+ } catch (e) {
1716
+ // eslint-disable-next-line no-console
1717
+ console.log(e);
1718
+ throw new Error(`Unable to initialize the request`, {
1719
+ cause: e
1720
+ });
1721
+ }
1722
+ } else {
1723
+ const request = this._request;
1724
+ this._updateSubscriptions();
1725
+ return request;
1726
+ }
1727
+ }
1728
+ static {
1729
+ decorateMethodV2(this.prototype, "request", [memoized]);
1730
+ }
1731
+ get reqState() {
1732
+ return getRequestState(this.request);
1733
+ }
1734
+ get result() {
1735
+ return this.reqState.result;
1736
+ }
1737
+ }
1738
+ defineSignal(RequestSubscription.prototype, 'isOnline', true);
1739
+ defineSignal(RequestSubscription.prototype, 'isHidden', false);
1740
+ defineSignal(RequestSubscription.prototype, 'isRefreshing', false);
1741
+ defineSignal(RequestSubscription.prototype, '_localRequest', undefined);
1742
+ defineSignal(RequestSubscription.prototype, '_latestRequest', undefined);
1743
+ function isStore(store) {
1744
+ return 'requestManager' in store;
1745
+ }
1746
+ function createRequestSubscription(store, args) {
1747
+ return new RequestSubscription(store, args);
1748
+ }
1749
+ function upgradeSubscription(sub) {
1750
+ return sub;
1751
+ }
1752
+ function _DISPOSE() {
1753
+ const self = upgradeSubscription(this);
1754
+ self.isDestroyed = true;
1755
+ self._removeSubscriptions();
1756
+ if (typeof window === 'undefined') {
1757
+ return;
1758
+ }
1759
+ self._clearInterval();
1760
+ window.removeEventListener('online', self._onlineChanged, {
1761
+ passive: true,
1762
+ capture: true
1763
+ });
1764
+ window.removeEventListener('offline', self._onlineChanged, {
1765
+ passive: true,
1766
+ capture: true
1767
+ });
1768
+ document.removeEventListener('visibilitychange', self._backgroundChanged, {
1769
+ passive: true,
1770
+ capture: true
1771
+ });
1772
+ }
1773
+ const PromiseCache = new WeakMap();
1774
+
1775
+ /**
1776
+ * The state of a promise in the "pending"
1777
+ * state. This is the default initial state.
1778
+ *
1779
+ */
1780
+
1781
+ /**
1782
+ * The state of a promise in the "fulfilled" state.
1783
+ * This is the state of a promise that has resolved
1784
+ * successfully.
1785
+ *
1786
+ */
1787
+
1788
+ /**
1789
+ * The state of a promise in the "rejected" state.
1790
+ * This is the state of a promise that has rejected
1791
+ * with an error.
1792
+ *
1793
+ */
1794
+
1795
+ /**
1796
+ * The state of a promise. This is the type that is returned
1797
+ * from `getPromiseState`.
1798
+ *
1799
+ * See also:
1800
+ * - {@link PendingPromise}
1801
+ * - {@link ResolvedPromise}
1802
+ * - {@link RejectedPromise}
1803
+ *
1804
+ */
1805
+
1806
+ const PromiseStateProto = {};
1807
+
1808
+ // TODO introduce a new mechanism for defining multiple properties
1809
+ // that share a common signal
1810
+ defineSignal(PromiseStateProto, 'reason', null);
1811
+ defineSignal(PromiseStateProto, 'value', null);
1812
+ defineSignal(PromiseStateProto, 'result', null);
1813
+ defineSignal(PromiseStateProto, 'error', null);
1814
+ defineSignal(PromiseStateProto, 'status', 'pending');
1815
+ defineSignal(PromiseStateProto, 'isPending', true);
1816
+ defineSignal(PromiseStateProto, 'isLoading', true);
1817
+ defineSignal(PromiseStateProto, 'isSuccess', false);
1818
+ defineSignal(PromiseStateProto, 'isError', false);
1819
+ function createPromiseState(promise) {
1820
+ const state = getPromiseResult(promise);
1821
+ const promiseState = Object.create(PromiseStateProto);
1822
+ if (state) {
1823
+ if (state.isError) {
1824
+ promiseState.error = state.result;
1825
+ promiseState.reason = state.result;
1826
+ promiseState.status = 'rejected';
1827
+ promiseState.isError = true;
1828
+ promiseState.isPending = false;
1829
+ promiseState.isLoading = false;
1830
+ } else {
1831
+ promiseState.result = state.result;
1832
+ promiseState.value = state.result;
1833
+ promiseState.status = 'fulfilled';
1834
+ promiseState.isSuccess = true;
1835
+ promiseState.isPending = false;
1836
+ promiseState.isLoading = false;
1837
+ }
1838
+ } else {
1839
+ void promise.then(result => {
1840
+ setPromiseResult(promise, {
1841
+ isError: false,
1842
+ result
1843
+ });
1844
+ promiseState.result = result;
1845
+ promiseState.value = result;
1846
+ promiseState.status = 'fulfilled';
1847
+ promiseState.isSuccess = true;
1848
+ promiseState.isPending = false;
1849
+ promiseState.isLoading = false;
1850
+ }, error => {
1851
+ setPromiseResult(promise, {
1852
+ isError: true,
1853
+ result: error
1854
+ });
1855
+ promiseState.error = error;
1856
+ promiseState.reason = error;
1857
+ promiseState.status = 'rejected';
1858
+ promiseState.isError = true;
1859
+ promiseState.isPending = false;
1860
+ promiseState.isLoading = false;
1861
+ });
1862
+ }
1863
+ return promiseState;
1864
+ }
1865
+ const LegacyPromiseProxy = Symbol.for('LegacyPromiseProxy');
1866
+ function isLegacyAwaitable(promise) {
1867
+ return LegacyPromiseProxy in promise && 'promise' in promise && promise[LegacyPromiseProxy] === true;
1868
+ }
1869
+ function getPromise(promise) {
1870
+ return isLegacyAwaitable(promise) ? promise.promise : promise;
1871
+ }
1872
+
1873
+ /**
1874
+ * Returns a reactive state-machine for the provided promise or awaitable.
1875
+ *
1876
+ * Repeat calls to `getPromiseState` with the same promise will return the same state object
1877
+ * making is safe and easy to use in templates and JavaScript code to produce reactive
1878
+ * behaviors around promises.
1879
+ *
1880
+ * `getPromiseState` can be used in both JavaScript and Template contexts.
1881
+ *
1882
+ * ```ts
1883
+ * import { getPromiseState } from '@warp-drive/ember';
1884
+ *
1885
+ * const state = getPromiseState(promise);
1886
+ * ```
1887
+ *
1888
+ * For instance, we could write a getter on a component that updates whenever
1889
+ * the promise state advances or the promise changes, by combining the function
1890
+ * with the use of `@cached`
1891
+ *
1892
+ * ```ts
1893
+ * class Component {
1894
+ * @cached
1895
+ * get title() {
1896
+ * const state = getPromiseState(this.args.request);
1897
+ * if (state.isPending) {
1898
+ * return 'loading...';
1899
+ * }
1900
+ * if (state.isError) { return null; }
1901
+ * return state.result.title;
1902
+ * }
1903
+ * }
1904
+ * ```
1905
+ *
1906
+ * Or in a template as a helper:
1907
+ *
1908
+ * ```gjs
1909
+ * import { getPromiseState } from '@warp-drive/ember';
1910
+ *
1911
+ * <template>
1912
+ * {{#let (getPromiseState @request) as |state|}}
1913
+ * {{#if state.isPending}} <Spinner />
1914
+ * {{else if state.isError}} <ErrorForm @error={{state.error}} />
1915
+ * {{else}}
1916
+ * <h1>{{state.result.title}}</h1>
1917
+ * {{/if}}
1918
+ * {{/let}}
1919
+ * </template>
1920
+ * ```
1921
+ *
1922
+ * If looking to use in a template, consider also the `<Await />` component.
1923
+ *
1924
+ * See also {@link PromiseState}
1925
+ */
1926
+ function getPromiseState(promise) {
1927
+ macroCondition(getGlobalConfig().WarpDrive.env.DEBUG) ? (test => {
1928
+ if (!test) {
1929
+ throw new Error(`getPromiseState expects to be called with a promise: called with ${String(promise)}`);
1930
+ }
1931
+ })(promise) : {};
1932
+ const _promise = getPromise(promise);
1933
+ let state = PromiseCache.get(_promise);
1934
+ if (!state) {
1935
+ state = createPromiseState(_promise);
1936
+ PromiseCache.set(_promise, state);
1937
+ }
1938
+ return state;
1939
+ }
1940
+ export { ARRAY_SIGNAL as A, DISPOSE as D, OBJECT_SIGNAL as O, Signals as S, defineGate as a, defineSignal as b, withSignalStore as c, defineNonEnumerableSignal as d, entangleSignal as e, createRequestSubscription as f, gate as g, getRequestState as h, getPromiseState as i, willSyncFlushWatchers as j, getOrCreateInternalSignal as k, consumeInternalSignal as l, memoized as m, notifyInternalSignal as n, createInternalSignal as o, peekInternalSignal as p, createSignalDescriptor as q, entangleInitiallyStaleSignal as r, signal as s, createInternalMemo as t, setupSignals as u, waitFor as w };