@warp-drive/core 5.9.0-beta.1 → 5.9.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/dist/-private-BL9zXgJB.js +3530 -0
  2. package/dist/-private-BL9zXgJB.js.map +1 -0
  3. package/dist/{-private-DMzvF_Q6.js → -private-Cxa8cMBj.js} +2 -2
  4. package/dist/-private-Cxa8cMBj.js.map +1 -0
  5. package/dist/{unpkg/dev-deprecated/-private-DL4tfrv9.js → -private-xK1KgxZJ.js} +2 -2
  6. package/dist/{-private-b1g4dhl0.js.map → -private-xK1KgxZJ.js.map} +1 -1
  7. package/{declarations/concepts-LHsLJZMl.d.ts → dist/concepts-DFldVwEM.d.ts} +2 -2
  8. package/{declarations/concepts-LHsLJZMl.d.ts.map → dist/concepts-DFldVwEM.d.ts.map} +1 -1
  9. package/dist/configure.js +1 -1
  10. package/dist/graph/-private.d.ts +2 -0
  11. package/dist/graph/-private.js +46 -33
  12. package/dist/graph/-private.js.map +1 -1
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +1 -1
  15. package/{declarations/internal-Cz-893zD.d.ts → dist/internal-DtWOpxrR.d.ts} +2763 -2271
  16. package/dist/internal-DtWOpxrR.d.ts.map +1 -0
  17. package/dist/reactive/-private.d.ts +2 -0
  18. package/dist/reactive/-private.js +1 -1
  19. package/dist/reactive.d.ts +2 -0
  20. package/dist/reactive.js +3 -3
  21. package/{declarations → dist}/record-D3QQcaIR.d.ts.map +1 -1
  22. package/dist/{request--vRFALbQ.js → request-z2NByNx0.js} +2 -2
  23. package/dist/request-z2NByNx0.js.map +1 -0
  24. package/dist/request.d.ts +2 -0
  25. package/dist/request.js +1 -1
  26. package/dist/signals/-leaked.d.ts +1060 -0
  27. package/dist/signals/-leaked.d.ts.map +1 -0
  28. package/dist/signals/-leaked.js +2 -2
  29. package/dist/{src-Dex_phWI.js → src-s5HHjglV.js} +192 -53
  30. package/dist/src-s5HHjglV.js.map +1 -0
  31. package/dist/store/-private.d.ts +2 -0
  32. package/dist/store/-private.js +1 -1
  33. package/dist/store-DNF9Rgoh.js.map +1 -1
  34. package/dist/store.d.ts +2 -0
  35. package/{declarations → dist}/types/-private.d.ts +1 -1
  36. package/{declarations → dist}/types/-private.d.ts.map +1 -1
  37. package/dist/types/-private.js +1 -1
  38. package/dist/types/cache.d.ts +2 -0
  39. package/dist/types/record.js.map +1 -1
  40. package/dist/types/request.d.ts +2 -0
  41. package/dist/types/request.js +1 -1
  42. package/dist/types/request.js.map +1 -1
  43. package/dist/types/runtime.js +1 -1
  44. package/dist/types/schema/concepts.d.ts +2 -0
  45. package/dist/types/schema/fields.js.map +1 -1
  46. package/dist/types/schema/schema-service.d.ts +2 -0
  47. package/dist/types/symbols.js +1 -1
  48. package/dist/types/symbols.js.map +1 -1
  49. package/{declarations → dist}/types.d.ts +1 -1
  50. package/dist/{-private-b1g4dhl0.js → unpkg/dev/-private-BGCYELwo.js} +2 -2
  51. package/dist/unpkg/{dev-deprecated/-private-DL4tfrv9.js.map → dev/-private-BGCYELwo.js.map} +1 -1
  52. package/dist/unpkg/{dev-deprecated/-private-2RfQ2761.js → dev/-private-DhiS6yOR.js} +2 -2
  53. package/dist/unpkg/dev/-private-DhiS6yOR.js.map +1 -0
  54. package/dist/unpkg/dev/-private-pNQae3qH.js +3519 -0
  55. package/dist/unpkg/dev/-private-pNQae3qH.js.map +1 -0
  56. package/dist/unpkg/dev/configure.js +1 -1
  57. package/dist/unpkg/dev/graph/-private.js +46 -33
  58. package/dist/unpkg/dev/graph/-private.js.map +1 -1
  59. package/dist/unpkg/dev/index.js +1 -1
  60. package/dist/unpkg/dev/reactive/-private.js +1 -1
  61. package/dist/unpkg/dev/reactive.js +3 -3
  62. package/dist/unpkg/{dev-deprecated/request-DAuXbfYi.js → dev/request-BbbzRou7.js} +2 -2
  63. package/dist/unpkg/dev/request-BbbzRou7.js.map +1 -0
  64. package/dist/unpkg/dev/request.js +1 -1
  65. package/dist/unpkg/dev/{runtime-EoVKAhTv.js → runtime-DoDtzXJb.js} +2 -2
  66. package/dist/unpkg/dev/runtime-DoDtzXJb.js.map +1 -0
  67. package/dist/unpkg/dev/signals/-leaked.js +2 -2
  68. package/dist/unpkg/dev/{src-Bxlr_vue.js → src-Cf7NXXR2.js} +194 -55
  69. package/dist/unpkg/dev/src-Cf7NXXR2.js.map +1 -0
  70. package/dist/unpkg/dev/store/-private.js +1 -1
  71. package/dist/unpkg/{dev-deprecated/store-TcP2H4Af.js → dev/store-DamE3C4y.js} +2 -2
  72. package/dist/unpkg/dev/store-DamE3C4y.js.map +1 -0
  73. package/dist/unpkg/dev/store.js +1 -1
  74. package/dist/unpkg/dev/types/-private.js +1 -1
  75. package/dist/unpkg/dev/types/record.js.map +1 -1
  76. package/dist/unpkg/dev/types/request.js +1 -1
  77. package/dist/unpkg/dev/types/request.js.map +1 -1
  78. package/dist/unpkg/dev/types/runtime.js +1 -1
  79. package/dist/unpkg/dev/types/schema/fields.js.map +1 -1
  80. package/dist/unpkg/dev/types/symbols.js +1 -1
  81. package/dist/unpkg/dev/types/symbols.js.map +1 -1
  82. package/dist/unpkg/{dev/-private-DL4tfrv9.js → dev-deprecated/-private-BGCYELwo.js} +2 -2
  83. package/dist/unpkg/{prod/-private-Z9i0icpE.js.map → dev-deprecated/-private-BGCYELwo.js.map} +1 -1
  84. package/dist/unpkg/{dev/-private-2RfQ2761.js → dev-deprecated/-private-DhiS6yOR.js} +2 -2
  85. package/dist/unpkg/dev-deprecated/-private-DhiS6yOR.js.map +1 -0
  86. package/dist/unpkg/dev-deprecated/-private-pNQae3qH.js +3519 -0
  87. package/dist/unpkg/dev-deprecated/-private-pNQae3qH.js.map +1 -0
  88. package/dist/unpkg/dev-deprecated/configure.js +1 -1
  89. package/dist/unpkg/dev-deprecated/graph/-private.js +47 -34
  90. package/dist/unpkg/dev-deprecated/graph/-private.js.map +1 -1
  91. package/dist/unpkg/dev-deprecated/index.js +1 -1
  92. package/dist/unpkg/dev-deprecated/reactive/-private.js +1 -1
  93. package/dist/unpkg/dev-deprecated/reactive.js +3 -3
  94. package/dist/unpkg/{dev/request-DAuXbfYi.js → dev-deprecated/request-BbbzRou7.js} +2 -2
  95. package/dist/unpkg/dev-deprecated/request-BbbzRou7.js.map +1 -0
  96. package/dist/unpkg/dev-deprecated/request.js +1 -1
  97. package/dist/unpkg/dev-deprecated/{runtime-BacZMq1r.js → runtime-CPL2BGgT.js} +2 -2
  98. package/dist/unpkg/dev-deprecated/runtime-CPL2BGgT.js.map +1 -0
  99. package/dist/unpkg/dev-deprecated/signals/-leaked.js +2 -2
  100. package/dist/unpkg/dev-deprecated/{src-DEl2Ca3T.js → src-CSuFUXv4.js} +195 -56
  101. package/dist/unpkg/dev-deprecated/src-CSuFUXv4.js.map +1 -0
  102. package/dist/unpkg/dev-deprecated/store/-private.js +1 -1
  103. package/dist/unpkg/{dev/store-DmiFvT1B.js → dev-deprecated/store-Bsdz5mRe.js} +2 -2
  104. package/dist/unpkg/dev-deprecated/store-Bsdz5mRe.js.map +1 -0
  105. package/dist/unpkg/dev-deprecated/store.js +1 -1
  106. package/dist/unpkg/dev-deprecated/types/-private.js +1 -1
  107. package/dist/unpkg/dev-deprecated/types/record.js.map +1 -1
  108. package/dist/unpkg/dev-deprecated/types/request.js +1 -1
  109. package/dist/unpkg/dev-deprecated/types/request.js.map +1 -1
  110. package/dist/unpkg/dev-deprecated/types/runtime.js +1 -1
  111. package/dist/unpkg/dev-deprecated/types/schema/fields.js.map +1 -1
  112. package/dist/unpkg/dev-deprecated/types/symbols.js +1 -1
  113. package/dist/unpkg/dev-deprecated/types/symbols.js.map +1 -1
  114. package/dist/unpkg/prod/-private-8gd8hbwm.js +22 -0
  115. package/dist/unpkg/{prod-deprecated/-private-Z9i0icpE.js.map → prod/-private-8gd8hbwm.js.map} +1 -1
  116. package/dist/unpkg/prod/{-private-BK71-uXR.js → -private-B6aLbrgV.js} +2 -2
  117. package/dist/unpkg/prod/-private-B6aLbrgV.js.map +1 -0
  118. package/dist/unpkg/prod/-private-ggVX_Iob.js +3294 -0
  119. package/dist/unpkg/prod/-private-ggVX_Iob.js.map +1 -0
  120. package/dist/unpkg/prod/configure.js +1 -1
  121. package/dist/unpkg/prod/graph/-private.js +45 -32
  122. package/dist/unpkg/prod/graph/-private.js.map +1 -1
  123. package/dist/unpkg/prod/index.js +1 -1
  124. package/dist/unpkg/prod/reactive/-private.js +1 -1
  125. package/dist/unpkg/prod/reactive.js +3 -3
  126. package/dist/unpkg/prod/{request-BcJNzSgv.js → request-BoeppjDj.js} +2 -2
  127. package/dist/unpkg/prod/request-BoeppjDj.js.map +1 -0
  128. package/dist/unpkg/prod/request.js +1 -1
  129. package/dist/unpkg/prod/signals/-leaked.js +2 -2
  130. package/dist/unpkg/prod/{src-Dzz-j6pp.js → src-C0wuASrN.js} +196 -53
  131. package/dist/unpkg/prod/src-C0wuASrN.js.map +1 -0
  132. package/dist/unpkg/prod/store/-private.js +1 -1
  133. package/dist/unpkg/prod/store-BWhmb7Ob.js.map +1 -1
  134. package/dist/unpkg/prod/types/-private.js +1 -1
  135. package/dist/unpkg/prod/types/record.js.map +1 -1
  136. package/dist/unpkg/prod/types/request.js +1 -1
  137. package/dist/unpkg/prod/types/request.js.map +1 -1
  138. package/dist/unpkg/prod/types/runtime.js +1 -1
  139. package/dist/unpkg/prod/types/schema/fields.js.map +1 -1
  140. package/dist/unpkg/prod/types/symbols.js +1 -1
  141. package/dist/unpkg/prod/types/symbols.js.map +1 -1
  142. package/dist/unpkg/prod-deprecated/{-private-Z9i0icpE.js → -private-8gd8hbwm.js} +2 -2
  143. package/dist/unpkg/{dev/-private-DL4tfrv9.js.map → prod-deprecated/-private-8gd8hbwm.js.map} +1 -1
  144. package/dist/unpkg/prod-deprecated/{-private-BK71-uXR.js → -private-B6aLbrgV.js} +2 -2
  145. package/dist/unpkg/prod-deprecated/-private-B6aLbrgV.js.map +1 -0
  146. package/dist/unpkg/prod-deprecated/-private-ggVX_Iob.js +3294 -0
  147. package/dist/unpkg/prod-deprecated/-private-ggVX_Iob.js.map +1 -0
  148. package/dist/unpkg/prod-deprecated/configure.js +1 -1
  149. package/dist/unpkg/prod-deprecated/graph/-private.js +46 -35
  150. package/dist/unpkg/prod-deprecated/graph/-private.js.map +1 -1
  151. package/dist/unpkg/prod-deprecated/index.js +1 -1
  152. package/dist/unpkg/prod-deprecated/reactive/-private.js +1 -1
  153. package/dist/unpkg/prod-deprecated/reactive.js +3 -3
  154. package/dist/unpkg/prod-deprecated/{request-BcJNzSgv.js → request-BoeppjDj.js} +2 -2
  155. package/dist/unpkg/prod-deprecated/request-BoeppjDj.js.map +1 -0
  156. package/dist/unpkg/prod-deprecated/request.js +1 -1
  157. package/dist/unpkg/prod-deprecated/signals/-leaked.js +2 -2
  158. package/dist/unpkg/prod-deprecated/{src-BOifHFQ5.js → src-BXOgNqmz.js} +197 -54
  159. package/dist/unpkg/prod-deprecated/src-BXOgNqmz.js.map +1 -0
  160. package/dist/unpkg/prod-deprecated/store/-private.js +1 -1
  161. package/dist/unpkg/prod-deprecated/store-BWhmb7Ob.js.map +1 -1
  162. package/dist/unpkg/prod-deprecated/types/-private.js +1 -1
  163. package/dist/unpkg/prod-deprecated/types/record.js.map +1 -1
  164. package/dist/unpkg/prod-deprecated/types/request.js +1 -1
  165. package/dist/unpkg/prod-deprecated/types/request.js.map +1 -1
  166. package/dist/unpkg/prod-deprecated/types/runtime.js +1 -1
  167. package/dist/unpkg/prod-deprecated/types/schema/fields.js.map +1 -1
  168. package/dist/unpkg/prod-deprecated/types/symbols.js +1 -1
  169. package/dist/unpkg/prod-deprecated/types/symbols.js.map +1 -1
  170. package/package.json +15 -19
  171. package/declarations/graph/-private.d.ts +0 -2
  172. package/declarations/index.d.ts +0 -2
  173. package/declarations/internal-Cz-893zD.d.ts.map +0 -1
  174. package/declarations/reactive/-private.d.ts +0 -2
  175. package/declarations/reactive.d.ts +0 -2
  176. package/declarations/request.d.ts +0 -2
  177. package/declarations/signals/-leaked.d.ts +0 -63
  178. package/declarations/signals/-leaked.d.ts.map +0 -1
  179. package/declarations/store/-private.d.ts +0 -2
  180. package/declarations/store.d.ts +0 -8358
  181. package/declarations/store.d.ts.map +0 -1
  182. package/declarations/types/cache.d.ts +0 -2
  183. package/declarations/types/request.d.ts +0 -2
  184. package/declarations/types/schema/concepts.d.ts +0 -2
  185. package/declarations/types/schema/schema-service.d.ts +0 -2
  186. package/dist/-private-DMzvF_Q6.js.map +0 -1
  187. package/dist/-private-HjaQ1wp1.js +0 -1695
  188. package/dist/-private-HjaQ1wp1.js.map +0 -1
  189. package/dist/request--vRFALbQ.js.map +0 -1
  190. package/dist/src-Dex_phWI.js.map +0 -1
  191. package/dist/unpkg/dev/-private-2RfQ2761.js.map +0 -1
  192. package/dist/unpkg/dev/-private-CM1zxNws.js +0 -1684
  193. package/dist/unpkg/dev/-private-CM1zxNws.js.map +0 -1
  194. package/dist/unpkg/dev/request-DAuXbfYi.js.map +0 -1
  195. package/dist/unpkg/dev/runtime-EoVKAhTv.js.map +0 -1
  196. package/dist/unpkg/dev/src-Bxlr_vue.js.map +0 -1
  197. package/dist/unpkg/dev/store-DmiFvT1B.js.map +0 -1
  198. package/dist/unpkg/dev-deprecated/-private-2RfQ2761.js.map +0 -1
  199. package/dist/unpkg/dev-deprecated/-private-CM1zxNws.js +0 -1684
  200. package/dist/unpkg/dev-deprecated/-private-CM1zxNws.js.map +0 -1
  201. package/dist/unpkg/dev-deprecated/request-DAuXbfYi.js.map +0 -1
  202. package/dist/unpkg/dev-deprecated/runtime-BacZMq1r.js.map +0 -1
  203. package/dist/unpkg/dev-deprecated/src-DEl2Ca3T.js.map +0 -1
  204. package/dist/unpkg/dev-deprecated/store-TcP2H4Af.js.map +0 -1
  205. package/dist/unpkg/prod/-private-BK71-uXR.js.map +0 -1
  206. package/dist/unpkg/prod/-private-TNaS5Piv.js +0 -1494
  207. package/dist/unpkg/prod/-private-TNaS5Piv.js.map +0 -1
  208. package/dist/unpkg/prod/-private-Z9i0icpE.js +0 -22
  209. package/dist/unpkg/prod/request-BcJNzSgv.js.map +0 -1
  210. package/dist/unpkg/prod/src-Dzz-j6pp.js.map +0 -1
  211. package/dist/unpkg/prod-deprecated/-private-BK71-uXR.js.map +0 -1
  212. package/dist/unpkg/prod-deprecated/-private-TNaS5Piv.js +0 -1494
  213. package/dist/unpkg/prod-deprecated/-private-TNaS5Piv.js.map +0 -1
  214. package/dist/unpkg/prod-deprecated/request-BcJNzSgv.js.map +0 -1
  215. package/dist/unpkg/prod-deprecated/src-BOifHFQ5.js.map +0 -1
  216. /package/{declarations → dist}/aliases-BWYW5EhX.d.ts +0 -0
  217. /package/{declarations → dist}/aliases-BWYW5EhX.d.ts.map +0 -0
  218. /package/{declarations → dist}/build-config/babel-macros.d.ts +0 -0
  219. /package/{declarations → dist}/build-config/canary-features.d.ts +0 -0
  220. /package/{declarations → dist}/build-config/debugging.d.ts +0 -0
  221. /package/{declarations → dist}/build-config/deprecations.d.ts +0 -0
  222. /package/{declarations → dist}/build-config/env.d.ts +0 -0
  223. /package/{declarations → dist}/build-config/macros.d.ts +0 -0
  224. /package/{declarations → dist}/build-config.d.ts +0 -0
  225. /package/{declarations → dist}/change-C7kqv2kW.d.ts +0 -0
  226. /package/{declarations → dist}/change-C7kqv2kW.d.ts.map +0 -0
  227. /package/{declarations → dist}/configure-B_F639tN.d.ts +0 -0
  228. /package/{declarations → dist}/configure-B_F639tN.d.ts.map +0 -0
  229. /package/{declarations → dist}/configure.d.ts +0 -0
  230. /package/{declarations → dist}/document-BEn91SwT.d.ts +0 -0
  231. /package/{declarations → dist}/document-BEn91SwT.d.ts.map +0 -0
  232. /package/{declarations → dist}/error-50OSEhsF.d.ts +0 -0
  233. /package/{declarations → dist}/error-50OSEhsF.d.ts.map +0 -0
  234. /package/{declarations → dist}/fields-FM7peCiM.d.ts +0 -0
  235. /package/{declarations → dist}/fields-FM7peCiM.d.ts.map +0 -0
  236. /package/{declarations → dist}/graph-DLqYXP2z.d.ts +0 -0
  237. /package/{declarations → dist}/graph-DLqYXP2z.d.ts.map +0 -0
  238. /package/{declarations → dist}/identifier-DQnqOSJK.d.ts +0 -0
  239. /package/{declarations → dist}/identifier-DQnqOSJK.d.ts.map +0 -0
  240. /package/{declarations → dist}/json-api-raw-C5APJHHB.d.ts +0 -0
  241. /package/{declarations → dist}/json-api-raw-C5APJHHB.d.ts.map +0 -0
  242. /package/{declarations → dist}/mutations-CqtoGB4t.d.ts +0 -0
  243. /package/{declarations → dist}/mutations-CqtoGB4t.d.ts.map +0 -0
  244. /package/{declarations → dist}/operations-D1qA6r0_.d.ts +0 -0
  245. /package/{declarations → dist}/operations-D1qA6r0_.d.ts.map +0 -0
  246. /package/{declarations → dist}/params-DrEx3bf8.d.ts +0 -0
  247. /package/{declarations → dist}/params-DrEx3bf8.d.ts.map +0 -0
  248. /package/{declarations → dist}/raw-D5hnjiq7.d.ts +0 -0
  249. /package/{declarations → dist}/raw-D5hnjiq7.d.ts.map +0 -0
  250. /package/{declarations → dist}/record-D3QQcaIR.d.ts +0 -0
  251. /package/{declarations → dist}/relationship-CmHzMPKf.d.ts +0 -0
  252. /package/{declarations → dist}/relationship-CmHzMPKf.d.ts.map +0 -0
  253. /package/{declarations → dist}/symbols-DjRDCeX0.d.ts +0 -0
  254. /package/{declarations → dist}/symbols-DjRDCeX0.d.ts.map +0 -0
  255. /package/{declarations → dist}/types/cache/aliases.d.ts +0 -0
  256. /package/{declarations → dist}/types/cache/change.d.ts +0 -0
  257. /package/{declarations → dist}/types/cache/mutations.d.ts +0 -0
  258. /package/{declarations → dist}/types/cache/operations.d.ts +0 -0
  259. /package/{declarations → dist}/types/cache/relationship.d.ts +0 -0
  260. /package/{declarations → dist}/types/graph.d.ts +0 -0
  261. /package/{declarations → dist}/types/identifier.d.ts +0 -0
  262. /package/{declarations → dist}/types/json/raw.d.ts +0 -0
  263. /package/{declarations → dist}/types/params.d.ts +0 -0
  264. /package/{declarations → dist}/types/record.d.ts +0 -0
  265. /package/{declarations → dist}/types/runtime.d.ts +0 -0
  266. /package/{declarations → dist}/types/runtime.d.ts.map +0 -0
  267. /package/{declarations → dist}/types/schema/fields.d.ts +0 -0
  268. /package/{declarations → dist}/types/schema/fields.type-test.d.ts +0 -0
  269. /package/{declarations → dist}/types/spec/document.d.ts +0 -0
  270. /package/{declarations → dist}/types/spec/error.d.ts +0 -0
  271. /package/{declarations → dist}/types/spec/json-api-raw.d.ts +0 -0
  272. /package/{declarations → dist}/types/symbols.d.ts +0 -0
  273. /package/{declarations → dist}/types/utils.d.ts +0 -0
  274. /package/{declarations → dist}/utils/string.d.ts +0 -0
  275. /package/{declarations → dist}/utils/string.d.ts.map +0 -0
  276. /package/{declarations → dist}/utils-BtURiy8l.d.ts +0 -0
  277. /package/{declarations → dist}/utils-BtURiy8l.d.ts.map +0 -0
@@ -0,0 +1,3519 @@
1
+ import { a as setTransient, r as peekTransient, t as getOrSetGlobal } from "./-private-DhiS6yOR.js";
2
+ import { f as setPromiseResult, o as DOMError, u as getPromiseResult } from "./request-BbbzRou7.js";
3
+
4
+ //#region src/signals/reactivity/configure.ts
5
+ const ARRAY_SIGNAL = getOrSetGlobal("#[]", Symbol("#[]"));
6
+ const OBJECT_SIGNAL = getOrSetGlobal("#{}", Symbol("#{}"));
7
+ /**
8
+ * An Opaque type that represents a framework specific or TC39 signal.
9
+ *
10
+ * It may be an array of signals or a single signal.
11
+ *
12
+ * @private
13
+ */
14
+ /**
15
+ * The hooks which MUST be configured in order to use reactive arrays,
16
+ * resources and documents with framework specfic signals or TC39 signals.
17
+ *
18
+ * Support for multiple frameworks simultaneously can be done via
19
+ * this abstraction by returning multiple signals from the `createSignal`
20
+ * method, and consuming the correct one via the correct framework via
21
+ * the `consumeSignal` and `notifySignal` methods.
22
+ *
23
+ * Unlike many signals implementations, WarpDrive does not wrap values as
24
+ * signals directly, but instead uses signals to alert the reactive layer
25
+ * to changes in the underlying cache. E.g. a signal is associated to a value,
26
+ * but does not serve as the cache for that value directly. We refer to this as
27
+ * a "gate", the pattern has also been called "side-signals".
28
+ *
29
+ * A no-op implementation is allowed, though it may lead to performance issues
30
+ * in locations that use createMemo as no memoization would be done. This is
31
+ * typically desirable only when integrating with a framework that does its own
32
+ * memoization and does not integrate with any signals-like primitive. For these
33
+ * scenarios you may also be interested in integrating with the {@link NotificationManager}
34
+ * more directly.
35
+ *
36
+ * @public
37
+ */
38
+ /**
39
+ * Contains information a {@link SignalHooks} implementation may want
40
+ * to use, such as the specialized key used for the signal
41
+ * representing an array's contents / length.
42
+ *
43
+ * ```ts
44
+ * interface HooksOptions {
45
+ * wellknown: {
46
+ * Array: symbol | string;
47
+ * }
48
+ * }
49
+ * ```
50
+ *
51
+ * @public
52
+ */
53
+ /**
54
+ * Configures the signals implementation to use. Supports multiple
55
+ * implementations simultaneously.
56
+ *
57
+ * See {@link HooksOptions} for the options passed to the provided function
58
+ * when called.
59
+ *
60
+ * See {@link SignalHooks} for the implementation the callback function should
61
+ * return.
62
+ *
63
+ * @public
64
+ * @param buildConfig - a function that takes options and returns a configuration object
65
+ */
66
+ function setupSignals(buildConfig) {
67
+ const hooks = buildConfig({ wellknown: { Array: ARRAY_SIGNAL } });
68
+ setTransient("signalHooks", hooks);
69
+ }
70
+ /**
71
+ * Internal method for consuming the configured `createSignal` hook
72
+ *
73
+ * @private
74
+ */
75
+ function createSignal(obj, key) {
76
+ const signalHooks = peekTransient("signalHooks");
77
+ ((test) => {
78
+ if (!test) throw new Error(`Signal hooks not configured`);
79
+ })(signalHooks);
80
+ return signalHooks.createSignal(obj, key);
81
+ }
82
+ /**
83
+ * Internal method for consuming the configured `consumeSignal` hook
84
+ *
85
+ * @private
86
+ */
87
+ function consumeSignal(signal) {
88
+ const signalHooks = peekTransient("signalHooks");
89
+ ((test) => {
90
+ if (!test) throw new Error(`Signal hooks not configured`);
91
+ })(signalHooks);
92
+ return signalHooks.consumeSignal(signal);
93
+ }
94
+ /**
95
+ * Internal method for consuming the configured `notifySignal` hook
96
+ *
97
+ * @private
98
+ */
99
+ function notifySignal(signal) {
100
+ const signalHooks = peekTransient("signalHooks");
101
+ ((test) => {
102
+ if (!test) throw new Error(`Signal hooks not configured`);
103
+ })(signalHooks);
104
+ return signalHooks.notifySignal(signal);
105
+ }
106
+ function createMemo(object, key, fn) {
107
+ const signalHooks = peekTransient("signalHooks");
108
+ ((test) => {
109
+ if (!test) throw new Error(`Signal hooks not configured`);
110
+ })(signalHooks);
111
+ return signalHooks.createMemo(object, key, fn);
112
+ }
113
+ function willSyncFlushWatchers() {
114
+ const signalHooks = peekTransient("signalHooks");
115
+ ((test) => {
116
+ if (!test) throw new Error(`Signal hooks not configured`);
117
+ })(signalHooks);
118
+ return signalHooks.willSyncFlushWatchers();
119
+ }
120
+ /**
121
+ * Wraps `promise` using the configured {@link SignalHooks.waitFor}, if any,
122
+ * for things like test-waiters. Returns `promise` unchanged if no
123
+ * `waitFor` hook is configured.
124
+ */
125
+ function waitFor(promise) {
126
+ const signalHooks = peekTransient("signalHooks");
127
+ if (signalHooks?.waitFor) return signalHooks.waitFor(promise);
128
+ return promise;
129
+ }
130
+
131
+ //#endregion
132
+ //#region src/signals/reactivity/internal.ts
133
+ const INITIALIZER_PROTO = { isInitializer: true };
134
+ /**
135
+ * Wraps `fn` so that a signal can recognize it as a lazy initializer
136
+ * for its value rather than the value itself, deferring the call to
137
+ * `fn` until the signal is first accessed.
138
+ */
139
+ function makeInitializer(fn) {
140
+ return Object.assign(Object.create(INITIALIZER_PROTO), { value: fn });
141
+ }
142
+ function isInitializer(obj) {
143
+ return typeof obj === "object" && obj !== null && Object.getPrototypeOf(obj) === INITIALIZER_PROTO;
144
+ }
145
+ /**
146
+ * A WarpDriveSignal is a wrapper around a framework specific or TC39 signal
147
+ * that enables us to store and manage the signal in a universal way.
148
+ *
149
+ * WarpDrive uses signals to manage three separate concepts:
150
+ *
151
+ * - as a `storage` for a value local to the object that we want to be reactive
152
+ * (see `@local` schema field for an example)
153
+ * - as a `gate` for a memoized getter that we want to act as a reactive property
154
+ * but whose value is computed/pulled from a non-reactive source elsewhere
155
+ * and whose latest value is stored in the signal
156
+ * (see `field` schema field for an example)
157
+ * - as a `gate` with a manually managed value updated on pull when `isStale` is true
158
+ *
159
+ *
160
+ * It offers
161
+ *
162
+ * - a non-reactive way to access/update the current value
163
+ * - a non-reactive way to mark the signal as dirtied
164
+ * - a non-reactive way to store content for why the signal was dirtied
165
+ * - access to the underlying Signal(s) in-use
166
+ *
167
+ * For debugging:
168
+ * - the "key" or "name" of the signal
169
+ * - the "object identity" or "context" to which the signal is attached
170
+ *
171
+ * @private
172
+ */
173
+ /**
174
+ * We attach signals to their context object via
175
+ * a Map attached to the object via this symbol.
176
+ *
177
+ * This allows us to store multiple signals
178
+ * on the same object with smaller memory
179
+ * overhead and no WeakMap lookups.
180
+ *
181
+ * Performance sensitive objects should
182
+ * pre-warm their shape by assigning this
183
+ * during initialization.
184
+ *
185
+ * ```ts
186
+ * initializeSignalStore(obj);
187
+ * ```
188
+ *
189
+ * @private
190
+ */
191
+ const Signals = getOrSetGlobal("Signals", Symbol("Signals"));
192
+ /**
193
+ * A type util to recast the object as having a signal store.
194
+ *
195
+ * @private
196
+ */
197
+ function upgradeWithSignals(obj) {}
198
+ /**
199
+ * A util that will create a signal store on the object
200
+ * if it does not already exist and returns the associated
201
+ * signal store.
202
+ *
203
+ * @private
204
+ */
205
+ function withSignalStore(obj) {
206
+ /* @__PURE__ */ upgradeWithSignals(obj);
207
+ if (!obj[Signals]) initializeSignalStore(obj);
208
+ return obj[Signals];
209
+ }
210
+ /**
211
+ * A util that will create a signal store on the object
212
+ * if it does not already exist.
213
+ *
214
+ * Useful for pre-warming the shape of an object to ensure
215
+ * a key-transition to add it is not required later.
216
+ *
217
+ * @private
218
+ */
219
+ function initializeSignalStore(obj) {
220
+ /* @__PURE__ */ upgradeWithSignals(obj);
221
+ ((test) => {
222
+ if (!test) throw new Error(`Signal store already exists on object`);
223
+ })(!obj[Signals]);
224
+ obj[Signals] = /* @__PURE__ */ new Map();
225
+ }
226
+ function createInternalSignal(signals, obj, key, initialValue) {
227
+ const warpDriveSignal = {
228
+ key,
229
+ context: obj,
230
+ signal: createSignal(obj, key),
231
+ value: isInitializer(initialValue) ? initialValue.value.call(obj) : initialValue,
232
+ isStale: false
233
+ };
234
+ signals.set(key, warpDriveSignal);
235
+ return warpDriveSignal;
236
+ }
237
+ function getOrCreateInternalSignal(signals, obj, key, initialValue) {
238
+ let signal = peekInternalSignal(signals, key);
239
+ if (!signal) signal = createInternalSignal(signals, obj, key, initialValue);
240
+ return signal;
241
+ }
242
+ function createInternalMemo(signals, object, key, fn) {
243
+ ((test) => {
244
+ if (!test) throw new Error(`Expected no signal/memo to exist for key "${String(key)}"`);
245
+ })(!peekInternalSignal(signals, key));
246
+ return withFrame(signals, object, key, fn);
247
+ }
248
+ /**
249
+ * Looks up the {@link WarpDriveSignal} stored for `key` in `signals`,
250
+ * if one has already been created, without creating or consuming it.
251
+ */
252
+ function peekInternalSignal(signals, key) {
253
+ return signals?.get(key);
254
+ }
255
+ function consumeInternalSignal(signal) {
256
+ TrackingFrame?.signals.add(signal);
257
+ consumeSignal(signal.signal);
258
+ }
259
+ /**
260
+ * Marks `signal` as stale and notifies its underlying framework/TC39
261
+ * signal, scheduling any of its consumers for re-render/re-computation.
262
+ */
263
+ function notifyInternalSignal(signal) {
264
+ if (signal) {
265
+ signal.isStale = true;
266
+ notifySignal(signal.signal);
267
+ }
268
+ }
269
+ let TrackingFrame = null;
270
+ /**
271
+ * This is currently just for signals debugging, but it could be used in production
272
+ * if we wanted to eliminate the need for frameworks to implement createMemo / to
273
+ * allow us to add our own Watcher.
274
+ *
275
+ * @internal
276
+ */
277
+ function withFrame(signals, object, key, fn) {
278
+ const frameSignals = /* @__PURE__ */ new Set();
279
+ const frameFn = () => {
280
+ if (frameSignals.size) frameSignals.clear();
281
+ TrackingFrame = {
282
+ object,
283
+ key,
284
+ signals: frameSignals,
285
+ parent: TrackingFrame
286
+ };
287
+ try {
288
+ return fn();
289
+ } finally {
290
+ TrackingFrame = TrackingFrame.parent;
291
+ }
292
+ };
293
+ const memo = createMemo(object, key, frameFn);
294
+ memo.signals = frameSignals;
295
+ signals.set(key, memo);
296
+ return memo;
297
+ }
298
+ function isMemo(obj) {
299
+ return typeof obj === "function" && obj.signals instanceof Set;
300
+ }
301
+ globalThis.debugWarpDriveSignals = (obj, key) => {
302
+ /* @__PURE__ */ upgradeWithSignals(obj);
303
+ const signals = obj[Signals];
304
+ if (!signals) {
305
+ log("The object has no associated signals");
306
+ return false;
307
+ }
308
+ if (key) {
309
+ const signal = signals.get(key);
310
+ if (!signal) {
311
+ log(`No signal found for key "${String(key)}"`);
312
+ return false;
313
+ }
314
+ log(signal);
315
+ if (isMemo(signal)) {
316
+ colorizeLines(printMemo(signal, key));
317
+ return true;
318
+ } else {
319
+ colorizeLines(printSignal(signal, key));
320
+ return true;
321
+ }
322
+ }
323
+ const lines = [];
324
+ for (const [k, signal] of signals) {
325
+ if (isMemo(signal)) continue;
326
+ printSignal(signal, k, lines);
327
+ }
328
+ for (const [k, signal] of signals) if (isMemo(signal)) printMemo(signal, k, lines);
329
+ log(signals);
330
+ colorizeLines(lines);
331
+ return true;
332
+ };
333
+ const LightColors = {
334
+ red: "color: red;",
335
+ green: "color: green;",
336
+ reset: "color: inherit;"
337
+ };
338
+ const DarkColors = {
339
+ red: "color: red;",
340
+ green: "color: lightgreen;",
341
+ reset: "color: inherit;"
342
+ };
343
+ function isLightMode() {
344
+ if (window?.matchMedia?.("(prefers-color-scheme: light)").matches) return true;
345
+ return false;
346
+ }
347
+ const RED = {};
348
+ const GREEN = {};
349
+ const RESET = {};
350
+ const EOL = {};
351
+ function colorizeLines(lines) {
352
+ const Colors = isLightMode() ? LightColors : DarkColors;
353
+ const colors = [];
354
+ let line = "";
355
+ for (const str of lines) if (str === RED) {
356
+ colors.push(Colors.red);
357
+ line += "%c";
358
+ } else if (str === GREEN) {
359
+ colors.push(Colors.green);
360
+ line += "%c";
361
+ } else if (str === RESET) {
362
+ colors.push(Colors.reset);
363
+ line += "%c";
364
+ } else if (str === EOL) line += "\n";
365
+ else line += str;
366
+ log(line, ...colors);
367
+ }
368
+ function log(...args) {
369
+ console.log(...args);
370
+ }
371
+ function isDirty(signal) {
372
+ return signal.isStale;
373
+ }
374
+ function isDirtyMemo(memo) {
375
+ for (const signal of memo.signals) {
376
+ if (isMemo(signal)) continue;
377
+ if (isDirty(signal)) return true;
378
+ }
379
+ for (const signal of memo.signals) if (isMemo(signal)) return isDirtyMemo(signal);
380
+ return false;
381
+ }
382
+ function printSignal(signal, key, lines = [], depth = 0) {
383
+ const _dirty = isDirty(signal);
384
+ lines.push(`${"".padStart(depth * 2, " ")}${_dirty ? "❌" : "✅"} `, _dirty ? RED : GREEN, `${String(key)}`, RESET, EOL);
385
+ return lines;
386
+ }
387
+ function printMemo(memo, key, lines = [], depth = 0) {
388
+ const _dirty = isDirtyMemo(memo);
389
+ lines.push(`${"".padStart(depth * 2, " ")}${_dirty ? "❌" : "✅"} `, _dirty ? RED : GREEN, `<memo> ${String(key)}`, RESET, `: (consumes ${memo.signals.size} signals)`, EOL);
390
+ for (const signal of memo.signals) {
391
+ if (isMemo(signal)) continue;
392
+ printSignal(signal, signal.key, lines, depth + 1);
393
+ }
394
+ for (const signal of memo.signals) if (isMemo(signal)) printMemo(signal, signal.key, lines, depth + 1);
395
+ return lines;
396
+ }
397
+
398
+ //#endregion
399
+ //#region src/signals/reactivity/signal.ts
400
+ /**
401
+ * Creates a signal for the key/object pairing and subscribes to the signal.
402
+ *
403
+ * Use when you need to ensure a signal exists and is subscribed to.
404
+ *
405
+ * @private
406
+ */
407
+ function entangleSignal(signals, obj, key, initialValue) {
408
+ let internalSignal = peekInternalSignal(signals, key);
409
+ if (!internalSignal) internalSignal = createInternalSignal(signals, obj, key, initialValue);
410
+ consumeInternalSignal(internalSignal);
411
+ return internalSignal;
412
+ }
413
+ function entangleInitiallyStaleSignal(signals, obj, key, initialValue) {
414
+ let internalSignal = peekInternalSignal(signals, key);
415
+ if (!internalSignal) {
416
+ internalSignal = createInternalSignal(signals, obj, key, initialValue);
417
+ internalSignal.isStale = true;
418
+ }
419
+ consumeInternalSignal(internalSignal);
420
+ return internalSignal;
421
+ }
422
+ function createSignalDescriptor(key, intialValue) {
423
+ return {
424
+ enumerable: true,
425
+ configurable: false,
426
+ get() {
427
+ const internalSignal = entangleSignal(withSignalStore(this), this, key, intialValue);
428
+ internalSignal.isStale = false;
429
+ return internalSignal.value;
430
+ },
431
+ set(value) {
432
+ const signals = withSignalStore(this);
433
+ const internalSignal = getOrCreateInternalSignal(signals, this, key, intialValue);
434
+ if (internalSignal.value !== value) {
435
+ internalSignal.value = value;
436
+ notifyInternalSignal(internalSignal);
437
+ }
438
+ }
439
+ };
440
+ }
441
+ /**
442
+ * define an enumerable signal property.
443
+ *
444
+ * Akin to Object.defineProperty.
445
+ *
446
+ * The signal will be lazily created when accessed and scoped to the
447
+ * instance of the object.
448
+ *
449
+ * @private
450
+ */
451
+ function defineSignal(obj, key, v) {
452
+ Object.defineProperty(obj, key, createSignalDescriptor(key, v));
453
+ }
454
+ /**
455
+ * Define a non-enumerable signal property.
456
+ *
457
+ * @private
458
+ */
459
+ function defineNonEnumerableSignal(obj, key, v) {
460
+ const desc = createSignalDescriptor(key, v);
461
+ desc.enumerable = false;
462
+ Object.defineProperty(obj, key, desc);
463
+ }
464
+ /**
465
+ * Decorator version of creating a signal.
466
+ */
467
+ function signal(target, key, descriptor) {
468
+ ((test) => {
469
+ if (!test) throw new Error("You attempted to use @signal(), which is not necessary nor supported. Remove the parentheses and you will be good to go!");
470
+ })(target !== void 0);
471
+ ((test) => {
472
+ if (!test) 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\``);
473
+ })(typeof target === "object" && typeof key === "string" && typeof descriptor === "object" && arguments.length === 3);
474
+ return createSignalDescriptor(key, descriptor.initializer ? makeInitializer(descriptor.initializer) : null);
475
+ }
476
+ /**
477
+ * Decorator version of creating a memoized getter
478
+ */
479
+ function memoized(target, key, descriptor) {
480
+ ((test) => {
481
+ if (!test) throw new Error("You attempted to use @memoized(), which is not necessary nor supported. Remove the parentheses and you will be good to go!");
482
+ })(target !== void 0);
483
+ ((test) => {
484
+ if (!test) 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\``);
485
+ })(typeof target === "object" && typeof key === "string" && typeof descriptor === "object" && arguments.length === 3);
486
+ ((test) => {
487
+ if (!test) throw new Error(`The @memoized decorator must be applied to getters. '${key}' is not a getter.`);
488
+ })(typeof descriptor.get === "function");
489
+ const getter = descriptor.get;
490
+ descriptor.get = function() {
491
+ const signals = withSignalStore(this);
492
+ let memoSignal = signals.get(key);
493
+ if (!memoSignal) memoSignal = createInternalMemo(signals, this, key, getter.bind(this));
494
+ return memoSignal();
495
+ };
496
+ return descriptor;
497
+ }
498
+ /**
499
+ * Decorator version of creating a gate.
500
+ *
501
+ * @private
502
+ */
503
+ function gate(_target, key, desc) {
504
+ const getter = desc.get;
505
+ const setter = desc.set;
506
+ const isLocal = desc.isLocal;
507
+ desc.get = function() {
508
+ const signals = withSignalStore(this);
509
+ let internalSignal = peekInternalSignal(signals, key);
510
+ if (!internalSignal) internalSignal = createInternalSignal(signals, this, key, getter.call(this));
511
+ else if (internalSignal.isStale) {
512
+ internalSignal.isStale = false;
513
+ internalSignal.value = getter.call(this);
514
+ }
515
+ consumeInternalSignal(internalSignal);
516
+ return internalSignal.value;
517
+ };
518
+ if (setter) desc.set = function(v) {
519
+ const signals = withSignalStore(this);
520
+ let internalSignal = peekInternalSignal(signals, key);
521
+ if (!internalSignal) {
522
+ internalSignal = createInternalSignal(signals, this, key, void 0);
523
+ internalSignal.isStale = true;
524
+ }
525
+ setter.call(this, v);
526
+ if (isLocal) {
527
+ internalSignal.isStale = true;
528
+ notifyInternalSignal(internalSignal);
529
+ }
530
+ };
531
+ return desc;
532
+ }
533
+ /**
534
+ * Defines a reactive "gated" property on `obj` using `desc` as its
535
+ * getter/setter descriptor.
536
+ *
537
+ * Unlike a signal defined with {@link defineSignal}, a gated property's
538
+ * consumers are not notified when the property is set, since its update
539
+ * is expected to be controlled externally (for instance, by a signal it
540
+ * derives its value from) unless the descriptor opts into being locally
541
+ * managed.
542
+ *
543
+ * Akin to `Object.defineProperty`.
544
+ *
545
+ * @private
546
+ */
547
+ function defineGate(obj, key, desc) {
548
+ const options = Object.assign({
549
+ enumerable: true,
550
+ configurable: false
551
+ }, gate(obj, key, desc));
552
+ Object.defineProperty(obj, key, options);
553
+ }
554
+
555
+ //#endregion
556
+ //#region src/signals/request-state.ts
557
+ const RequestCache = /* @__PURE__ */ new WeakMap();
558
+ function isAbortError(error) {
559
+ return error instanceof DOMError && error.name === "AbortError";
560
+ }
561
+ function upgradeLoadingState(state) {
562
+ return state;
563
+ }
564
+ async function watchStream(stream, loadingState) {
565
+ const state = upgradeLoadingState(loadingState);
566
+ const reader = stream.getReader();
567
+ let bytesLoaded = 0;
568
+ let shouldForward = state._stream !== null && state._stream.readable.locked;
569
+ let isForwarding = shouldForward;
570
+ let writer = state._stream?.writable.getWriter();
571
+ const buffer = [];
572
+ state._isPending = false;
573
+ state._isStarted = true;
574
+ state._startTime = performance.now();
575
+ while (true) {
576
+ const { value, done } = await reader.read();
577
+ if (done) break;
578
+ bytesLoaded += value.byteLength;
579
+ state._bytesLoaded = bytesLoaded;
580
+ state._lastPacketTime = performance.now();
581
+ shouldForward = shouldForward || state._stream !== null && state._stream.readable.locked;
582
+ if (shouldForward) {
583
+ if (!isForwarding) {
584
+ isForwarding = true;
585
+ writer = state._stream.writable.getWriter();
586
+ for (const item of buffer) {
587
+ await writer.ready;
588
+ await writer.write(item);
589
+ }
590
+ buffer.length = 0;
591
+ }
592
+ await writer.ready;
593
+ await writer.write(value);
594
+ } else buffer.push(value);
595
+ }
596
+ if (isForwarding) {
597
+ await writer.ready;
598
+ await writer.close();
599
+ } else if (state._stream) {
600
+ await state._stream.readable.cancel("The Stream Has Already Ended");
601
+ state._stream = null;
602
+ }
603
+ state._endTime = performance.now();
604
+ state._isComplete = true;
605
+ state._isStarted = false;
606
+ }
607
+ /**
608
+ * Lazily consumes the stream of a request, providing a number of
609
+ * reactive properties that can be used to build UIs that respond
610
+ * to the progress of a request.
611
+ *
612
+ * @hideconstructor
613
+ */
614
+ var RequestLoadingState = class {
615
+ /** @internal */
616
+ /** @internal */
617
+ /** @internal */
618
+ /** @internal */
619
+ /** @internal */
620
+ /** @internal */
621
+ /** @internal */
622
+ /** @internal */
623
+ /** @internal */
624
+ /** @internal */
625
+ /** @internal */
626
+ /** @internal */
627
+ _stream = null;
628
+ /** @internal */
629
+ _future;
630
+ /** @internal */
631
+ _triggered = false;
632
+ /** @internal */
633
+ _trigger() {
634
+ if (this._triggered) return;
635
+ this._triggered = true;
636
+ const promise = this._future.getStream();
637
+ if (promise.sizeHint) this._sizeHint = promise.sizeHint;
638
+ this.promise = promise.then((stream) => {
639
+ if (!stream) {
640
+ this._isPending = false;
641
+ this._isComplete = true;
642
+ return;
643
+ }
644
+ return watchStream(stream, this);
645
+ }, (error) => {
646
+ this._isPending = false;
647
+ this._isStarted = false;
648
+ if (isAbortError(error)) {
649
+ this._isCancelled = true;
650
+ this._isComplete = true;
651
+ }
652
+ this._isErrored = true;
653
+ this._error = error;
654
+ });
655
+ }
656
+ /**
657
+ * Resolves once the stream has finished being consumed, or rejects
658
+ * if the request errors. `null` until first accessed.
659
+ */
660
+ promise = null;
661
+ /**
662
+ * Whether the stream has not yet started being consumed.
663
+ */
664
+ get isPending() {
665
+ this._trigger();
666
+ return this._isPending;
667
+ }
668
+ /**
669
+ * The total size of the response in bytes, if known ahead of time
670
+ * (via a `Content-Length` header or similar).
671
+ */
672
+ get sizeHint() {
673
+ this._trigger();
674
+ return this._sizeHint;
675
+ }
676
+ /**
677
+ * A readable stream of the response content. Accessing this property
678
+ * begins consumption of the underlying request stream.
679
+ */
680
+ get stream() {
681
+ this._trigger();
682
+ if (!this._stream) {
683
+ if (this._isComplete || this._isCancelled || this._isErrored) return null;
684
+ this._stream = new TransformStream();
685
+ }
686
+ return this._stream.readable;
687
+ }
688
+ /**
689
+ * Whether the stream has started being consumed but has not yet completed.
690
+ */
691
+ get isStarted() {
692
+ this._trigger();
693
+ return this._isStarted;
694
+ }
695
+ /**
696
+ * The number of bytes loaded so far.
697
+ */
698
+ get bytesLoaded() {
699
+ this._trigger();
700
+ return this._bytesLoaded;
701
+ }
702
+ /**
703
+ * The `performance.now()` timestamp at which the stream started being consumed.
704
+ */
705
+ get startTime() {
706
+ this._trigger();
707
+ return this._startTime;
708
+ }
709
+ /**
710
+ * The `performance.now()` timestamp at which the stream finished being consumed.
711
+ */
712
+ get endTime() {
713
+ this._trigger();
714
+ return this._endTime;
715
+ }
716
+ /**
717
+ * The `performance.now()` timestamp at which the last chunk of data was received.
718
+ */
719
+ get lastPacketTime() {
720
+ this._trigger();
721
+ return this._lastPacketTime;
722
+ }
723
+ /**
724
+ * Whether the stream has finished being consumed.
725
+ */
726
+ get isComplete() {
727
+ this._trigger();
728
+ return this._isComplete;
729
+ }
730
+ /**
731
+ * Whether the request was aborted before the stream finished being consumed.
732
+ */
733
+ get isCancelled() {
734
+ this._trigger();
735
+ return this._isCancelled;
736
+ }
737
+ /**
738
+ * Whether an error occurred while consuming the stream.
739
+ */
740
+ get isErrored() {
741
+ this._trigger();
742
+ return this._isErrored;
743
+ }
744
+ /**
745
+ * The error that occurred while consuming the stream, if any.
746
+ */
747
+ get error() {
748
+ this._trigger();
749
+ return this._error;
750
+ }
751
+ /**
752
+ * The number of milliseconds elapsed since the stream started being
753
+ * consumed, using the last packet time (or end time, once complete)
754
+ * as the endpoint.
755
+ */
756
+ get elapsedTime() {
757
+ return (this.endTime || this.lastPacketTime) - this.startTime;
758
+ }
759
+ /**
760
+ * The ratio (0 to 1) of {@link RequestLoadingState.bytesLoaded | bytesLoaded}
761
+ * to {@link RequestLoadingState.sizeHint | sizeHint}, or `0` if no size hint is available.
762
+ */
763
+ get completedRatio() {
764
+ return this.sizeHint ? this.bytesLoaded / this.sizeHint : 0;
765
+ }
766
+ /**
767
+ * The inverse of {@link RequestLoadingState.completedRatio | completedRatio}.
768
+ */
769
+ get remainingRatio() {
770
+ return 1 - this.completedRatio;
771
+ }
772
+ /**
773
+ * The total number of milliseconds elapsed between
774
+ * {@link RequestLoadingState.startTime | startTime} and {@link RequestLoadingState.endTime | endTime}.
775
+ */
776
+ get duration() {
777
+ return this.endTime - this.startTime;
778
+ }
779
+ /**
780
+ * The average download speed in bytes per second.
781
+ */
782
+ get speed() {
783
+ return this.bytesLoaded / (this.elapsedTime / 1e3);
784
+ }
785
+ constructor(future) {
786
+ this._future = future;
787
+ }
788
+ /**
789
+ * Aborts the underlying request.
790
+ */
791
+ abort = () => {
792
+ this._future.abort();
793
+ };
794
+ };
795
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_isPending", true);
796
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_isStarted", false);
797
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_isComplete", false);
798
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_isCancelled", false);
799
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_isErrored", false);
800
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_error", null);
801
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_sizeHint", 0);
802
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_bytesLoaded", 0);
803
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_startTime", 0);
804
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_endTime", 0);
805
+ defineNonEnumerableSignal(RequestLoadingState.prototype, "_lastPacketTime", 0);
806
+ /**
807
+ * The state of a request in the "pending"
808
+ * state. This is the default initial state.
809
+ *
810
+ * Extends the {@link PendingPromise} interface.
811
+ *
812
+ */
813
+ /**
814
+ * The state of a request in the "fulfilled" state.
815
+ * This is the state of a request that has resolved
816
+ * successfully.
817
+ *
818
+ * Extends the {@link ResolvedPromise} interface.
819
+ *
820
+ */
821
+ /**
822
+ * The state of a request in the "rejected" state.
823
+ * This is the state of a request that has rejected
824
+ * with an error.
825
+ *
826
+ * Extends the {@link RejectedPromise} interface.
827
+ *
828
+ */
829
+ /**
830
+ * The state of a request in the "cancelled" state.
831
+ * This is the state of a promise that has been
832
+ * cancelled.
833
+ *
834
+ */
835
+ /**
836
+ * RequestState extends the concept of {@link PromiseState} to provide a reactive
837
+ * wrapper for a request {@link Future} which allows you write declarative code
838
+ * around a Future's control flow.
839
+ *
840
+ * It is useful in both Template and JavaScript contexts, allowing you
841
+ * to quickly derive behaviors and data from pending, error and success
842
+ * states.
843
+ *
844
+ * The key difference between a {@link Promise} and a Future is that Futures provide
845
+ * access to a {@link ReadableStream | stream} of their content, the {@link RequestKey} of the request (if any)
846
+ * as well as the ability to attempt to {@link Future.abort | abort} the request.
847
+ *
848
+ * ```ts
849
+ * interface Future<T> extends Promise<T>> {
850
+ * getStream(): Promise<ReadableStream>;
851
+ * abort(): void;
852
+ * lid: RequestKey | null;
853
+ * }
854
+ * ```
855
+ *
856
+ * These additional APIs allow us to craft even richer state experiences.
857
+ *
858
+ * To get the state of a request, use {@link getRequestState}.
859
+ *
860
+ * See also:
861
+ * - {@link PendingRequest}
862
+ * - {@link ResolvedRequest}
863
+ * - {@link RejectedRequest}
864
+ * - {@link CancelledRequest}
865
+ *
866
+ */
867
+ const RequestStateProto = {};
868
+ function performRefresh(requester, request, isReload) {
869
+ const req = Object.assign({}, request);
870
+ const cacheOptions = Object.assign({}, req.cacheOptions);
871
+ if (isReload) cacheOptions.reload = true;
872
+ else if (isReload === false) {
873
+ delete cacheOptions.reload;
874
+ cacheOptions.backgroundReload = true;
875
+ } else {
876
+ delete cacheOptions.backgroundReload;
877
+ delete cacheOptions.reload;
878
+ }
879
+ req.cacheOptions = cacheOptions;
880
+ return requester.request(req);
881
+ }
882
+ defineSignal(RequestStateProto, "reason", null);
883
+ defineSignal(RequestStateProto, "value", null);
884
+ defineSignal(RequestStateProto, "result", null);
885
+ defineSignal(RequestStateProto, "error", null);
886
+ defineSignal(RequestStateProto, "status", "pending");
887
+ defineSignal(RequestStateProto, "isPending", true);
888
+ defineSignal(RequestStateProto, "isLoading", true);
889
+ defineSignal(RequestStateProto, "isSuccess", false);
890
+ defineSignal(RequestStateProto, "isError", false);
891
+ defineSignal(RequestStateProto, "request", null);
892
+ defineSignal(RequestStateProto, "response", null);
893
+ Object.defineProperty(RequestStateProto, "isCancelled", { get() {
894
+ return this.isError && isAbortError(this.reason);
895
+ } });
896
+ Object.defineProperty(RequestStateProto, "loadingState", { get() {
897
+ if (!this._loadingState) this._loadingState = new RequestLoadingState(this._request);
898
+ return this._loadingState;
899
+ } });
900
+ function createRequestState(future) {
901
+ const state = getPromiseResult(future);
902
+ const promiseState = Object.create(RequestStateProto);
903
+ promiseState._request = future;
904
+ promiseState.reload = () => {
905
+ ((test) => {
906
+ if (!test) throw new Error(`Cannot reload a request that is still pending. Await or abort the original request first.`);
907
+ })(!promiseState.isPending);
908
+ return performRefresh(future.requester, promiseState.request, true);
909
+ };
910
+ promiseState.refresh = (usePolicy = false) => {
911
+ ((test) => {
912
+ if (!test) throw new Error(`Cannot refresh a request that is still pending. Await or abort the original request first.`);
913
+ })(!promiseState.isPending);
914
+ return performRefresh(future.requester, promiseState.request, usePolicy === true ? null : false);
915
+ };
916
+ if (state) {
917
+ if (state.isError) {
918
+ promiseState.error = state.result;
919
+ promiseState.reason = state.result;
920
+ promiseState.status = "rejected";
921
+ promiseState.isError = true;
922
+ promiseState.isPending = false;
923
+ promiseState.isLoading = false;
924
+ promiseState.request = state.result.request;
925
+ promiseState.response = state.result.response;
926
+ } else {
927
+ promiseState.result = state.result.content;
928
+ promiseState.value = state.result.content;
929
+ promiseState.status = "fulfilled";
930
+ promiseState.isSuccess = true;
931
+ promiseState.isPending = false;
932
+ promiseState.isLoading = false;
933
+ promiseState.request = state.result.request;
934
+ promiseState.response = state.result.response;
935
+ }
936
+ } else future.then((result) => {
937
+ setPromiseResult(future, {
938
+ isError: false,
939
+ result
940
+ });
941
+ promiseState.result = result.content;
942
+ promiseState.value = result.content;
943
+ promiseState.status = "fulfilled";
944
+ promiseState.isSuccess = true;
945
+ promiseState.isPending = false;
946
+ promiseState.isLoading = false;
947
+ promiseState.request = result.request;
948
+ promiseState.response = result.response;
949
+ }, (error) => {
950
+ setPromiseResult(future, {
951
+ isError: true,
952
+ result: error
953
+ });
954
+ promiseState.error = error;
955
+ promiseState.reason = error;
956
+ promiseState.status = "rejected";
957
+ promiseState.isError = true;
958
+ promiseState.isPending = false;
959
+ promiseState.isLoading = false;
960
+ promiseState.request = error.request;
961
+ promiseState.response = error.response;
962
+ });
963
+ return promiseState;
964
+ }
965
+ /**
966
+ * `getRequestState` can be used in both JavaScript and Template contexts.
967
+ *
968
+ * ```ts
969
+ * import { getRequestState } from '@warp-drive/ember';
970
+ *
971
+ * const state = getRequestState(future);
972
+ * ```
973
+ *
974
+ * For instance, we could write a getter on a component that updates whenever
975
+ * the request state advances or the future changes, by combining the function
976
+ * with the use of `@cached`
977
+ *
978
+ * ```ts
979
+ * class Component {
980
+ * @cached
981
+ * get title() {
982
+ * const state = getRequestState(this.args.request);
983
+ * if (state.isPending) {
984
+ * return 'loading...';
985
+ * }
986
+ * if (state.isError) { return null; }
987
+ * return state.result.title;
988
+ * }
989
+ * }
990
+ * ```
991
+ *
992
+ * Or in a template as a helper:
993
+ *
994
+ * ```gjs
995
+ * import { getRequestState } from '@warp-drive/ember';
996
+ *
997
+ * <template>
998
+ * {{#let (getRequestState @request) as |state|}}
999
+ * {{#if state.isPending}}
1000
+ * <Spinner />
1001
+ * {{else if state.isError}}
1002
+ * <ErrorForm @error={{state.error}} />
1003
+ * {{else}}
1004
+ * <h1>{{state.result.title}}</h1>
1005
+ * {{/if}}
1006
+ * {{/let}}
1007
+ * </template>
1008
+ * ```
1009
+ *
1010
+ * If looking to use in a template, consider also the `<Request />` component
1011
+ * which offers a number of additional capabilities for requests *beyond* what
1012
+ * `RequestState` provides.
1013
+ *
1014
+ */
1015
+ function getRequestState(future) {
1016
+ let state = RequestCache.get(future);
1017
+ if (!state) {
1018
+ state = createRequestState(future);
1019
+ RequestCache.set(future, state);
1020
+ }
1021
+ return state;
1022
+ }
1023
+
1024
+ //#endregion
1025
+ //#region ../../node_modules/.pnpm/decorat_5d4eca388601a94e7fbc656401b751d1/node_modules/decorator-transforms/dist/runtime--fcdnjmJ.js
1026
+ const deferred = /* @__PURE__ */ new WeakMap();
1027
+ function deferDecorator(proto, prop, desc) {
1028
+ let map = deferred.get(proto);
1029
+ if (!map) {
1030
+ map = /* @__PURE__ */ new Map();
1031
+ deferred.set(proto, map);
1032
+ }
1033
+ map.set(prop, desc);
1034
+ }
1035
+ function findDeferredDecorator(target, prop) {
1036
+ var _a;
1037
+ let cursor = target.prototype;
1038
+ while (cursor) {
1039
+ let desc = (_a = deferred.get(cursor)) == null ? void 0 : _a.get(prop);
1040
+ if (desc) return desc;
1041
+ cursor = Object.getPrototypeOf(cursor);
1042
+ }
1043
+ }
1044
+ function decorateFieldV2(prototype, prop, decorators, initializer) {
1045
+ let desc = {
1046
+ configurable: true,
1047
+ enumerable: true,
1048
+ writable: true,
1049
+ initializer: null
1050
+ };
1051
+ if (initializer) desc.initializer = initializer;
1052
+ for (let decorator of decorators) desc = decorator(prototype, prop, desc) || desc;
1053
+ if (desc.initializer === void 0) Object.defineProperty(prototype, prop, desc);
1054
+ else deferDecorator(prototype, prop, desc);
1055
+ }
1056
+ function decorateMethodV2(prototype, prop, decorators) {
1057
+ let desc = { ...Object.getOwnPropertyDescriptor(prototype, prop) };
1058
+ for (let decorator of decorators) desc = decorator(prototype, prop, desc) || desc;
1059
+ if (desc.initializer !== void 0) {
1060
+ desc.value = desc.initializer ? desc.initializer.call(prototype) : void 0;
1061
+ desc.initializer = void 0;
1062
+ }
1063
+ Object.defineProperty(prototype, prop, desc);
1064
+ }
1065
+ function initializeDeferredDecorator(target, prop) {
1066
+ let desc = findDeferredDecorator(target.constructor, prop);
1067
+ if (desc) Object.defineProperty(target, prop, {
1068
+ enumerable: desc.enumerable,
1069
+ configurable: desc.configurable,
1070
+ writable: desc.writable,
1071
+ value: desc.initializer ? desc.initializer.call(target) : void 0
1072
+ });
1073
+ }
1074
+
1075
+ //#endregion
1076
+ //#region src/signals/request-subscription.ts
1077
+ const DEFAULT_DEADLINE = 3e4;
1078
+ /**
1079
+ * A symbol used to dispose of a {@link RequestSubscription} when the
1080
+ * component or context using it is torn down.
1081
+ */
1082
+ const DISPOSE = Symbol.dispose || Symbol.for("dispose");
1083
+ function isNeverString(val) {
1084
+ return val;
1085
+ }
1086
+ /**
1087
+ * The individual autorefresh strategies a {@link RequestSubscription}
1088
+ * may combine, see {@link AutorefreshBehaviorCombos}.
1089
+ */
1090
+ /**
1091
+ * The value accepted by {@link SubscriptionArgs.autorefresh}: either a
1092
+ * boolean, a single {@link AutorefreshBehaviorType}, or a comma-separated
1093
+ * combination of up to three of them.
1094
+ */
1095
+ /**
1096
+ * Utilities to assist in recovering from the error.
1097
+ */
1098
+ /** @deprecated use {@link RecoveryFeatures} */
1099
+ /**
1100
+ * Utilities for keeping the request fresh
1101
+ */
1102
+ /**
1103
+ * The args accepted by the `<Request />` component.
1104
+ */
1105
+ /**
1106
+ * The args accepted by a {@link RequestSubscription}.
1107
+ */
1108
+ /**
1109
+ * A reactive class
1110
+ *
1111
+ * @hideconstructor
1112
+ */
1113
+ var RequestSubscription = class {
1114
+ /**
1115
+ * Whether the browser reports that the network is online.
1116
+ */
1117
+ /**
1118
+ * Whether the browser reports that the tab is hidden.
1119
+ */
1120
+ /**
1121
+ * Whether the component is currently refreshing the request.
1122
+ */
1123
+ /**
1124
+ * The most recent blocking request that was made, typically
1125
+ * the result of a reload.
1126
+ *
1127
+ * This will never be the original request passed as an arg to
1128
+ * the component.
1129
+ *
1130
+ * @internal
1131
+ */
1132
+ /**
1133
+ * The most recent request that was made, typically due to either a
1134
+ * reload or a refresh.
1135
+ *
1136
+ * This will never be the original request passed as an arg to
1137
+ * the component.
1138
+ *
1139
+ * @internal
1140
+ */
1141
+ /**
1142
+ * The time at which the network was reported as offline.
1143
+ *
1144
+ * @internal
1145
+ */
1146
+ /** @internal */
1147
+ /** @internal */
1148
+ /** @internal */
1149
+ /** @internal */
1150
+ /** @internal */
1151
+ /**
1152
+ * The event listener for network status changes,
1153
+ * cached to use the reference for removal.
1154
+ *
1155
+ * @internal
1156
+ */
1157
+ /**
1158
+ * The event listener for visibility status changes,
1159
+ * cached to use the reference for removal.
1160
+ *
1161
+ * @internal
1162
+ */
1163
+ /**
1164
+ * The last request passed as an arg to the component,
1165
+ * cached for comparison.
1166
+ *
1167
+ * @internal
1168
+ */
1169
+ /**
1170
+ * The last query passed as an arg to the component,
1171
+ * cached for comparison.
1172
+ *
1173
+ * @internal
1174
+ */
1175
+ /** @internal */
1176
+ /** @internal */
1177
+ /** @internal */
1178
+ /**
1179
+ * The Store this subscription subscribes to or the RequestManager
1180
+ * which issues this request.
1181
+ */
1182
+ /**
1183
+ * The Store or RequestManager that the last subscription is attached to.
1184
+ *
1185
+ * This differs from 'store' because a <Request /> may be passed a
1186
+ * request originating from a different store than the <Request />
1187
+ * component would use if it were to issue the request itself.
1188
+ *
1189
+ * @internal
1190
+ */
1191
+ _requester;
1192
+ constructor(store, args) {
1193
+ this._args = args;
1194
+ this.store = store;
1195
+ this._subscribedTo = null;
1196
+ this._subscription = null;
1197
+ this._intervalStart = null;
1198
+ this._invalidated = false;
1199
+ this._nextInterval = null;
1200
+ this._requester = null;
1201
+ this.isDestroyed = false;
1202
+ this[DISPOSE] = _DISPOSE$2;
1203
+ this._installListeners();
1204
+ this._beginPolling();
1205
+ }
1206
+ /**
1207
+ * @internal
1208
+ */
1209
+ async _beginPolling() {
1210
+ try {
1211
+ if (!this.isIdle) await this.request;
1212
+ } catch {} finally {
1213
+ if (!this.isDestroyed) this._scheduleInterval();
1214
+ }
1215
+ }
1216
+ /**
1217
+ * Whether neither a `request` nor a `query` arg was provided, and so
1218
+ * this subscription has nothing to fetch or monitor.
1219
+ */
1220
+ get isIdle() {
1221
+ const { request, query } = this._args;
1222
+ return Boolean(!request && !query);
1223
+ }
1224
+ /**
1225
+ * The set of {@link AutorefreshBehaviorType}s this subscription is
1226
+ * configured to autorefresh for, derived from {@link SubscriptionArgs.autorefresh}.
1227
+ */
1228
+ static {
1229
+ decorateMethodV2(this.prototype, "isIdle", [memoized]);
1230
+ }
1231
+ get autorefreshTypes() {
1232
+ const { autorefresh } = this._args;
1233
+ let types;
1234
+ if (autorefresh === true) types = ["online", "invalid"];
1235
+ else if (typeof autorefresh === "string") types = autorefresh.split(",");
1236
+ else types = [];
1237
+ return new Set(types);
1238
+ }
1239
+ /** @internal */
1240
+ static {
1241
+ decorateMethodV2(this.prototype, "autorefreshTypes", [memoized]);
1242
+ }
1243
+ async _scheduleInterval() {
1244
+ const { autorefreshThreshold } = this._args;
1245
+ if (typeof window === "undefined" || !(typeof autorefreshThreshold === "number" && autorefreshThreshold > 0) || !this.autorefreshTypes.has("interval") || this._intervalStart !== null) return;
1246
+ if (this._latestRequest) {
1247
+ try {
1248
+ await this._latestRequest;
1249
+ } catch {}
1250
+ if (this.isDestroyed) return;
1251
+ }
1252
+ this._intervalStart = Date.now();
1253
+ this._nextInterval = setTimeout(() => {
1254
+ this._maybeUpdate();
1255
+ }, autorefreshThreshold);
1256
+ }
1257
+ /** @internal */
1258
+ _clearInterval() {
1259
+ if (this._nextInterval) {
1260
+ clearTimeout(this._nextInterval);
1261
+ this._intervalStart = null;
1262
+ }
1263
+ }
1264
+ /**
1265
+ * @internal
1266
+ */
1267
+ _updateSubscriptions() {
1268
+ if (this.isIdle) return;
1269
+ const requestId = this._request.lid;
1270
+ if (this._subscribedTo === requestId) return;
1271
+ this._removeSubscriptions();
1272
+ const store = this._getRequester();
1273
+ this._requester = store;
1274
+ if (requestId && isStore(store)) {
1275
+ this._subscribedTo = requestId;
1276
+ this._subscription = store.notifications.subscribe(requestId, (_id, op) => {
1277
+ if (this._isUpdating) return;
1278
+ switch (op) {
1279
+ case "invalidated":
1280
+ if (this.autorefreshTypes.has("invalid")) {
1281
+ this._invalidated = true;
1282
+ this._maybeUpdate();
1283
+ }
1284
+ break;
1285
+ case "state": {
1286
+ const priority = store.requestManager._deduped.get(requestId)?.priority;
1287
+ const state = this.reqState;
1288
+ if (!priority) this.isRefreshing = false;
1289
+ else if (priority.blocking && !state.isLoading) {
1290
+ this.isRefreshing = false;
1291
+ this._maybeUpdate("policy", true);
1292
+ } else this.isRefreshing = true;
1293
+ }
1294
+ }
1295
+ });
1296
+ }
1297
+ }
1298
+ /**
1299
+ * @internal
1300
+ */
1301
+ _removeSubscriptions() {
1302
+ const store = this._requester;
1303
+ if (this._subscription && store && isStore(store)) {
1304
+ store.notifications.unsubscribe(this._subscription);
1305
+ this._subscribedTo = null;
1306
+ this._subscription = null;
1307
+ this._requester = null;
1308
+ }
1309
+ }
1310
+ /**
1311
+ * Install the event listeners for network and visibility changes.
1312
+ *
1313
+ * This is only done in environments that provide a fully-featured global
1314
+ * `window` and/or `document`. Some non-DOM environments (e.g. React Native,
1315
+ * SSR/Node, workers) may provide a `window` global without the APIs we
1316
+ * rely on here (or no `window`/`document` at all), in which case we skip
1317
+ * attaching the corresponding listeners rather than throwing.
1318
+ *
1319
+ * @internal
1320
+ */
1321
+ _installListeners() {
1322
+ const hasWindow = typeof window !== "undefined";
1323
+ const hasDocument = typeof document !== "undefined";
1324
+ const hasWindowEvents = hasWindow && typeof window.addEventListener === "function";
1325
+ const hasDocumentEvents = hasDocument && typeof document.addEventListener === "function";
1326
+ this.isOnline = hasWindow && typeof window.navigator?.onLine === "boolean" ? window.navigator.onLine : true;
1327
+ this._unavailableStart = this.isOnline ? null : Date.now();
1328
+ this.isHidden = hasDocument && typeof document.visibilityState === "string" && document.visibilityState === "hidden";
1329
+ if (hasWindowEvents) {
1330
+ this._onlineChanged = (event) => {
1331
+ this.isOnline = event.type === "online";
1332
+ if (event.type === "offline" && this._unavailableStart === null) this._unavailableStart = Date.now();
1333
+ this._maybeUpdate();
1334
+ };
1335
+ window.addEventListener("online", this._onlineChanged, {
1336
+ passive: true,
1337
+ capture: true
1338
+ });
1339
+ window.addEventListener("offline", this._onlineChanged, {
1340
+ passive: true,
1341
+ capture: true
1342
+ });
1343
+ }
1344
+ if (hasDocumentEvents) {
1345
+ this._backgroundChanged = () => {
1346
+ const isHidden = document.visibilityState === "hidden";
1347
+ this.isHidden = isHidden;
1348
+ if (isHidden && this._unavailableStart === null) this._unavailableStart = Date.now();
1349
+ this._maybeUpdate();
1350
+ };
1351
+ document.addEventListener("visibilitychange", this._backgroundChanged, {
1352
+ passive: true,
1353
+ capture: true
1354
+ });
1355
+ }
1356
+ }
1357
+ /**
1358
+ * If the network is online and the tab is visible, either reload or refresh the request
1359
+ * based on the component's configuration and the requested update mode.
1360
+ *
1361
+ * Valid modes are:
1362
+ *
1363
+ * - `'reload'`: Force a reload of the request.
1364
+ * - `'refresh'`: Refresh the request in the background.
1365
+ * - `'policy'`: Make the request, letting the store's configured CachePolicy decide whether to reload, refresh, or do nothing.
1366
+ * - `undefined`: Make the request using the component's autorefreshBehavior setting if the autorefreshThreshold has passed.
1367
+ *
1368
+ * @internal
1369
+ */
1370
+ _maybeUpdate(mode, silent) {
1371
+ if (this.isIdle) return;
1372
+ const { reqState } = this;
1373
+ if (reqState.isPending) return;
1374
+ if (!Boolean(this.isOnline && !this.isHidden && (mode || this.autorefreshTypes.size))) {
1375
+ if (!silent && mode && mode !== "_invalidated") throw new Error(`Reload not available: the network is not online or the tab is hidden`);
1376
+ return;
1377
+ }
1378
+ const { autorefreshTypes } = this;
1379
+ let shouldAttempt = this._invalidated || Boolean(mode);
1380
+ if (!shouldAttempt && autorefreshTypes.has("online")) {
1381
+ const { _unavailableStart } = this;
1382
+ const { autorefreshThreshold } = this._args;
1383
+ const deadline = typeof autorefreshThreshold === "number" ? autorefreshThreshold : DEFAULT_DEADLINE;
1384
+ shouldAttempt = Boolean(_unavailableStart && Date.now() - _unavailableStart > deadline);
1385
+ }
1386
+ if (!shouldAttempt && autorefreshTypes.has("interval")) {
1387
+ const { _intervalStart } = this;
1388
+ const { autorefreshThreshold } = this._args;
1389
+ if (_intervalStart && typeof autorefreshThreshold === "number" && autorefreshThreshold > 0) shouldAttempt = Boolean(Date.now() - _intervalStart >= autorefreshThreshold);
1390
+ }
1391
+ this._unavailableStart = null;
1392
+ this._invalidated = false;
1393
+ if (shouldAttempt) {
1394
+ this._clearInterval();
1395
+ this._isUpdating = true;
1396
+ const val = (mode === "_invalidated" ? null : mode) ?? this._args.autorefreshBehavior ?? "policy";
1397
+ const requester = this._getRequester();
1398
+ if (!reqState._request.requester) reqState._request.requester = requester;
1399
+ switch (val) {
1400
+ case "reload":
1401
+ this._latestRequest = reqState.reload();
1402
+ break;
1403
+ case "refresh":
1404
+ this._latestRequest = reqState.refresh();
1405
+ break;
1406
+ case "policy":
1407
+ this._latestRequest = reqState.refresh(true);
1408
+ break;
1409
+ default: ((test) => {
1410
+ if (!test) throw new Error(`Invalid ${mode ? "update mode" : "@autorefreshBehavior"} for <Request />: ${isNeverString(val)}`);
1411
+ })(false);
1412
+ }
1413
+ if (val !== "refresh") this._localRequest = this._latestRequest;
1414
+ this._scheduleInterval();
1415
+ this._latestRequest.finally(() => {
1416
+ this._isUpdating = false;
1417
+ });
1418
+ }
1419
+ }
1420
+ /**
1421
+ * @internal
1422
+ */
1423
+ _getRequester() {
1424
+ if (this._args.request?.requester) return this._args.request.requester;
1425
+ return this.store;
1426
+ }
1427
+ /**
1428
+ * Retry the request, reloading it from the server.
1429
+ */
1430
+ retry = async () => {
1431
+ this._maybeUpdate("reload");
1432
+ await this._localRequest;
1433
+ };
1434
+ /**
1435
+ * Refresh the request, updating it in the background.
1436
+ */
1437
+ refresh = async () => {
1438
+ this._maybeUpdate("refresh");
1439
+ await this._latestRequest;
1440
+ };
1441
+ /**
1442
+ * features to yield to the error slot of a component
1443
+ */
1444
+ get errorFeatures() {
1445
+ return {
1446
+ isHidden: this.isHidden,
1447
+ isOnline: this.isOnline,
1448
+ retry: this.retry
1449
+ };
1450
+ }
1451
+ /**
1452
+ * features to yield to the content slot of a component
1453
+ */
1454
+ static {
1455
+ decorateMethodV2(this.prototype, "errorFeatures", [memoized]);
1456
+ }
1457
+ get contentFeatures() {
1458
+ const feat = {
1459
+ isHidden: this.isHidden,
1460
+ isOnline: this.isOnline,
1461
+ reload: this.retry,
1462
+ refresh: this.refresh,
1463
+ isRefreshing: this.isRefreshing,
1464
+ latestRequest: this._latestRequest
1465
+ };
1466
+ if (feat.isRefreshing) feat.abort = () => {
1467
+ this._latestRequest?.abort();
1468
+ };
1469
+ return feat;
1470
+ }
1471
+ /**
1472
+ * @internal
1473
+ */
1474
+ static {
1475
+ decorateMethodV2(this.prototype, "contentFeatures", [memoized]);
1476
+ }
1477
+ get _request() {
1478
+ const { request, query } = this._args;
1479
+ ((test) => {
1480
+ if (!test) throw new Error(`Cannot use both @request and @query args with the <Request> component`);
1481
+ })(!request || !query);
1482
+ const { _localRequest, _originalRequest, _originalQuery } = this;
1483
+ if (_localRequest && request === _originalRequest && query === _originalQuery) return _localRequest;
1484
+ this._originalQuery = query;
1485
+ this._originalRequest = request;
1486
+ if (request) return request;
1487
+ ((test) => {
1488
+ if (!test) throw new Error(`You must provide either @request or an @query arg with the <Request> component`);
1489
+ })(query);
1490
+ return this.store.request(query);
1491
+ }
1492
+ /**
1493
+ * The {@link Future} this subscription is currently monitoring, and
1494
+ * (re-)subscribes to notifications for as a side effect of access.
1495
+ */
1496
+ static {
1497
+ decorateMethodV2(this.prototype, "_request", [memoized]);
1498
+ }
1499
+ get request() {
1500
+ try {
1501
+ const request = this._request;
1502
+ this._updateSubscriptions();
1503
+ return request;
1504
+ } catch (e) {
1505
+ console.log(e);
1506
+ throw new Error(`Unable to initialize the request`, { cause: e });
1507
+ }
1508
+ }
1509
+ /**
1510
+ * The {@link RequestState} for {@link RequestSubscription.request | request}.
1511
+ */
1512
+ static {
1513
+ decorateMethodV2(this.prototype, "request", [memoized]);
1514
+ }
1515
+ get reqState() {
1516
+ return getRequestState(this.request);
1517
+ }
1518
+ /**
1519
+ * The resolved content of the request, once it has succeeded.
1520
+ */
1521
+ get result() {
1522
+ return this.reqState.result;
1523
+ }
1524
+ };
1525
+ defineSignal(RequestSubscription.prototype, "isOnline", true);
1526
+ defineSignal(RequestSubscription.prototype, "isHidden", false);
1527
+ defineSignal(RequestSubscription.prototype, "isRefreshing", false);
1528
+ defineSignal(RequestSubscription.prototype, "_localRequest", void 0);
1529
+ defineSignal(RequestSubscription.prototype, "_latestRequest", void 0);
1530
+ function isStore(store) {
1531
+ return "requestManager" in store;
1532
+ }
1533
+ /**
1534
+ * Creates a {@link RequestSubscription}, the reactive class powering the
1535
+ * `<Request />` component's autorefresh, retry, and refresh behaviors.
1536
+ */
1537
+ function createRequestSubscription(store, args) {
1538
+ return new RequestSubscription(store, args);
1539
+ }
1540
+ function upgradeSubscription$2(sub) {
1541
+ return sub;
1542
+ }
1543
+ function _DISPOSE$2() {
1544
+ const self = upgradeSubscription$2(this);
1545
+ self.isDestroyed = true;
1546
+ self._removeSubscriptions();
1547
+ self._clearInterval();
1548
+ if (self._onlineChanged && typeof window !== "undefined" && typeof window.removeEventListener === "function") {
1549
+ window.removeEventListener("online", self._onlineChanged, {
1550
+ passive: true,
1551
+ capture: true
1552
+ });
1553
+ window.removeEventListener("offline", self._onlineChanged, {
1554
+ passive: true,
1555
+ capture: true
1556
+ });
1557
+ }
1558
+ if (self._backgroundChanged && typeof document !== "undefined" && typeof document.removeEventListener === "function") document.removeEventListener("visibilitychange", self._backgroundChanged, {
1559
+ passive: true,
1560
+ capture: true
1561
+ });
1562
+ }
1563
+
1564
+ //#endregion
1565
+ //#region src/signals/page-cache.ts
1566
+ const { abs } = Math;
1567
+ /**
1568
+ * Extracts the `data` member of a document type, or the document type itself
1569
+ * when it has no `data` member.
1570
+ */
1571
+ /**
1572
+ * The element type of a collection document's `data` array — the item type an
1573
+ * infinite view renders. See {@link PaginationState.data}.
1574
+ */
1575
+ /** @internal */
1576
+ function getHref(link) {
1577
+ if (!link) return null;
1578
+ if (typeof link === "string") return link;
1579
+ return link.href;
1580
+ }
1581
+ /**
1582
+ * A single page of a paginated collection: its request, its loaded document, and
1583
+ * its links to neighboring pages in the shared page graph.
1584
+ *
1585
+ * Pages are yielded to consumers as `Readonly<PageCache>` — through
1586
+ * {@link PaginationState.activePage}, {@link PaginationState.pages}, and the
1587
+ * relational getters below — to read a page's data and request status when
1588
+ * building pagination UIs:
1589
+ *
1590
+ * ```ts
1591
+ * const page = paginationState.activePage;
1592
+ *
1593
+ * if (page?.isLoading) {
1594
+ * // show a spinner
1595
+ * } else if (page?.isError) {
1596
+ * // show page.reason
1597
+ * } else {
1598
+ * // render page.data
1599
+ * }
1600
+ * ```
1601
+ *
1602
+ * @since 5.9.0
1603
+ * @public
1604
+ * @hideconstructor
1605
+ */
1606
+ var PageCache = class {
1607
+ static {
1608
+ decorateFieldV2(this.prototype, "request", [signal]);
1609
+ }
1610
+ #request = (initializeDeferredDecorator(this, "request"), void 0);
1611
+ /** @internal */
1612
+ /**
1613
+ * The request that loaded (or is loading) this page, or `null` if the page is
1614
+ * known from links but was never requested. Wrap it in a `<Request>` component
1615
+ * to render the page's loading, error, and content states.
1616
+ */
1617
+ static {
1618
+ decorateFieldV2(this.prototype, "state", [signal]);
1619
+ }
1620
+ #state = (initializeDeferredDecorator(this, "state"), void 0);
1621
+ /** @internal */
1622
+ static {
1623
+ decorateFieldV2(this.prototype, "selfLink", [signal]);
1624
+ }
1625
+ #selfLink = (initializeDeferredDecorator(this, "selfLink"), void 0);
1626
+ /** The `self` link of this page — the URL that identifies it in the collection. */
1627
+ static {
1628
+ decorateFieldV2(this.prototype, "prevLink", [signal]);
1629
+ }
1630
+ #prevLink = (initializeDeferredDecorator(this, "prevLink"), void 0);
1631
+ /** The `prev` link of this page, or `null` at the start of the collection. */
1632
+ static {
1633
+ decorateFieldV2(this.prototype, "nextLink", [signal]);
1634
+ }
1635
+ #nextLink = (initializeDeferredDecorator(this, "nextLink"), void 0);
1636
+ /** The `next` link of this page, or `null` at the end of the collection. */
1637
+ static {
1638
+ decorateFieldV2(this.prototype, "firstLink", [signal]);
1639
+ }
1640
+ #firstLink = (initializeDeferredDecorator(this, "firstLink"), void 0);
1641
+ /** The `first` link of the collection, when the response exposed one. */
1642
+ static {
1643
+ decorateFieldV2(this.prototype, "lastLink", [signal]);
1644
+ }
1645
+ #lastLink = (initializeDeferredDecorator(this, "lastLink"), void 0);
1646
+ /** The `last` link of the collection, when the response exposed one. */
1647
+ static {
1648
+ decorateFieldV2(this.prototype, "pageNumber", [signal]);
1649
+ }
1650
+ #pageNumber = (initializeDeferredDecorator(this, "pageNumber"), void 0);
1651
+ /**
1652
+ * The 1-based page number, or `0` when unknown (for example cursor-based
1653
+ * pagination, where pages have no ordinal position). Derived from the
1654
+ * collection's {@link PageHints}.
1655
+ */
1656
+ static {
1657
+ decorateFieldV2(this.prototype, "before", [signal]);
1658
+ }
1659
+ #before = (initializeDeferredDecorator(this, "before"), void 0);
1660
+ /** @internal */
1661
+ static {
1662
+ decorateFieldV2(this.prototype, "after", [signal]);
1663
+ }
1664
+ #after = (initializeDeferredDecorator(this, "after"), void 0);
1665
+ /** @internal */
1666
+ constructor(manager, url) {
1667
+ this.manager = manager;
1668
+ this.pageNumber = 0;
1669
+ this.selfLink = url;
1670
+ }
1671
+ /**
1672
+ * The document this page's request resolved to, or `null` while it has not
1673
+ * resolved.
1674
+ */
1675
+ get value() {
1676
+ return this.state?.value;
1677
+ }
1678
+ /**
1679
+ * The `data` member of the loaded document — the page's items — or `null`
1680
+ * while the page has not loaded.
1681
+ */
1682
+ static {
1683
+ decorateMethodV2(this.prototype, "value", [memoized]);
1684
+ }
1685
+ get data() {
1686
+ return this.value?.data ?? null;
1687
+ }
1688
+ /**
1689
+ * Whether a request has ever been issued for this page. `false` for pages that
1690
+ * are known only from links.
1691
+ */
1692
+ static {
1693
+ decorateMethodV2(this.prototype, "data", [memoized]);
1694
+ }
1695
+ get isRequested() {
1696
+ return Boolean(this.state);
1697
+ }
1698
+ /** Whether this page's request has settled (successfully or with an error). */
1699
+ static {
1700
+ decorateMethodV2(this.prototype, "isRequested", [memoized]);
1701
+ }
1702
+ get isLoaded() {
1703
+ return this.isSuccess || this.isError;
1704
+ }
1705
+ /** Whether this page's request is currently in flight. */
1706
+ static {
1707
+ decorateMethodV2(this.prototype, "isLoaded", [memoized]);
1708
+ }
1709
+ get isLoading() {
1710
+ return Boolean(this.state?.isLoading);
1711
+ }
1712
+ /** Whether this page's request resolved successfully. */
1713
+ static {
1714
+ decorateMethodV2(this.prototype, "isLoading", [memoized]);
1715
+ }
1716
+ get isSuccess() {
1717
+ return Boolean(this.state?.isSuccess);
1718
+ }
1719
+ /** Whether this page's request was cancelled (aborted). */
1720
+ static {
1721
+ decorateMethodV2(this.prototype, "isSuccess", [memoized]);
1722
+ }
1723
+ get isCancelled() {
1724
+ return Boolean(this.state?.isCancelled);
1725
+ }
1726
+ /** Whether this page's request rejected with an error. */
1727
+ static {
1728
+ decorateMethodV2(this.prototype, "isCancelled", [memoized]);
1729
+ }
1730
+ get isError() {
1731
+ return Boolean(this.state?.isError);
1732
+ }
1733
+ /** The error this page's request rejected with, or `null` if it did not reject. */
1734
+ static {
1735
+ decorateMethodV2(this.prototype, "isError", [memoized]);
1736
+ }
1737
+ get reason() {
1738
+ return this.state?.reason ?? null;
1739
+ }
1740
+ /** The page at this page's `prev` link, or `null` at the start of the collection. */
1741
+ static {
1742
+ decorateMethodV2(this.prototype, "reason", [memoized]);
1743
+ }
1744
+ get prev() {
1745
+ const url = this.prevLink;
1746
+ return url ? this.manager.getPageCache(url) : null;
1747
+ }
1748
+ /** The page at this page's `next` link, or `null` at the end of the collection. */
1749
+ static {
1750
+ decorateMethodV2(this.prototype, "prev", [memoized]);
1751
+ }
1752
+ get next() {
1753
+ const url = this.nextLink;
1754
+ return url ? this.manager.getPageCache(url) : null;
1755
+ }
1756
+ /** The first page of the collection, when the response exposed a `first` link. */
1757
+ static {
1758
+ decorateMethodV2(this.prototype, "next", [memoized]);
1759
+ }
1760
+ get first() {
1761
+ const url = this.firstLink;
1762
+ return url ? this.manager.getPageCache(url) : null;
1763
+ }
1764
+ /** The last page of the collection, when the response exposed a `last` link. */
1765
+ static {
1766
+ decorateMethodV2(this.prototype, "first", [memoized]);
1767
+ }
1768
+ get last() {
1769
+ const url = this.lastLink;
1770
+ return url ? this.manager.getPageCache(url) : null;
1771
+ }
1772
+ /** @internal */
1773
+ static {
1774
+ decorateMethodV2(this.prototype, "last", [memoized]);
1775
+ }
1776
+ get isLinked() {
1777
+ return Boolean(this.before || this.after);
1778
+ }
1779
+ /** @internal */
1780
+ static {
1781
+ decorateMethodV2(this.prototype, "isLinked", [memoized]);
1782
+ }
1783
+ async load(request) {
1784
+ try {
1785
+ this.request = request;
1786
+ this.state = getRequestState(this.request);
1787
+ const content = (await this.request).content;
1788
+ const self = getHref(content?.links?.self);
1789
+ const first = getHref(content?.links?.first);
1790
+ const last = getHref(content?.links?.last);
1791
+ const next = getHref(content?.links?.next);
1792
+ const prev = getHref(content?.links?.prev);
1793
+ ((test) => {
1794
+ if (!test) throw new Error("Expected the page to have a self link");
1795
+ })(self);
1796
+ const pageNumber = this.getPageNumber(content);
1797
+ if (pageNumber) this.pageNumber = pageNumber;
1798
+ const firstPage = first ? this.manager.getPageCache(first) : null;
1799
+ const lastPage = last ? this.manager.getPageCache(last) : null;
1800
+ const prevPage = prev ? this.manager.getPageCache(prev) : null;
1801
+ const nextPage = next ? this.manager.getPageCache(next) : null;
1802
+ if (firstPage) {
1803
+ this.firstLink = first;
1804
+ firstPage.setPageNumber(1);
1805
+ if (!firstPage.after) firstPage.updateLinkage({ after: this });
1806
+ }
1807
+ if (lastPage) {
1808
+ this.lastLink = last;
1809
+ lastPage.setPageNumber(this.manager.totalPages);
1810
+ if (!lastPage.before) lastPage.updateLinkage({ before: this });
1811
+ }
1812
+ if (nextPage) {
1813
+ this.nextLink = next;
1814
+ nextPage.setPageNumber(this.pageNumber + 1);
1815
+ nextPage.updateLinks({ prev: self });
1816
+ }
1817
+ if (prevPage) {
1818
+ this.prevLink = prev;
1819
+ prevPage.setPageNumber(this.pageNumber - 1);
1820
+ prevPage.updateLinks({ next: self });
1821
+ }
1822
+ if (this.isLinked) {
1823
+ if (prevPage) prevPage.updateLinkage({ after: this });
1824
+ if (nextPage) nextPage.updateLinkage({ before: this });
1825
+ } else if (prevPage?.isLinked) {
1826
+ this.updateLinkage({ before: prevPage });
1827
+ if (nextPage) nextPage.updateLinkage({ before: this });
1828
+ } else if (nextPage?.isLinked) {
1829
+ this.updateLinkage({ after: nextPage });
1830
+ if (prevPage) prevPage.updateLinkage({ after: this });
1831
+ } else if ((prevPage || nextPage) && (firstPage || lastPage)) this.lookupLinkage(firstPage, lastPage);
1832
+ else if (prevPage || nextPage) this.updateLinkage({
1833
+ before: prevPage,
1834
+ after: nextPage
1835
+ });
1836
+ return content;
1837
+ } catch {}
1838
+ return null;
1839
+ }
1840
+ /** @internal */
1841
+ updateLinkage({ before, after }) {
1842
+ ((test) => {
1843
+ if (!test) throw new Error("Expected at least one of before or after page states to link to this page");
1844
+ })(before || after);
1845
+ const leftSide = before ?? after?.before;
1846
+ const rightSide = after ?? before?.after;
1847
+ if (leftSide && leftSide !== this) {
1848
+ leftSide.setAfter(this);
1849
+ this.setBefore(leftSide);
1850
+ }
1851
+ if (rightSide && rightSide !== this) {
1852
+ rightSide.setBefore(this);
1853
+ this.setAfter(rightSide);
1854
+ }
1855
+ }
1856
+ /** @internal */
1857
+ lookupLinkage(firstPage, lastPage) {
1858
+ ((test) => {
1859
+ if (!test) throw new Error("Expected at least one of firstPage or lastPage to lookup linkage against");
1860
+ })(firstPage || lastPage);
1861
+ if (firstPage && lastPage) {
1862
+ if (abs(this.pageNumber - firstPage.pageNumber) <= abs(this.pageNumber - lastPage.pageNumber)) this.lookupLinkageForward(firstPage);
1863
+ else this.lookupLinkageBackwards(lastPage);
1864
+ } else if (firstPage) this.lookupLinkageForward(firstPage);
1865
+ else if (lastPage) this.lookupLinkageBackwards(lastPage);
1866
+ }
1867
+ /** @internal */
1868
+ lookupLinkageForward(page) {
1869
+ while (page.after && page.after.pageNumber < this.pageNumber) page = page.after;
1870
+ this.updateLinkage({ before: page });
1871
+ }
1872
+ /** @internal */
1873
+ lookupLinkageBackwards(page) {
1874
+ while (page.before && page.before.pageNumber > this.pageNumber) page = page.before;
1875
+ this.updateLinkage({ after: page });
1876
+ }
1877
+ /** @internal */
1878
+ setBefore(page) {
1879
+ ((test) => {
1880
+ if (!test) throw new Error("Expected the before page to be a different page, got the same page");
1881
+ })(page !== this);
1882
+ this.before = page;
1883
+ }
1884
+ /** @internal */
1885
+ setAfter(page) {
1886
+ ((test) => {
1887
+ if (!test) throw new Error("Expected the after page to be a different page, got the same page");
1888
+ })(page !== this);
1889
+ this.after = page;
1890
+ }
1891
+ /** @internal */
1892
+ getPageNumber(document) {
1893
+ return this.manager.readPageHints(document).currentPage;
1894
+ }
1895
+ /** @internal */
1896
+ updateLinks = ({ prev, next, first, last }) => {
1897
+ if (prev) this.prevLink = prev;
1898
+ if (next) this.nextLink = next;
1899
+ if (first) this.firstLink = first;
1900
+ if (last) this.lastLink = last;
1901
+ };
1902
+ /** @internal */
1903
+ setPageNumber = (pageNumber) => {
1904
+ if (!this.pageNumber) this.pageNumber = pageNumber;
1905
+ };
1906
+ };
1907
+
1908
+ //#endregion
1909
+ //#region src/signals/pagination-cache.ts
1910
+ const PaginationCacheMap = /* @__PURE__ */ new Map();
1911
+ /**
1912
+ * A hint function for extracting the `currentPage` and `totalPages` from a loaded
1913
+ * document, for when the response does not expose these values through the
1914
+ * default `meta` locations. Provided by the consumer via `<Paginate />`'s
1915
+ * `@pageHints` arg:
1916
+ *
1917
+ * ```gts
1918
+ * <Paginate @pageHints={{...}} />
1919
+ * ```
1920
+ *
1921
+ * Since these values are attached to the shared {@link PaginationCache}, the hint is
1922
+ * a property of the *collection*, not the component. Every `<Paginate />` sharing a
1923
+ * collection must provide the same function reference — define it once at module
1924
+ * scope and import it everywhere.
1925
+ *
1926
+ * @since 5.9.0
1927
+ * @public
1928
+ */
1929
+ /**
1930
+ * The default {@link PageHints}. Reads `currentPage`/`page` and `totalPages` from the
1931
+ * document `meta`, matching the behavior used before `pageHints` was configurable.
1932
+ * Used whenever the consumer does not provide a `pageHints` function.
1933
+ *
1934
+ * @since 5.9.0
1935
+ * @public
1936
+ */
1937
+ const defaultPageHints = (document) => {
1938
+ return {
1939
+ currentPage: document.meta?.page ?? document.meta?.currentPage ?? 0,
1940
+ totalPages: document.meta?.totalPages ?? 0
1941
+ };
1942
+ };
1943
+ /**
1944
+ * The global, shared cache for a paginated collection. Keyed by the collection's
1945
+ * `first` (or `self`) link, so that multiple components paging the same collection
1946
+ * share loaded pages, the page graph, and `totalPages`.
1947
+ *
1948
+ * This holds only shared, request-agnostic data. Per-component state (the active
1949
+ * page, navigation) lives on {@link PaginationState}, which is the API consumers
1950
+ * interact with — the cache itself is plumbing shared between the pagination
1951
+ * classes.
1952
+ *
1953
+ * @since 5.9.0
1954
+ * @public
1955
+ * @hideconstructor
1956
+ */
1957
+ var PaginationCache = class {
1958
+ static {
1959
+ decorateFieldV2(this.prototype, "firstPage", [signal]);
1960
+ }
1961
+ #firstPage = (initializeDeferredDecorator(this, "firstPage"), void 0);
1962
+ /**
1963
+ * The cache key this collection is stored under in the module-level cache —
1964
+ * its `first` (or `self`) link. This is the collection's identity: two
1965
+ * requests whose documents resolve to the same key are pages of the same
1966
+ * collection.
1967
+ *
1968
+ * @internal
1969
+ */
1970
+ /** @internal */
1971
+ static {
1972
+ decorateFieldV2(this.prototype, "totalPages", [signal]);
1973
+ }
1974
+ #totalPages = (initializeDeferredDecorator(this, "totalPages"), void 0);
1975
+ /**
1976
+ * The total number of pages in the collection, or `0` when unknown. Consumers
1977
+ * should read this via {@link PaginationState.totalPages}.
1978
+ */
1979
+ static {
1980
+ decorateFieldV2(this.prototype, "isNumbered", [signal]);
1981
+ }
1982
+ #isNumbered = (initializeDeferredDecorator(this, "isNumbered"), void 0);
1983
+ /**
1984
+ * Whether this collection has server-known page numbers. Stays `false` for
1985
+ * cursor-based collections (opaque `prev`/`next`, no index/total), which drives
1986
+ * whether numbered links are produced. Set once a {@link PageHints} yields a real
1987
+ * `currentPage`/`totalPages`.
1988
+ *
1989
+ * @internal
1990
+ */
1991
+ /** @internal */
1992
+ /** @internal */
1993
+ pageHints = defaultPageHints;
1994
+ constructor(key) {
1995
+ this.key = key;
1996
+ this.pagesCache = /* @__PURE__ */ new Map();
1997
+ this.firstPage = null;
1998
+ this.totalPages = 0;
1999
+ this.isNumbered = false;
2000
+ }
2001
+ /**
2002
+ * Installs the consumer-provided {@link PageHints} onto the shared cache. The first
2003
+ * explicit hint wins; passing `undefined` (no hint) is a no-op that preserves the
2004
+ * default. In dev, asserts that components sharing a collection do not provide
2005
+ * diverging hint functions.
2006
+ *
2007
+ * @internal
2008
+ */
2009
+ installPageHints(pageHints) {
2010
+ if (!pageHints) return;
2011
+ if (this.pageHints === defaultPageHints) {
2012
+ this.pageHints = pageHints;
2013
+ return;
2014
+ }
2015
+ ((test) => {
2016
+ if (!test) throw new Error("Received diverging `pageHints` functions for the same paginated collection. Provide the same function reference to every <Paginate /> sharing a collection (define it once at module scope).");
2017
+ })(this.pageHints === pageHints);
2018
+ }
2019
+ /**
2020
+ * Runs the active {@link PageHints} against a document.
2021
+ *
2022
+ * Both values are *hints*, not requirements. A value of `0` means "unknown" —
2023
+ * the response did not expose it and no `pageHints` function derived it. When a
2024
+ * value is present (`> 0`) it is relied upon (numbered links, total, sparse
2025
+ * placement of jumped-to pages); when absent the page graph falls back to pure
2026
+ * `prev`/`next` adjacency (as in cursor/infinite streams).
2027
+ *
2028
+ * @internal
2029
+ */
2030
+ readPageHints(document) {
2031
+ const { currentPage, totalPages } = this.pageHints(document);
2032
+ if (currentPage > 0 || totalPages > 0) this.isNumbered = true;
2033
+ return {
2034
+ currentPage,
2035
+ totalPages
2036
+ };
2037
+ }
2038
+ /** @internal */
2039
+ getPageCache(url) {
2040
+ let page = this.pagesCache.get(url);
2041
+ if (!page) {
2042
+ page = new PageCache(this, url);
2043
+ this.pagesCache.set(url, page);
2044
+ }
2045
+ return page;
2046
+ }
2047
+ /** @internal */
2048
+ loadPage(url, request) {
2049
+ const page = this.getPageCache(url);
2050
+ if ((!page.isLoaded || page.isError) && request) {
2051
+ ((test) => {
2052
+ if (!test) throw new Error("Expected a request to a load a page");
2053
+ })(request);
2054
+ page.load(request).then((document) => {
2055
+ this.updateFirstPage(page);
2056
+ if (document) this.totalPages = this.getTotalPages(document);
2057
+ });
2058
+ }
2059
+ return page;
2060
+ }
2061
+ /** @internal */
2062
+ updateFirstPage(page) {
2063
+ let maybeFirstPage = page;
2064
+ while (maybeFirstPage.before) maybeFirstPage = maybeFirstPage.before;
2065
+ if (!this.firstPage || this.firstPage.pageNumber > maybeFirstPage.pageNumber) this.firstPage = maybeFirstPage;
2066
+ }
2067
+ /** @internal */
2068
+ getTotalPages(document) {
2069
+ return this.readPageHints(document).totalPages;
2070
+ }
2071
+ /**
2072
+ * Every page known to the shared graph, in order — loaded pages and pages
2073
+ * known only from links — across all components sharing the collection.
2074
+ *
2075
+ * This is the whole-collection view. For the run a single component is
2076
+ * viewing, use {@link PaginationState.pages}.
2077
+ *
2078
+ * ```ts
2079
+ * const cache = getPaginationCache(firstLink);
2080
+ * for (const page of cache.pages) {
2081
+ * // page.isLoaded, page.pageNumber, page.data, ...
2082
+ * }
2083
+ * ```
2084
+ */
2085
+ get pages() {
2086
+ const self = this;
2087
+ return { *[Symbol.iterator]() {
2088
+ let page = self.firstPage;
2089
+ while (page) {
2090
+ yield page;
2091
+ page = page.after;
2092
+ }
2093
+ } };
2094
+ }
2095
+ /**
2096
+ * The items of every loaded page in the shared graph, flattened into one
2097
+ * contiguous iterable in page order. Pages that are known but not loaded
2098
+ * contribute nothing.
2099
+ *
2100
+ * This is the whole-collection view. For the run a single component is
2101
+ * viewing, use {@link PaginationState.data}.
2102
+ */
2103
+ static {
2104
+ decorateMethodV2(this.prototype, "pages", [memoized]);
2105
+ }
2106
+ get data() {
2107
+ const self = this;
2108
+ return { *[Symbol.iterator]() {
2109
+ for (const page of self.pages) if (page.data) yield* page.data;
2110
+ } };
2111
+ }
2112
+ static {
2113
+ decorateMethodV2(this.prototype, "data", [memoized]);
2114
+ }
2115
+ };
2116
+ /**
2117
+ * Get the shared {@link PaginationCache} for a given cache key (the collection's
2118
+ * `first` or `self` link). Returns the same instance for the same key for the
2119
+ * lifetime of the module.
2120
+ *
2121
+ * @since 5.9.0
2122
+ * @public
2123
+ */
2124
+ function getPaginationCache(key) {
2125
+ let cache = PaginationCacheMap.get(key);
2126
+ if (!cache) {
2127
+ cache = new PaginationCache(key);
2128
+ PaginationCacheMap.set(key, cache);
2129
+ }
2130
+ return cache;
2131
+ }
2132
+ /**
2133
+ * Clears the module-level pagination cache used by {@link getPaginationCache}.
2134
+ * Primarily intended for test isolation, since the cache is keyed by url and
2135
+ * otherwise persists for the lifetime of the module.
2136
+ *
2137
+ * @since 5.9.0
2138
+ * @public
2139
+ */
2140
+ function clearPaginationCache() {
2141
+ PaginationCacheMap.clear();
2142
+ }
2143
+
2144
+ //#endregion
2145
+ //#region src/signals/pagination-state.ts
2146
+ /**
2147
+ * The two navigation surfaces a `<Paginate />` component can drive. Selecting
2148
+ * one (via the component's `@mode` arg) narrows the yielded state so the two
2149
+ * APIs cannot be mixed:
2150
+ *
2151
+ * - `'paged'` — single-page view, see {@link PagedPaginationState}.
2152
+ * - `'infinite'` — accumulated view, see {@link InfinitePaginationState}.
2153
+ */
2154
+ /**
2155
+ * The part of a {@link PaginationState} available to both navigation surfaces.
2156
+ */
2157
+ /**
2158
+ * The paged (single-page view) surface of a {@link PaginationState}: render
2159
+ * {@link PaginationState.activePageRequest | activePageRequest}, navigate with
2160
+ * {@link PaginationState.loadPage | loadPage}. This is what the `<Paginate />`
2161
+ * component yields in `'paged'` mode (the default).
2162
+ */
2163
+ /**
2164
+ * The infinite (accumulated view) surface of a {@link PaginationState}: render
2165
+ * {@link PaginationState.data | data}, grow it with
2166
+ * {@link PaginationState.loadNext | loadNext}/{@link PaginationState.loadPrev | loadPrev}.
2167
+ * This is what the `<Paginate />` component yields in `'infinite'` mode.
2168
+ */
2169
+ /**
2170
+ * Resolves a {@link PaginateMode} to the surface it exposes, so a component
2171
+ * generic over the mode can yield only that surface.
2172
+ */
2173
+ /**
2174
+ * The per-component, local pagination state. It houses the state that is unique
2175
+ * to a single component instance — the active page and navigation — while
2176
+ * referencing a shared {@link PaginationCache} for the page graph and data.
2177
+ *
2178
+ * This is the object yielded by the `<Paginate />` component, narrowed by the
2179
+ * component's `@mode` arg to one of its two navigation surfaces so the two
2180
+ * APIs cannot be mixed:
2181
+ *
2182
+ * - **Paged** (`@mode="paged"`, the default): {@link PagedPaginationState} —
2183
+ * render {@link activePageRequest}, navigate with {@link loadPage} (what the
2184
+ * numbered/relational links call). Reads {@link activePage}.
2185
+ * - **Infinite** (`@mode="infinite"`): {@link InfinitePaginationState} — render
2186
+ * {@link data}, wrap {@link nextRequest}/{@link previousRequest} in `<Request>`
2187
+ * for loading state, and grow the view with {@link loadNext}/{@link loadPrev}.
2188
+ *
2189
+ * Both surfaces read the same shared page graph; the mode only selects which
2190
+ * API is exposed.
2191
+ *
2192
+ * Instances are created via {@link getPaginationState} (or by the `<Paginate />`
2193
+ * component on your behalf), never constructed directly.
2194
+ *
2195
+ * @since 5.9.0
2196
+ * @public
2197
+ * @hideconstructor
2198
+ */
2199
+ var PaginationState = class {
2200
+ /** @internal */
2201
+ /** @internal */
2202
+ /** @internal */
2203
+ /**
2204
+ * The shared page graph and data this component reads from.
2205
+ *
2206
+ * @internal
2207
+ */
2208
+ /**
2209
+ * The page the paged surface is currently showing. Starts at the page this
2210
+ * component first loaded and moves whenever {@link loadPage} runs (for
2211
+ * example a numbered link is clicked).
2212
+ */
2213
+ /**
2214
+ * The page this component first loaded, used to seed the active page and frontier.
2215
+ *
2216
+ * @internal
2217
+ */
2218
+ /**
2219
+ * The first and last loaded pages of the contiguous run this component is
2220
+ * viewing. Drives the infinite surface — {@link data} walks from
2221
+ * `frontierStart` to `frontierEnd`, and {@link loadPrev}/{@link loadNext} extend
2222
+ * them backward/forward. Both seed to {@link initialPage}; a purely paged
2223
+ * consumer never extends them, so they stay put and are effectively unused.
2224
+ *
2225
+ * @internal
2226
+ */
2227
+ /** @internal */
2228
+ /**
2229
+ * The request of the latest {@link adoptPage} call — only that call may
2230
+ * commit. Later calls (or a {@link loadPage} navigation) claim the slot,
2231
+ * superseding in-flight adoptions so the newest navigation always wins.
2232
+ * Untracked bookkeeping.
2233
+ *
2234
+ * @internal
2235
+ */
2236
+ constructor(request, pageHints) {
2237
+ this.store = request.requester;
2238
+ this.request = request;
2239
+ this.pageHints = pageHints;
2240
+ this._adoptTarget = null;
2241
+ this.setup();
2242
+ }
2243
+ /**
2244
+ * The request for the {@link activePage}, for the paged surface to render. This
2245
+ * is what a single-page view wraps in a `<Request>` to show the active page's
2246
+ * loading, error, and content states:
2247
+ *
2248
+ * ```gts
2249
+ * <Paginate @request={{this.request}}>
2250
+ * <:content as |pages|>
2251
+ * <Request @request={{pages.activePageRequest}}>
2252
+ * <:content as |result|>
2253
+ * {{#each result.data as |item|}}...{{/each}}
2254
+ * </:content>
2255
+ * </Request>
2256
+ * </:content>
2257
+ * </Paginate>
2258
+ * ```
2259
+ */
2260
+ get activePageRequest() {
2261
+ return this.activePage?.request ?? null;
2262
+ }
2263
+ /**
2264
+ * The total number of pages in the collection, or `0` when it is unknown (for
2265
+ * example a cursor-based collection that reports no total).
2266
+ *
2267
+ * ```gts
2268
+ * <p>Page {{pages.activePage.pageNumber}} of {{pages.totalPages}}</p>
2269
+ * ```
2270
+ */
2271
+ static {
2272
+ decorateMethodV2(this.prototype, "activePageRequest", [memoized]);
2273
+ }
2274
+ get totalPages() {
2275
+ return this.paginationCache?.totalPages ?? 0;
2276
+ }
2277
+ /**
2278
+ * The pages of the run this component is viewing, from the backward frontier
2279
+ * to the forward frontier inclusive, in order. Part of the infinite surface:
2280
+ * it is the same run as {@link data}, yielding the {@link PageCache} objects
2281
+ * instead of their flattened items — use it when the UI needs per-page
2282
+ * boundaries or request states.
2283
+ *
2284
+ * Grows as {@link loadNext}/{@link loadPrev} extend the frontier. Scoped to
2285
+ * this component's frontier (not the shared cache), so components paging the
2286
+ * same collection to different extents each see only what they have scrolled
2287
+ * through. For every page known to the whole collection, see
2288
+ * {@link PaginationCache.pages}.
2289
+ */
2290
+ static {
2291
+ decorateMethodV2(this.prototype, "totalPages", [memoized]);
2292
+ }
2293
+ get pages() {
2294
+ const self = this;
2295
+ return { *[Symbol.iterator]() {
2296
+ const end = self.frontierEnd;
2297
+ let page = self.frontierStart;
2298
+ while (page) {
2299
+ yield page;
2300
+ if (page === end) break;
2301
+ page = page.after;
2302
+ }
2303
+ } };
2304
+ }
2305
+ /**
2306
+ * The accumulated items across the loaded run, from the backward frontier to
2307
+ * the forward frontier inclusive — the single set an infinite collection renders.
2308
+ * Grows as {@link loadNext}/{@link loadPrev} extend the frontier. Scoped to this
2309
+ * component's frontier (not the shared cache), so components paging the same
2310
+ * collection to different extents each see only what they have scrolled through.
2311
+ *
2312
+ * The flattened items of {@link pages}, as one contiguous iterable. For the
2313
+ * items of every loaded page in the whole collection, see
2314
+ * {@link PaginationCache.data}.
2315
+ *
2316
+ * ```gts
2317
+ * <Paginate @request={{this.request}} @mode="infinite">
2318
+ * <:content as |pages features|>
2319
+ * {{#each pages.data as |item|}}...{{/each}}
2320
+ * {{#if pages.hasNext}}
2321
+ * <button {{on "click" features.loadNext}}>Load more</button>
2322
+ * {{/if}}
2323
+ * </:content>
2324
+ * </Paginate>
2325
+ * ```
2326
+ */
2327
+ static {
2328
+ decorateMethodV2(this.prototype, "pages", [memoized]);
2329
+ }
2330
+ get data() {
2331
+ const self = this;
2332
+ return { *[Symbol.iterator]() {
2333
+ for (const page of self.pages) if (page.data) yield* page.data;
2334
+ } };
2335
+ }
2336
+ /**
2337
+ * Whether a page exists after the forward frontier — i.e. there is more to load
2338
+ * going forward. Use to hide the trailing load-more sentinel at end-of-list:
2339
+ *
2340
+ * ```gts
2341
+ * {{#if pages.hasNext}}
2342
+ * <button {{on "click" features.loadNext}}>Load more</button>
2343
+ * {{/if}}
2344
+ * ```
2345
+ */
2346
+ static {
2347
+ decorateMethodV2(this.prototype, "data", [memoized]);
2348
+ }
2349
+ get hasNext() {
2350
+ return Boolean(this.frontierEnd?.nextLink);
2351
+ }
2352
+ /**
2353
+ * Whether a page exists before the backward frontier.
2354
+ */
2355
+ static {
2356
+ decorateMethodV2(this.prototype, "hasNext", [memoized]);
2357
+ }
2358
+ get hasPrevious() {
2359
+ return Boolean(this.frontierStart?.prevLink);
2360
+ }
2361
+ /**
2362
+ * The request for the page just after the forward frontier, for the infinite
2363
+ * surface. `null` until {@link loadNext} fires it (so a `<Request>` wrapping it
2364
+ * renders its idle block), the in-flight `Future` while that page loads, then
2365
+ * `null` again once the frontier advances onto it. Also `null` at end-of-list.
2366
+ *
2367
+ * ```gts
2368
+ * {{#if pages.hasNext}}
2369
+ * <Request @request={{pages.nextRequest}}>
2370
+ * <:idle><button {{on "click" features.loadNext}}>Load more</button></:idle>
2371
+ * <:loading><Spinner /></:loading>
2372
+ * </Request>
2373
+ * {{/if}}
2374
+ * ```
2375
+ */
2376
+ static {
2377
+ decorateMethodV2(this.prototype, "hasPrevious", [memoized]);
2378
+ }
2379
+ get nextRequest() {
2380
+ const url = this.frontierEnd?.nextLink;
2381
+ if (!url) return null;
2382
+ return this.paginationCache?.getPageCache(url).request ?? null;
2383
+ }
2384
+ /**
2385
+ * The request for the page just before the backward frontier. Mirror of
2386
+ * {@link nextRequest} for {@link loadPrev}.
2387
+ */
2388
+ static {
2389
+ decorateMethodV2(this.prototype, "nextRequest", [memoized]);
2390
+ }
2391
+ get previousRequest() {
2392
+ const url = this.frontierStart?.prevLink;
2393
+ if (!url) return null;
2394
+ return this.paginationCache?.getPageCache(url).request ?? null;
2395
+ }
2396
+ /** @internal */
2397
+ static {
2398
+ decorateMethodV2(this.prototype, "previousRequest", [memoized]);
2399
+ }
2400
+ async setup() {
2401
+ let document;
2402
+ try {
2403
+ document = await this.request;
2404
+ } catch {
2405
+ return;
2406
+ }
2407
+ const content = document.content;
2408
+ const selfLink = getHref(content.links?.self);
2409
+ const firstLink = getHref(content.links?.first);
2410
+ ((test) => {
2411
+ if (!test) throw new Error("Expected the initial document to have a self link");
2412
+ })(selfLink);
2413
+ const cache = getPaginationCache(firstLink ?? selfLink ?? "");
2414
+ cache.installPageHints(this.pageHints);
2415
+ this.paginationCache = cache;
2416
+ cache.totalPages = cache.getTotalPages(content);
2417
+ this.activePage = this.initialPage = cache.loadPage(selfLink, this.request);
2418
+ this.frontierStart = this.frontierEnd = this.initialPage;
2419
+ }
2420
+ /**
2421
+ * Commits a resolved, membership-proven page into this state, making it the
2422
+ * {@link activePage}. The synchronous commit step under {@link adoptPage},
2423
+ * which is where the resolution and membership verification live.
2424
+ *
2425
+ * It only activates the page and keeps the infinite surface's frontier
2426
+ * coherent — a page already inside the run leaves the frontier untouched,
2427
+ * an adjacent page extends it, and a disjoint page resets the run to the
2428
+ * adopted page (jump semantics).
2429
+ *
2430
+ * @internal
2431
+ */
2432
+ _activate(page, url) {
2433
+ this.activePage = page;
2434
+ for (const existing of this.pages) if (existing === page) return;
2435
+ if (this.frontierEnd?.nextLink === url) this.frontierEnd = page;
2436
+ else if (this.frontierStart?.prevLink === url) this.frontierStart = page;
2437
+ else this.frontierStart = this.frontierEnd = page;
2438
+ }
2439
+ /**
2440
+ * Adopts an externally-issued request into this pagination, making its page
2441
+ * the {@link activePage} — the programmatic entry point for route-driven
2442
+ * navigation when managing a `PaginationState` directly (the `<Paginate />`
2443
+ * component uses the same mechanism for a changed `@request` arg).
2444
+ *
2445
+ * Awaits the request and verifies that its document is a page of this
2446
+ * state's collection (same `first` — or `self` — link). On a match, the
2447
+ * page is loaded (a page already in the shared cache is reused) and — once
2448
+ * its request settles — committed: it becomes the active page, and the
2449
+ * infinite surface's run is kept coherent (a page already inside the run
2450
+ * leaves it untouched, an adjacent page extends it, a disjoint page resets
2451
+ * the run to the adopted page). The commit happens only after the page has
2452
+ * loaded, so the previous page stays active — and rendered — while the
2453
+ * adoption resolves. Returns the page's document.
2454
+ *
2455
+ * Concurrent calls race safely: the latest call wins. An earlier in-flight
2456
+ * adoption is superseded and commits nothing, and a {@link loadPage}
2457
+ * navigation also supersedes a pending adoption (the user's click is the
2458
+ * newer intent).
2459
+ *
2460
+ * Returns `null` — leaving the state untouched — whenever the adoption does
2461
+ * not commit:
2462
+ *
2463
+ * - the request (or its page's load) rejected
2464
+ * - the document is a page of a *different* collection
2465
+ * - this state has not finished setting up its own collection yet
2466
+ * - the call was superseded by a newer navigation
2467
+ *
2468
+ * ```ts
2469
+ * const pages = getPaginationState(initialRequest);
2470
+ * // later, e.g. in a route model hook reacting to a ?page= param:
2471
+ * const adopted = await pages.adoptPage(store.request(query));
2472
+ * if (adopted === null) {
2473
+ * // not part of this collection — start a fresh pagination
2474
+ * }
2475
+ * ```
2476
+ *
2477
+ * It is a stable reference, so it is safe to pass around as an "action" or
2478
+ * "event" handler.
2479
+ */
2480
+ adoptPage = async (request) => {
2481
+ this._adoptTarget = request;
2482
+ let content;
2483
+ try {
2484
+ content = (await request).content;
2485
+ } catch {
2486
+ return null;
2487
+ }
2488
+ if (this._adoptTarget !== request) return null;
2489
+ const cache = this.paginationCache;
2490
+ if (!cache) return null;
2491
+ const selfLink = getHref(content.links?.self);
2492
+ const firstLink = getHref(content.links?.first);
2493
+ ((test) => {
2494
+ if (!test) throw new Error("Expected the adopted document to have a self link");
2495
+ })(selfLink);
2496
+ if (!selfLink || (firstLink ?? selfLink) !== cache.key) return null;
2497
+ const page = cache.loadPage(selfLink, request);
2498
+ try {
2499
+ await page.request;
2500
+ } catch {
2501
+ return null;
2502
+ }
2503
+ if (this._adoptTarget !== request) return null;
2504
+ this._activate(page, selfLink);
2505
+ return page.value;
2506
+ };
2507
+ /**
2508
+ * Extends the backward frontier by one page, prepending it to {@link data}.
2509
+ * The frontier advances only once the page has loaded, so
2510
+ * {@link previousRequest} tracks the in-flight page meanwhile. Returns the
2511
+ * loaded value, or `null` when there is no previous page or the load fails.
2512
+ *
2513
+ * On failure the frontier stays put and {@link previousRequest} keeps
2514
+ * resolving to the failed page, so a wrapping `<Request>` renders its error
2515
+ * block. Calling again retries: the failed page is re-requested with a
2516
+ * forced reload.
2517
+ *
2518
+ * In templates it is also available as the `loadPrev` content feature
2519
+ * ({@link InfinitePaginationContentFeatures.loadPrev}) yielded by
2520
+ * `<Paginate />`; the two are the same function.
2521
+ *
2522
+ * It is a stable reference, so it is safe to pass around as an "action" or
2523
+ * "event" handler.
2524
+ */
2525
+ loadPrev = async () => {
2526
+ return this._extend("prev");
2527
+ };
2528
+ /**
2529
+ * Extends the forward frontier by one page, appending it to {@link data}.
2530
+ * Mirror of {@link loadPrev}.
2531
+ *
2532
+ * In templates it is also available as the `loadNext` content feature
2533
+ * ({@link InfinitePaginationContentFeatures.loadNext}) yielded by
2534
+ * `<Paginate />`; the two are the same function.
2535
+ *
2536
+ * ```gts
2537
+ * <button {{on "click" pages.loadNext}}>Load more</button>
2538
+ * ```
2539
+ */
2540
+ loadNext = async () => {
2541
+ return this._extend("next");
2542
+ };
2543
+ /** @internal */
2544
+ _extend = async (dir) => {
2545
+ const cache = this.paginationCache;
2546
+ ((test) => {
2547
+ if (!test) throw new Error("Expected the pagination cache to be set up before loading a page");
2548
+ })(cache);
2549
+ const frontier = dir === "next" ? this.frontierEnd : this.frontierStart;
2550
+ const url = dir === "next" ? frontier?.nextLink : frontier?.prevLink;
2551
+ if (!url) return null;
2552
+ const page = cache.getPageCache(url);
2553
+ if (!page.isRequested || page.isError) {
2554
+ const request = this.store.request(page.isError ? {
2555
+ method: "GET",
2556
+ url,
2557
+ cacheOptions: { reload: true }
2558
+ } : {
2559
+ method: "GET",
2560
+ url
2561
+ });
2562
+ cache.loadPage(url, request);
2563
+ }
2564
+ try {
2565
+ await page.request;
2566
+ } catch {
2567
+ return null;
2568
+ }
2569
+ if (dir === "next") this.frontierEnd = page;
2570
+ else this.frontierStart = page;
2571
+ return page.value;
2572
+ };
2573
+ /**
2574
+ * Loads a specific page by its URL and makes it the {@link activePage},
2575
+ * requesting it first if it is not already loaded. This is the paged surface's
2576
+ * navigation entry point, called by the numbered and relational links.
2577
+ *
2578
+ * In templates it is also available as the `loadPage` content feature
2579
+ * ({@link PagedPaginationContentFeatures.loadPage}) yielded by `<Paginate />`;
2580
+ * the two are the same function.
2581
+ *
2582
+ * It is a stable reference, so it is safe to pass around as an "action" or
2583
+ * "event" handler. Returns the page's value, or `null` if it has none or
2584
+ * the load fails.
2585
+ *
2586
+ * On failure the page stays active and {@link activePageRequest} resolves to
2587
+ * it, so a wrapping `<Request>` renders its error block. Calling again (for
2588
+ * example clicking the page's link a second time) retries: the failed page
2589
+ * is re-requested with a forced reload.
2590
+ *
2591
+ * ```gts
2592
+ * <EachLink @pages={{pages}}>
2593
+ * <:link as |link|>
2594
+ * <button {{on "click" (fn features.loadPage link.url)}}>{{link.text}}</button>
2595
+ * </:link>
2596
+ * </EachLink>
2597
+ * ```
2598
+ */
2599
+ loadPage = async (url) => {
2600
+ const cache = this.paginationCache;
2601
+ ((test) => {
2602
+ if (!test) throw new Error("Expected the pagination cache to be set up before loading a page");
2603
+ })(cache);
2604
+ this._adoptTarget = null;
2605
+ const page = cache.getPageCache(url);
2606
+ this.activePage = page;
2607
+ if (!page.isLoaded || page.isError) {
2608
+ const request = this.store.request(page.isError ? {
2609
+ method: "GET",
2610
+ url,
2611
+ cacheOptions: { reload: true }
2612
+ } : {
2613
+ method: "GET",
2614
+ url
2615
+ });
2616
+ cache.loadPage(url, request);
2617
+ try {
2618
+ await page.request;
2619
+ } catch {
2620
+ return null;
2621
+ }
2622
+ }
2623
+ return page.value;
2624
+ };
2625
+ };
2626
+ defineSignal(PaginationState.prototype, "paginationCache", null);
2627
+ defineSignal(PaginationState.prototype, "activePage", null);
2628
+ defineSignal(PaginationState.prototype, "initialPage", null);
2629
+ defineSignal(PaginationState.prototype, "frontierStart", null);
2630
+ defineSignal(PaginationState.prototype, "frontierEnd", null);
2631
+ const PaginationStateCache = /* @__PURE__ */ new WeakMap();
2632
+ /**
2633
+ * Get the {@link PaginationState} for a given request. Returns the same instance
2634
+ * for the same request future, so that repeated calls (e.g. in a template, or
2635
+ * alongside the `<Paginate />` component using the same request) share the same
2636
+ * local pagination state. Keyed by request identity, just like
2637
+ * {@link getRequestState}.
2638
+ *
2639
+ * ```ts
2640
+ * const future = store.request(query);
2641
+ * const pages = getPaginationState(future);
2642
+ *
2643
+ * await future;
2644
+ * pages.totalPages; // now known, if the response exposed it
2645
+ * await pages.loadNext();
2646
+ * ```
2647
+ *
2648
+ * @since 5.9.0
2649
+ * @public
2650
+ */
2651
+ function getPaginationState(request, pageHints) {
2652
+ let state = PaginationStateCache.get(request);
2653
+ if (!state) {
2654
+ state = new PaginationState(request, pageHints);
2655
+ PaginationStateCache.set(request, state);
2656
+ }
2657
+ return state;
2658
+ }
2659
+
2660
+ //#endregion
2661
+ //#region src/signals/pagination-links.ts
2662
+ const PaginationLinksCache = /* @__PURE__ */ new WeakMap();
2663
+ /**
2664
+ * A single numbered link, e.g. page `3`. Loads its page and makes it active when
2665
+ * {@link setActive} runs. Carries its {@link index} and its
2666
+ * {@link distanceFromActiveIndex} so a UI can style links by how far they sit
2667
+ * from the current page.
2668
+ *
2669
+ * ```gts
2670
+ * <EachLink @pages={{pages}} as |state|>
2671
+ * {{#each state.links as |link|}}
2672
+ * {{#if link.isReal}}
2673
+ * <button class={{if link.isCurrent "active"}} {{on "click" link.setActive}}>
2674
+ * {{link.text}}
2675
+ * </button>
2676
+ * {{/if}}
2677
+ * {{/each}}
2678
+ * </EachLink>
2679
+ * ```
2680
+ *
2681
+ * @since 5.9.0
2682
+ * @public
2683
+ * @hideconstructor
2684
+ */
2685
+ var RealPaginationLink = class {
2686
+ isReal = true;
2687
+ url;
2688
+ index;
2689
+ isCurrent;
2690
+ distanceFromActiveIndex;
2691
+ /** @internal */
2692
+ constructor(url, index, activeIndex, loadPage) {
2693
+ this.url = url;
2694
+ this.index = index;
2695
+ this.isCurrent = index === activeIndex;
2696
+ this.distanceFromActiveIndex = Math.abs(index - activeIndex);
2697
+ this._loadPage = loadPage;
2698
+ }
2699
+ get text() {
2700
+ return `${this.index}`;
2701
+ }
2702
+ /**
2703
+ * Loads this link's page and makes it the active page on the associated
2704
+ * {@link PaginationState}. It is a stable reference, so it is safe to pass
2705
+ * around as an "action" or "event" handler:
2706
+ *
2707
+ * ```gts
2708
+ * <button {{on "click" link.setActive}}>{{link.text}}</button>
2709
+ * ```
2710
+ */
2711
+ setActive = () => {
2712
+ return this._loadPage(this.url);
2713
+ };
2714
+ };
2715
+ /**
2716
+ * A stand-in for a run of pages that have not been loaded yet, rendered as an
2717
+ * ellipsis between numbered links. It covers an {@link indexRange} rather than a
2718
+ * single page and has no page to navigate to.
2719
+ *
2720
+ * ```gts
2721
+ * <EachLink @pages={{pages}} as |state|>
2722
+ * {{#each state.links as |link|}}
2723
+ * {{#unless link.isReal}}
2724
+ * <span title="{{link.rangeSize}} more pages">{{link.text}}</span>
2725
+ * {{/unless}}
2726
+ * {{/each}}
2727
+ * </EachLink>
2728
+ * ```
2729
+ *
2730
+ * @since 5.9.0
2731
+ * @public
2732
+ * @hideconstructor
2733
+ */
2734
+ var PlaceholderPaginationLink = class {
2735
+ isReal = false;
2736
+ /**
2737
+ * The inclusive `[start, end]` page-number range of not-yet-loaded pages this
2738
+ * placeholder stands in for.
2739
+ */
2740
+ indexRange;
2741
+ /** @internal */
2742
+ activeIndex;
2743
+ text = ".";
2744
+ constructor(index, activeIndex) {
2745
+ this.indexRange = index;
2746
+ this.activeIndex = activeIndex;
2747
+ }
2748
+ /** The number of pages this placeholder covers. */
2749
+ get rangeSize() {
2750
+ return this.indexRange[1] - this.indexRange[0] + 1;
2751
+ }
2752
+ /**
2753
+ * The distance between the active page and the nearest edge of this
2754
+ * placeholder's index range.
2755
+ */
2756
+ get distanceFromActiveIndex() {
2757
+ const [start, end] = this.indexRange;
2758
+ return Math.min(Math.abs(start - this.activeIndex), Math.abs(end - this.activeIndex));
2759
+ }
2760
+ /** @internal */
2761
+ _mergeRange(newRange) {
2762
+ const [oldStart, oldEnd] = this.indexRange;
2763
+ const [newStart, newEnd] = newRange;
2764
+ const mergedRange = [Math.min(oldStart, newStart), Math.max(oldEnd, newEnd)];
2765
+ this.indexRange = mergedRange;
2766
+ }
2767
+ };
2768
+ /**
2769
+ * A relational (`first`/`prev`/`next`/`last`) navigation link, relative to the
2770
+ * active page. Unlike {@link RealPaginationLink} these carry no ordinal index —
2771
+ * they are the only links available for cursor-based pagination, where pages are
2772
+ * chained purely by opaque relational links with no page number or total. They
2773
+ * are also available in numbered pagination as a convenience.
2774
+ *
2775
+ * ```gts
2776
+ * <EachLink @pages={{pages}} as |state|>
2777
+ * {{#if state.prev}}<button {{on "click" state.prev.setActive}}>Previous</button>{{/if}}
2778
+ * {{#if state.next}}<button {{on "click" state.next.setActive}}>Next</button>{{/if}}
2779
+ * </EachLink>
2780
+ * ```
2781
+ *
2782
+ * @since 5.9.0
2783
+ * @public
2784
+ * @hideconstructor
2785
+ */
2786
+ var RelationalPaginationLink = class {
2787
+ isReal = true;
2788
+ rel;
2789
+ url;
2790
+ /**
2791
+ * Whether this link points at the page that is already active — for example
2792
+ * the `first` link while the first page is being viewed. Useful for
2793
+ * disabling the control.
2794
+ */
2795
+ isCurrent;
2796
+ /** @internal */
2797
+ constructor(rel, url, isCurrent, loadPage) {
2798
+ this.rel = rel;
2799
+ this.url = url;
2800
+ this.isCurrent = isCurrent;
2801
+ this._loadPage = loadPage;
2802
+ }
2803
+ get text() {
2804
+ return this.rel;
2805
+ }
2806
+ /**
2807
+ * Loads this link's page and makes it the active page on the associated
2808
+ * {@link PaginationState}. It is a stable reference, so it is safe to pass
2809
+ * around as an "action" or "event" handler:
2810
+ *
2811
+ * ```gts
2812
+ * <button {{on "click" link.setActive}}>{{link.text}}</button>
2813
+ * ```
2814
+ */
2815
+ setActive = () => {
2816
+ return this._loadPage(this.url);
2817
+ };
2818
+ };
2819
+ /**
2820
+ * A member of {@link PaginationLinks.links}: either a numbered
2821
+ * {@link RealPaginationLink} or a {@link PlaceholderPaginationLink} standing in
2822
+ * for a gap. Discriminate with {@link RealPaginationLink.isReal | isReal}:
2823
+ *
2824
+ * ```ts
2825
+ * for (const link of links.links) {
2826
+ * if (link.isReal) {
2827
+ * // numbered link: link.index, link.setActive
2828
+ * } else {
2829
+ * // gap: link.indexRange
2830
+ * }
2831
+ * }
2832
+ * ```
2833
+ */
2834
+ /**
2835
+ * The reactive set of navigation links derived from a {@link PaginationState}.
2836
+ * Where `PaginationState` tracks which pages are loaded and which one is active,
2837
+ * `PaginationLinks` turns that page graph into the links a UI renders to move
2838
+ * between pages.
2839
+ *
2840
+ * It provides two kinds of link:
2841
+ *
2842
+ * - {@link links}: the numbered links, with {@link PlaceholderPaginationLink}
2843
+ * placeholders standing in for gaps of not-yet-loaded pages. Only numbered
2844
+ * collections (where the server exposes page numbers) produce these.
2845
+ * - {@link prev} and {@link next}: the relational links for the active page.
2846
+ * Available in both numbered and cursor-based pagination, and the only links a
2847
+ * cursor-based collection has.
2848
+ * - {@link first} and {@link last}: the relational links to the collection's
2849
+ * edges, when the response exposes them. Usually present on every page —
2850
+ * including the edge page itself, where the link's
2851
+ * {@link RelationalPaginationLink.isCurrent | isCurrent} is `true`.
2852
+ *
2853
+ * Every link updates as pages load and as the active page changes, since they
2854
+ * read straight from the state's shared page graph. To get the links for a
2855
+ * state, use {@link getPaginationLinks}.
2856
+ *
2857
+ * See also:
2858
+ * - {@link RealPaginationLink}
2859
+ * - {@link PlaceholderPaginationLink}
2860
+ * - {@link RelationalPaginationLink}
2861
+ *
2862
+ * @since 5.9.0
2863
+ * @public
2864
+ * @hideconstructor
2865
+ */
2866
+ var PaginationLinks = class {
2867
+ /** @internal */
2868
+ constructor(paginationState) {
2869
+ this.paginationState = paginationState;
2870
+ }
2871
+ /**
2872
+ * The relational `first` link of the collection, or `null` when the active
2873
+ * page's response did not expose one. Unlike {@link prev}/{@link next} it is
2874
+ * usually present on every page — including the first page itself, where the
2875
+ * link's {@link RelationalPaginationLink.isCurrent | isCurrent} is `true`
2876
+ * (useful for disabling the control).
2877
+ */
2878
+ get first() {
2879
+ const activePage = this.paginationState.activePage;
2880
+ const url = activePage?.firstLink;
2881
+ return url ? new RelationalPaginationLink("first", url, url === activePage?.selfLink, this.paginationState.loadPage) : null;
2882
+ }
2883
+ /**
2884
+ * The relational `prev` link for the active page, or `null` at the start of the
2885
+ * collection. Available in both numbered and cursor pagination.
2886
+ */
2887
+ static {
2888
+ decorateMethodV2(this.prototype, "first", [memoized]);
2889
+ }
2890
+ get prev() {
2891
+ const activePage = this.paginationState.activePage;
2892
+ const url = activePage?.prevLink;
2893
+ return url ? new RelationalPaginationLink("prev", url, url === activePage?.selfLink, this.paginationState.loadPage) : null;
2894
+ }
2895
+ /**
2896
+ * The relational `next` link for the active page, or `null` at the end of the
2897
+ * collection. Available in both numbered and cursor pagination.
2898
+ */
2899
+ static {
2900
+ decorateMethodV2(this.prototype, "prev", [memoized]);
2901
+ }
2902
+ get next() {
2903
+ const activePage = this.paginationState.activePage;
2904
+ const url = activePage?.nextLink;
2905
+ return url ? new RelationalPaginationLink("next", url, url === activePage?.selfLink, this.paginationState.loadPage) : null;
2906
+ }
2907
+ /**
2908
+ * The relational `last` link of the collection, or `null` when the active
2909
+ * page's response did not expose one. Mirror of {@link first} for the end of
2910
+ * the collection.
2911
+ */
2912
+ static {
2913
+ decorateMethodV2(this.prototype, "next", [memoized]);
2914
+ }
2915
+ get last() {
2916
+ const activePage = this.paginationState.activePage;
2917
+ const url = activePage?.lastLink;
2918
+ return url ? new RelationalPaginationLink("last", url, url === activePage?.selfLink, this.paginationState.loadPage) : null;
2919
+ }
2920
+ /**
2921
+ * The numbered links and placeholders, derived from the shared page graph.
2922
+ *
2923
+ * Only produced for numbered pagination (where the server exposes page numbers).
2924
+ * Cursor-based collections have no page numbers, so this is empty — use
2925
+ * {@link prev}/{@link next} for cursor navigation.
2926
+ */
2927
+ static {
2928
+ decorateMethodV2(this.prototype, "last", [memoized]);
2929
+ }
2930
+ get links() {
2931
+ const links = [];
2932
+ const cache = this.paginationState.paginationCache;
2933
+ if (!cache || !cache.isNumbered) return links;
2934
+ const { firstPage, totalPages } = cache;
2935
+ const activeIndex = this.paginationState.activePage?.pageNumber ?? 0;
2936
+ if (firstPage) {
2937
+ let previousPage = null;
2938
+ let currentPage = firstPage;
2939
+ while (currentPage) {
2940
+ if (previousPage && currentPage.pageNumber - previousPage.pageNumber > 1) links.push(new PlaceholderPaginationLink([previousPage.pageNumber + 1, currentPage.pageNumber - 1], activeIndex));
2941
+ links.push(new RealPaginationLink(currentPage.selfLink ?? "", currentPage.pageNumber, activeIndex, this.paginationState.loadPage));
2942
+ previousPage = currentPage;
2943
+ currentPage = currentPage.after;
2944
+ }
2945
+ if (previousPage && previousPage.pageNumber < totalPages) links.push(new PlaceholderPaginationLink([previousPage.pageNumber + 1, totalPages], activeIndex));
2946
+ }
2947
+ return links;
2948
+ }
2949
+ static {
2950
+ decorateMethodV2(this.prototype, "links", [memoized]);
2951
+ }
2952
+ };
2953
+ /**
2954
+ * Get the {@link PaginationLinks} for a given {@link PaginationState}. Returns
2955
+ * the same instance for the same state, so repeated calls (for example a
2956
+ * `<Paginate />` component and a separate links component reading the same state)
2957
+ * share one set of links. Keyed by state identity, the same way
2958
+ * {@link getPaginationState} is keyed by request and {@link getRequestState} by
2959
+ * future.
2960
+ *
2961
+ * ```ts
2962
+ * const links = getPaginationLinks(paginationState);
2963
+ *
2964
+ * for (const link of links.links) {
2965
+ * if (link.isReal) {
2966
+ * // render a numbered link, using link.setActive as the click handler
2967
+ * } else {
2968
+ * // render an ellipsis for the gap link.indexRange covers
2969
+ * }
2970
+ * }
2971
+ * ```
2972
+ *
2973
+ * @since 5.9.0
2974
+ * @public
2975
+ */
2976
+ function getPaginationLinks(state) {
2977
+ let links = PaginationLinksCache.get(state);
2978
+ if (!links) {
2979
+ links = new PaginationLinks(state);
2980
+ PaginationLinksCache.set(state, links);
2981
+ }
2982
+ return links;
2983
+ }
2984
+
2985
+ //#endregion
2986
+ //#region src/signals/pagination-subscription.ts
2987
+ /**
2988
+ * The content features available in both pagination modes: the state and
2989
+ * controls of the initial request.
2990
+ */
2991
+ /**
2992
+ * The content features yielded in `'paged'` mode: navigation happens by
2993
+ * loading a specific page.
2994
+ */
2995
+ /**
2996
+ * The content features yielded in `'infinite'` mode: navigation happens by
2997
+ * extending the loaded run at either end.
2998
+ */
2999
+ /**
3000
+ * The full set of content features a {@link PaginationSubscription} builds —
3001
+ * both modes' surfaces. The `<Paginate />` component narrows this to one mode
3002
+ * via {@link PaginationContentFeaturesFor} before yielding.
3003
+ */
3004
+ /**
3005
+ * Resolves a {@link PaginateMode} to the content features it exposes. Mirror of
3006
+ * {@link PaginationStateFor}.
3007
+ */
3008
+ /**
3009
+ * Lifecycle glue for the `<Paginate />` component. Owns the initial
3010
+ * {@link RequestSubscription} (loading/error state, autorefresh, disposal) and
3011
+ * the per-component {@link PaginationState} that it hands to the component.
3012
+ *
3013
+ * @since 5.9.0
3014
+ * @public
3015
+ * @hideconstructor
3016
+ */
3017
+ var PaginationSubscription = class {
3018
+ /** @internal */
3019
+ /** @internal */
3020
+ /** @internal */
3021
+ /**
3022
+ * The Store this subscription subscribes to or the RequestManager
3023
+ * which issues this request.
3024
+ */
3025
+ /**
3026
+ * The wrapped {@link RequestSubscription} monitoring the initial request.
3027
+ * Created eagerly: constructing one consumes reactive state (its own
3028
+ * signals), so building it lazily inside a tracked getter would cause the
3029
+ * getter to invalidate — and the subscription to be recreated, losing its
3030
+ * reloaded request — whenever `retry`/`reload` runs.
3031
+ *
3032
+ * @internal
3033
+ */
3034
+ /**
3035
+ * The first request this subscription saw — the one that keys the
3036
+ * {@link PaginationState} until a navigation resolves to a different
3037
+ * collection. Plain (untracked) because it is written during the first
3038
+ * computation of {@link paginationState}.
3039
+ *
3040
+ * @internal
3041
+ */
3042
+ /**
3043
+ * The request a resolved navigation swapped the {@link PaginationState} to,
3044
+ * when the navigation turned out to target a different collection. A signal:
3045
+ * writing it (always outside of render, from {@link _resolveNavigation})
3046
+ * invalidates {@link paginationState} so the fresh state takes over.
3047
+ *
3048
+ * @internal
3049
+ */
3050
+ /**
3051
+ * The changed request currently being resolved by {@link _resolveNavigation},
3052
+ * both to avoid kicking the same navigation twice and as the latest-wins
3053
+ * guard when several changes race. Untracked bookkeeping.
3054
+ *
3055
+ * @internal
3056
+ */
3057
+ constructor(store, args) {
3058
+ this._args = args;
3059
+ this.store = store;
3060
+ this.isDestroyed = false;
3061
+ this._seedRequest = null;
3062
+ this._navTarget = null;
3063
+ this[DISPOSE] = _DISPOSE$1;
3064
+ this._requestSubscription = createRequestSubscription(store, args);
3065
+ }
3066
+ /**
3067
+ * The per-component pagination state yielded to the component.
3068
+ *
3069
+ * Keyed to the request that started the collection, not the current
3070
+ * `@request` arg: when the arg changes, the existing state keeps rendering
3071
+ * while {@link _resolveNavigation} resolves the new request in the
3072
+ * background. A request that resolves to a page of the same collection is
3073
+ * adopted into this state as the new active page (route-driven navigation,
3074
+ * e.g. the browser back button); one that resolves to a different
3075
+ * collection swaps in a fresh state (a true reset).
3076
+ *
3077
+ * A background `refresh` does not swap the request, so the pagination
3078
+ * state is stable across refreshes.
3079
+ */
3080
+ get paginationState() {
3081
+ const request = this._requestSubscription.request;
3082
+ const active = this._navRequest ?? this._seedRequest;
3083
+ if (!active) {
3084
+ this._seedRequest = request;
3085
+ return getPaginationState(request, this._args.pageHints);
3086
+ }
3087
+ if (request !== active && request !== this._navTarget) {
3088
+ this._navTarget = request;
3089
+ this._resolveNavigation(request);
3090
+ }
3091
+ return getPaginationState(active, this._args.pageHints);
3092
+ }
3093
+ /**
3094
+ * Resolves a changed `@request` arg against the current collection via
3095
+ * {@link PaginationState.adoptPage}: a request that resolves to a page of
3096
+ * the same collection is adopted into the existing state; one that resolves
3097
+ * to a different collection (or arrives before a collection is loaded) swaps
3098
+ * the state for a fresh one keyed to this request.
3099
+ *
3100
+ * A rejected request changes nothing here — the request subscription
3101
+ * already surfaces the failure (error/cancelled states), and the existing
3102
+ * pagination state is kept for recovery. The request is awaited before
3103
+ * `adoptPage` so that rejection and the latest-wins guard are handled
3104
+ * before anything is adopted.
3105
+ *
3106
+ * @internal
3107
+ */
3108
+ static {
3109
+ decorateMethodV2(this.prototype, "paginationState", [memoized]);
3110
+ }
3111
+ async _resolveNavigation(request) {
3112
+ try {
3113
+ await request;
3114
+ } catch {
3115
+ return;
3116
+ }
3117
+ if (this.isDestroyed || this._navTarget !== request) return;
3118
+ const adopted = await this.paginationState.adoptPage(request);
3119
+ if (this.isDestroyed || this._navTarget !== request) return;
3120
+ if (adopted === null) this._navRequest = request;
3121
+ }
3122
+ /**
3123
+ * Whether there is no request or query to monitor, so the component has
3124
+ * nothing to load.
3125
+ */
3126
+ get isIdle() {
3127
+ return this._requestSubscription.isIdle;
3128
+ }
3129
+ /**
3130
+ * Whether the collection is still blocking-loading: no {@link PaginationState}
3131
+ * has finished setting up yet. Only the very first page load (or the reset
3132
+ * to a different collection) blocks here — extending the collection with
3133
+ * `loadNext`/`loadPrev` does not, and neither does a changed `@request` arg
3134
+ * while a collection is already on screen (that is {@link isNavigating}).
3135
+ *
3136
+ * Remains `true` for the moment between the request resolving and the
3137
+ * {@link paginationState} finishing its setup from the response, so that
3138
+ * {@link isSuccess} consumers never see a success state with an empty
3139
+ * pagination surface.
3140
+ */
3141
+ static {
3142
+ decorateMethodV2(this.prototype, "isIdle", [memoized]);
3143
+ }
3144
+ get isLoading() {
3145
+ const { reqState } = this._requestSubscription;
3146
+ return this.paginationState.paginationCache === null && (reqState.isLoading || reqState.isSuccess);
3147
+ }
3148
+ /**
3149
+ * Whether a changed `@request` arg is resolving while a collection is
3150
+ * already on screen — route-driven navigation, e.g. the browser back
3151
+ * button. The content stays rendered (see {@link isSuccess}); consumers can
3152
+ * use this to show a lightweight navigation indicator, the same way a
3153
+ * `loadPage` call surfaces through the active page's request state.
3154
+ */
3155
+ static {
3156
+ decorateMethodV2(this.prototype, "isLoading", [memoized]);
3157
+ }
3158
+ get isNavigating() {
3159
+ return this.paginationState.paginationCache !== null && this._requestSubscription.reqState.isLoading;
3160
+ }
3161
+ /**
3162
+ * The {@link RequestLoadingState} for the initial request, for building UIs
3163
+ * that respond to download progress.
3164
+ */
3165
+ static {
3166
+ decorateMethodV2(this.prototype, "isNavigating", [memoized]);
3167
+ }
3168
+ get loadingState() {
3169
+ return this._requestSubscription.reqState.loadingState;
3170
+ }
3171
+ /**
3172
+ * Whether the component has a set-up {@link paginationState} to render and
3173
+ * the current request did not fail. Stays `true` while a changed `@request`
3174
+ * arg resolves ({@link isNavigating}), so the existing content keeps
3175
+ * rendering instead of falling back to a blocking loading state.
3176
+ */
3177
+ static {
3178
+ decorateMethodV2(this.prototype, "loadingState", [memoized]);
3179
+ }
3180
+ get isSuccess() {
3181
+ const { reqState } = this._requestSubscription;
3182
+ return this.paginationState.paginationCache !== null && !reqState.isError && !reqState.isCancelled;
3183
+ }
3184
+ /**
3185
+ * Whether the initial request was cancelled (aborted).
3186
+ */
3187
+ static {
3188
+ decorateMethodV2(this.prototype, "isSuccess", [memoized]);
3189
+ }
3190
+ get isCancelled() {
3191
+ return this._requestSubscription.reqState.isCancelled;
3192
+ }
3193
+ /**
3194
+ * Whether the initial request rejected with an error.
3195
+ */
3196
+ static {
3197
+ decorateMethodV2(this.prototype, "isCancelled", [memoized]);
3198
+ }
3199
+ get isError() {
3200
+ return this._requestSubscription.reqState.isError;
3201
+ }
3202
+ /**
3203
+ * The error the initial request rejected with, or `null` if it did not reject.
3204
+ */
3205
+ static {
3206
+ decorateMethodV2(this.prototype, "isError", [memoized]);
3207
+ }
3208
+ get reason() {
3209
+ return this._requestSubscription.reqState.reason;
3210
+ }
3211
+ /**
3212
+ * Error features to yield to the error slot of a component
3213
+ */
3214
+ static {
3215
+ decorateMethodV2(this.prototype, "reason", [memoized]);
3216
+ }
3217
+ get errorFeatures() {
3218
+ return {
3219
+ isHidden: this._requestSubscription.isHidden,
3220
+ isOnline: this._requestSubscription.isOnline,
3221
+ retry: this._requestSubscription.retry
3222
+ };
3223
+ }
3224
+ /**
3225
+ * Content features to yield to the content slot of a component
3226
+ */
3227
+ static {
3228
+ decorateMethodV2(this.prototype, "errorFeatures", [memoized]);
3229
+ }
3230
+ get contentFeatures() {
3231
+ const contentFeatures = this._requestSubscription.contentFeatures;
3232
+ const { paginationState } = this;
3233
+ const feat = {
3234
+ ...contentFeatures,
3235
+ isNavigating: this.isNavigating,
3236
+ loadPrev: paginationState.loadPrev,
3237
+ loadNext: paginationState.loadNext,
3238
+ loadPage: paginationState.loadPage
3239
+ };
3240
+ if (feat.isRefreshing) feat.abort = () => {
3241
+ contentFeatures.latestRequest?.abort();
3242
+ };
3243
+ return feat;
3244
+ }
3245
+ /**
3246
+ * The initial request `Future` this subscription is monitoring, i.e. the first
3247
+ * page load. This is the future the {@link paginationState} is built from.
3248
+ *
3249
+ * @internal
3250
+ */
3251
+ static {
3252
+ decorateMethodV2(this.prototype, "contentFeatures", [memoized]);
3253
+ }
3254
+ get request() {
3255
+ return this._requestSubscription.request;
3256
+ }
3257
+ static {
3258
+ decorateMethodV2(this.prototype, "request", [memoized]);
3259
+ }
3260
+ };
3261
+ defineSignal(PaginationSubscription.prototype, "_navRequest", null);
3262
+ /**
3263
+ * Creates the {@link PaginationSubscription} a `<Paginate />` component uses to
3264
+ * manage its request lifecycle and pagination state. Pass the result back into
3265
+ * the component via `@subscription` to manage the lifecycle externally.
3266
+ *
3267
+ * ```ts
3268
+ * const subscription = createPaginationSubscription(store, { request });
3269
+ *
3270
+ * subscription.paginationState; // the per-component PaginationState
3271
+ * subscription[DISPOSE](); // tear down when the owning component unmounts
3272
+ * ```
3273
+ *
3274
+ * @since 5.9.0
3275
+ * @public
3276
+ */
3277
+ function createPaginationSubscription(store, args) {
3278
+ return new PaginationSubscription(store, args);
3279
+ }
3280
+ function upgradeSubscription$1(sub) {
3281
+ return sub;
3282
+ }
3283
+ function _DISPOSE$1() {
3284
+ const self = upgradeSubscription$1(this);
3285
+ self.isDestroyed = true;
3286
+ self._requestSubscription?.[DISPOSE]?.();
3287
+ }
3288
+
3289
+ //#endregion
3290
+ //#region src/signals/pagination-links-subscription.ts
3291
+ /**
3292
+ * The framework-agnostic core of a pagination links component (for example the
3293
+ * `<EachLink />` component of `@warp-drive/ember`): it owns the component
3294
+ * lifecycle, while the links themselves live on the {@link PaginationLinks}
3295
+ * it exposes.
3296
+ *
3297
+ * Given the {@link PagedPaginationState} a `<Paginate />` component is driving,
3298
+ * {@link paginationLinks} derives that state's `PaginationLinks` — the numbered
3299
+ * links (with placeholders for gaps) and the relational
3300
+ * `first`/`prev`/`next`/`last` links a component yields for the consumer to
3301
+ * render. All of them read from the same shared page graph as the
3302
+ * `<Paginate />` component, so they stay in sync as pages load and the active
3303
+ * page changes.
3304
+ *
3305
+ * @since 5.9.0
3306
+ * @public
3307
+ * @hideconstructor
3308
+ */
3309
+ var PaginationLinksSubscription = class {
3310
+ /** @internal */
3311
+ /** @internal */
3312
+ constructor(args) {
3313
+ this._args = args;
3314
+ this.isDestroyed = false;
3315
+ this[DISPOSE] = _DISPOSE;
3316
+ }
3317
+ /**
3318
+ * The {@link PaginationLinks} derived from the {@link PagedPaginationState}
3319
+ * passed as an arg — the surface a links component yields to its consumer:
3320
+ * the numbered {@link PaginationLinks.links | links} (empty for cursor-based
3321
+ * collections) and the relational {@link PaginationLinks.first | first}/
3322
+ * {@link PaginationLinks.prev | prev}/{@link PaginationLinks.next | next}/
3323
+ * {@link PaginationLinks.last | last} links.
3324
+ *
3325
+ * Recomputes when the `pages` arg changes, so a component whose pagination
3326
+ * resets to a different collection derives fresh links automatically.
3327
+ */
3328
+ get paginationLinks() {
3329
+ return getPaginationLinks(this._args.pages);
3330
+ }
3331
+ static {
3332
+ decorateMethodV2(this.prototype, "paginationLinks", [memoized]);
3333
+ }
3334
+ };
3335
+ /**
3336
+ * Creates the {@link PaginationLinksSubscription} a links component (such as
3337
+ * `<EachLink />`) uses to derive its links from a {@link PagedPaginationState}.
3338
+ *
3339
+ * ```ts
3340
+ * const subscription = createPaginationLinksSubscription({ pages: paginationState });
3341
+ *
3342
+ * subscription.paginationLinks; // the derived PaginationLinks
3343
+ * subscription[DISPOSE](); // tear down when the owning component unmounts
3344
+ * ```
3345
+ *
3346
+ * @since 5.9.0
3347
+ * @public
3348
+ */
3349
+ function createPaginationLinksSubscription(args) {
3350
+ return new PaginationLinksSubscription(args);
3351
+ }
3352
+ function upgradeSubscription(sub) {
3353
+ return sub;
3354
+ }
3355
+ function _DISPOSE() {
3356
+ const self = upgradeSubscription(this);
3357
+ self.isDestroyed = true;
3358
+ }
3359
+
3360
+ //#endregion
3361
+ //#region src/signals/promise-state.ts
3362
+ const PromiseCache = /* @__PURE__ */ new WeakMap();
3363
+ /**
3364
+ * The state of a promise in the "pending"
3365
+ * state. This is the default initial state.
3366
+ *
3367
+ */
3368
+ /**
3369
+ * The state of a promise in the "fulfilled" state.
3370
+ * This is the state of a promise that has resolved
3371
+ * successfully.
3372
+ *
3373
+ */
3374
+ /**
3375
+ * The state of a promise in the "rejected" state.
3376
+ * This is the state of a promise that has rejected
3377
+ * with an error.
3378
+ *
3379
+ */
3380
+ /**
3381
+ * The state of a promise. This is the type that is returned
3382
+ * from `getPromiseState`.
3383
+ *
3384
+ * See also:
3385
+ * - {@link PendingPromise}
3386
+ * - {@link ResolvedPromise}
3387
+ * - {@link RejectedPromise}
3388
+ *
3389
+ */
3390
+ const PromiseStateProto = {};
3391
+ defineSignal(PromiseStateProto, "reason", null);
3392
+ defineSignal(PromiseStateProto, "value", null);
3393
+ defineSignal(PromiseStateProto, "result", null);
3394
+ defineSignal(PromiseStateProto, "error", null);
3395
+ defineSignal(PromiseStateProto, "status", "pending");
3396
+ defineSignal(PromiseStateProto, "isPending", true);
3397
+ defineSignal(PromiseStateProto, "isLoading", true);
3398
+ defineSignal(PromiseStateProto, "isSuccess", false);
3399
+ defineSignal(PromiseStateProto, "isError", false);
3400
+ function createPromiseState(promise) {
3401
+ const state = getPromiseResult(promise);
3402
+ const promiseState = Object.create(PromiseStateProto);
3403
+ if (state) {
3404
+ if (state.isError) {
3405
+ promiseState.error = state.result;
3406
+ promiseState.reason = state.result;
3407
+ promiseState.status = "rejected";
3408
+ promiseState.isError = true;
3409
+ promiseState.isPending = false;
3410
+ promiseState.isLoading = false;
3411
+ } else {
3412
+ promiseState.result = state.result;
3413
+ promiseState.value = state.result;
3414
+ promiseState.status = "fulfilled";
3415
+ promiseState.isSuccess = true;
3416
+ promiseState.isPending = false;
3417
+ promiseState.isLoading = false;
3418
+ }
3419
+ } else promise.then((result) => {
3420
+ setPromiseResult(promise, {
3421
+ isError: false,
3422
+ result
3423
+ });
3424
+ promiseState.result = result;
3425
+ promiseState.value = result;
3426
+ promiseState.status = "fulfilled";
3427
+ promiseState.isSuccess = true;
3428
+ promiseState.isPending = false;
3429
+ promiseState.isLoading = false;
3430
+ }, (error) => {
3431
+ setPromiseResult(promise, {
3432
+ isError: true,
3433
+ result: error
3434
+ });
3435
+ promiseState.error = error;
3436
+ promiseState.reason = error;
3437
+ promiseState.status = "rejected";
3438
+ promiseState.isError = true;
3439
+ promiseState.isPending = false;
3440
+ promiseState.isLoading = false;
3441
+ });
3442
+ return promiseState;
3443
+ }
3444
+ const LegacyPromiseProxy = Symbol.for("LegacyPromiseProxy");
3445
+ function isLegacyAwaitable(promise) {
3446
+ return LegacyPromiseProxy in promise && "promise" in promise && promise[LegacyPromiseProxy] === true;
3447
+ }
3448
+ function getPromise(promise) {
3449
+ return isLegacyAwaitable(promise) ? promise.promise : promise;
3450
+ }
3451
+ /**
3452
+ * Returns a reactive state-machine for the provided promise or awaitable.
3453
+ *
3454
+ * Repeat calls to `getPromiseState` with the same promise will return the same state object
3455
+ * making is safe and easy to use in templates and JavaScript code to produce reactive
3456
+ * behaviors around promises.
3457
+ *
3458
+ * `getPromiseState` can be used in both JavaScript and Template contexts.
3459
+ *
3460
+ * ```ts
3461
+ * import { getPromiseState } from '@warp-drive/ember';
3462
+ *
3463
+ * const state = getPromiseState(promise);
3464
+ * ```
3465
+ *
3466
+ * For instance, we could write a getter on a component that updates whenever
3467
+ * the promise state advances or the promise changes, by combining the function
3468
+ * with the use of `@cached`
3469
+ *
3470
+ * ```ts
3471
+ * class Component {
3472
+ * @cached
3473
+ * get title() {
3474
+ * const state = getPromiseState(this.args.request);
3475
+ * if (state.isPending) {
3476
+ * return 'loading...';
3477
+ * }
3478
+ * if (state.isError) { return null; }
3479
+ * return state.result.title;
3480
+ * }
3481
+ * }
3482
+ * ```
3483
+ *
3484
+ * Or in a template as a helper:
3485
+ *
3486
+ * ```gjs
3487
+ * import { getPromiseState } from '@warp-drive/ember';
3488
+ *
3489
+ * <template>
3490
+ * {{#let (getPromiseState @request) as |state|}}
3491
+ * {{#if state.isPending}} <Spinner />
3492
+ * {{else if state.isError}} <ErrorForm @error={{state.error}} />
3493
+ * {{else}}
3494
+ * <h1>{{state.result.title}}</h1>
3495
+ * {{/if}}
3496
+ * {{/let}}
3497
+ * </template>
3498
+ * ```
3499
+ *
3500
+ * If looking to use in a template, consider also the `<Await />` component.
3501
+ *
3502
+ * See also {@link PromiseState}
3503
+ */
3504
+ function getPromiseState(promise) {
3505
+ ((test) => {
3506
+ if (!test) throw new Error(`getPromiseState expects to be called with a promise: called with ${String(promise)}`);
3507
+ })(promise);
3508
+ const _promise = getPromise(promise);
3509
+ let state = PromiseCache.get(_promise);
3510
+ if (!state) {
3511
+ state = createPromiseState(_promise);
3512
+ PromiseCache.set(_promise, state);
3513
+ }
3514
+ return state;
3515
+ }
3516
+
3517
+ //#endregion
3518
+ export { ARRAY_SIGNAL as A, createInternalMemo as C, notifyInternalSignal as D, makeInitializer as E, setupSignals as M, waitFor as N, peekInternalSignal as O, willSyncFlushWatchers as P, consumeInternalSignal as S, getOrCreateInternalSignal as T, entangleSignal as _, getPaginationState as a, signal as b, getPaginationCache as c, getRequestState as d, createSignalDescriptor as f, entangleInitiallyStaleSignal as g, defineSignal as h, getPaginationLinks as i, OBJECT_SIGNAL as j, withSignalStore as k, DISPOSE as l, defineNonEnumerableSignal as m, createPaginationLinksSubscription as n, clearPaginationCache as o, defineGate as p, createPaginationSubscription as r, defaultPageHints as s, getPromiseState as t, createRequestSubscription as u, gate as v, createInternalSignal as w, Signals as x, memoized as y };
3519
+ //# sourceMappingURL=-private-pNQae3qH.js.map