@askrjs/askr 0.0.49 → 0.0.51

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 (238) hide show
  1. package/dist/bench/components/benchmark-table.js.map +1 -1
  2. package/dist/benchmark.js +5 -4
  3. package/dist/benchmark.js.map +1 -1
  4. package/dist/bin/askr-ssg.d.ts.map +1 -1
  5. package/dist/bin/askr-ssg.js.map +1 -1
  6. package/dist/boot/hydration.js.map +1 -1
  7. package/dist/boot/index.js +2 -1
  8. package/dist/boot/index.js.map +1 -1
  9. package/dist/boot/root-lifecycle.d.ts.map +1 -1
  10. package/dist/boot/root-lifecycle.js +4 -4
  11. package/dist/boot/root-lifecycle.js.map +1 -1
  12. package/dist/boot/route-startup.js.map +1 -1
  13. package/dist/common/error-boundary.d.ts +16 -0
  14. package/dist/common/error-boundary.d.ts.map +1 -0
  15. package/dist/common/invariant.js +17 -0
  16. package/dist/common/invariant.js.map +1 -0
  17. package/dist/common/jsx.d.ts +6 -2
  18. package/dist/common/jsx.d.ts.map +1 -1
  19. package/dist/common/jsx.js.map +1 -1
  20. package/dist/{dev → common}/logger.js +5 -6
  21. package/dist/common/logger.js.map +1 -0
  22. package/dist/common/vnode.d.ts +2 -2
  23. package/dist/common/vnode.d.ts.map +1 -1
  24. package/dist/common/vnode.js.map +1 -1
  25. package/dist/components/error-boundary.d.ts +2 -15
  26. package/dist/components/error-boundary.d.ts.map +1 -1
  27. package/dist/components/error-boundary.js +2 -74
  28. package/dist/components/error-boundary.js.map +1 -1
  29. package/dist/components/index.d.ts +2 -1
  30. package/dist/components/link.js +2 -0
  31. package/dist/components/link.js.map +1 -1
  32. package/dist/control/case.d.ts.map +1 -1
  33. package/dist/control/case.js +1 -0
  34. package/dist/control/case.js.map +1 -1
  35. package/dist/control/for.d.ts +3 -3
  36. package/dist/control/for.d.ts.map +1 -1
  37. package/dist/control/for.js +2 -2
  38. package/dist/control/for.js.map +1 -1
  39. package/dist/control/show.js +1 -0
  40. package/dist/control/show.js.map +1 -1
  41. package/dist/data/data-runtime.js.map +1 -1
  42. package/dist/data/invalidation.js +2 -2
  43. package/dist/data/invalidation.js.map +1 -1
  44. package/dist/data/mutation-cell.d.ts.map +1 -1
  45. package/dist/data/mutation-cell.js +1 -1
  46. package/dist/data/mutation-cell.js.map +1 -1
  47. package/dist/data/query-cell.js +2 -2
  48. package/dist/data/query-cell.js.map +1 -1
  49. package/dist/data/shared.js +1 -0
  50. package/dist/data/shared.js.map +1 -1
  51. package/dist/data/testing.js +2 -0
  52. package/dist/foundations/index.d.ts +1 -1
  53. package/dist/foundations/index.js +1 -1
  54. package/dist/foundations/state/controllable.d.ts +0 -1
  55. package/dist/foundations/state/controllable.d.ts.map +1 -1
  56. package/dist/foundations/state/controllable.js +1 -0
  57. package/dist/foundations/state/controllable.js.map +1 -1
  58. package/dist/foundations/structures/index.d.ts +1 -1
  59. package/dist/foundations/structures/index.js +2 -1
  60. package/dist/foundations/structures/portal.d.ts +2 -24
  61. package/dist/foundations/structures/portal.js +3 -187
  62. package/dist/fx/fx.js +2 -2
  63. package/dist/fx/fx.js.map +1 -1
  64. package/dist/fx/index.js +1 -0
  65. package/dist/index.d.ts +3 -3
  66. package/dist/index.js +4 -4
  67. package/dist/index.js.map +1 -1
  68. package/dist/jsx/index.d.ts +1 -1
  69. package/dist/jsx/types.d.ts +2 -2
  70. package/dist/jsx-dev-runtime.d.ts +2 -2
  71. package/dist/jsx-dev-runtime.d.ts.map +1 -1
  72. package/dist/jsx-dev-runtime.js +1 -0
  73. package/dist/jsx-dev-runtime.js.map +1 -1
  74. package/dist/jsx-runtime.d.ts +2 -2
  75. package/dist/jsx-runtime.d.ts.map +1 -1
  76. package/dist/jsx-runtime.js +1 -0
  77. package/dist/jsx-runtime.js.map +1 -1
  78. package/dist/jsx-runtime2.d.ts +1 -1
  79. package/dist/renderer/attributes.js +1 -0
  80. package/dist/renderer/attributes.js.map +1 -1
  81. package/dist/renderer/boundaries.js +5 -5
  82. package/dist/renderer/boundaries.js.map +1 -1
  83. package/dist/renderer/child-shape.js +2 -2
  84. package/dist/renderer/child-shape.js.map +1 -1
  85. package/dist/renderer/children-fastpath.js +149 -0
  86. package/dist/renderer/children-fastpath.js.map +1 -0
  87. package/dist/renderer/children.js +3 -138
  88. package/dist/renderer/children.js.map +1 -1
  89. package/dist/renderer/cleanup.js +2 -2
  90. package/dist/renderer/cleanup.js.map +1 -1
  91. package/dist/renderer/component-host-cleanup.js +1 -1
  92. package/dist/renderer/component-host-cleanup.js.map +1 -1
  93. package/dist/renderer/component-host-instances.js +1 -1
  94. package/dist/renderer/component-host-instances.js.map +1 -1
  95. package/dist/renderer/component-host.js +1 -1
  96. package/dist/renderer/component-host.js.map +1 -1
  97. package/dist/renderer/dom-host.js.map +1 -1
  98. package/dist/renderer/dom-internal.js +5 -4
  99. package/dist/renderer/dom-internal.js.map +1 -1
  100. package/dist/renderer/dom.js +2 -1
  101. package/dist/renderer/element-children.js.map +1 -1
  102. package/dist/renderer/error-boundary-dom.js +51 -2
  103. package/dist/renderer/error-boundary-dom.js.map +1 -1
  104. package/dist/renderer/evaluate-reconcile.js +6 -5
  105. package/dist/renderer/evaluate-reconcile.js.map +1 -1
  106. package/dist/renderer/evaluate.js.map +1 -1
  107. package/dist/renderer/fastpath.js +3 -2
  108. package/dist/renderer/fastpath.js.map +1 -1
  109. package/dist/renderer/for-commit-dom-map.js.map +1 -1
  110. package/dist/renderer/for-commit-removal.js +2 -2
  111. package/dist/renderer/for-commit-removal.js.map +1 -1
  112. package/dist/renderer/for-commit-reorder.js +2 -2
  113. package/dist/renderer/for-commit-reorder.js.map +1 -1
  114. package/dist/renderer/for-commit.js +3 -3
  115. package/dist/renderer/for-commit.js.map +1 -1
  116. package/dist/renderer/index.js +3 -1
  117. package/dist/renderer/index.js.map +1 -1
  118. package/dist/renderer/prop-bindings.js +4 -4
  119. package/dist/renderer/prop-bindings.js.map +1 -1
  120. package/dist/renderer/reactive-child-dom.js.map +1 -1
  121. package/dist/renderer/reactive-children.js +4 -4
  122. package/dist/renderer/reactive-children.js.map +1 -1
  123. package/dist/renderer/reconcile-fastpaths.js +2 -1
  124. package/dist/renderer/reconcile-fastpaths.js.map +1 -1
  125. package/dist/renderer/reconcile-resolution.js +3 -3
  126. package/dist/renderer/reconcile-resolution.js.map +1 -1
  127. package/dist/renderer/retained-element-rollback.js +2 -1
  128. package/dist/renderer/retained-element-rollback.js.map +1 -1
  129. package/dist/renderer/stable-patch.js +2 -3
  130. package/dist/renderer/stable-patch.js.map +1 -1
  131. package/dist/renderer/utils.js +2 -1
  132. package/dist/renderer/utils.js.map +1 -1
  133. package/dist/resources/index.js +1 -2
  134. package/dist/router/activity.d.ts.map +1 -1
  135. package/dist/router/activity.js +20 -22
  136. package/dist/router/activity.js.map +1 -1
  137. package/dist/router/authoring.js +1 -1
  138. package/dist/router/authoring.js.map +1 -1
  139. package/dist/router/index.d.ts +1 -1
  140. package/dist/router/navigate.js +1 -1
  141. package/dist/router/navigate.js.map +1 -1
  142. package/dist/router/navigation-registry.js +1 -1
  143. package/dist/router/navigation-registry.js.map +1 -1
  144. package/dist/router/navigation-targets.d.ts.map +1 -1
  145. package/dist/router/navigation-targets.js +7 -5
  146. package/dist/router/navigation-targets.js.map +1 -1
  147. package/dist/router/rendering.js +1 -0
  148. package/dist/router/rendering.js.map +1 -1
  149. package/dist/router/resolution.d.ts +1 -14
  150. package/dist/router/resolution.d.ts.map +1 -1
  151. package/dist/router/resolution.js +6 -173
  152. package/dist/router/resolution.js.map +1 -1
  153. package/dist/router/route-matching.d.ts +20 -0
  154. package/dist/router/route-matching.d.ts.map +1 -0
  155. package/dist/router/route-matching.js +175 -0
  156. package/dist/router/route-matching.js.map +1 -0
  157. package/dist/router/route.js +4 -2
  158. package/dist/router/testing.js +4 -0
  159. package/dist/runtime/access.d.ts +20 -0
  160. package/dist/runtime/access.d.ts.map +1 -0
  161. package/dist/runtime/component-cleanup.js +1 -1
  162. package/dist/runtime/component-cleanup.js.map +1 -1
  163. package/dist/runtime/component-commit.js +1 -1
  164. package/dist/runtime/component-commit.js.map +1 -1
  165. package/dist/runtime/component-internal.d.ts +1 -1
  166. package/dist/runtime/component-internal.js +1 -1
  167. package/dist/runtime/component-internal.js.map +1 -1
  168. package/dist/runtime/component-lifecycle.d.ts +1 -1
  169. package/dist/runtime/component-lifecycle.js +1 -1
  170. package/dist/runtime/component-lifecycle.js.map +1 -1
  171. package/dist/runtime/component-scope.d.ts +1 -1
  172. package/dist/runtime/dev-namespace.d.ts +31 -0
  173. package/dist/runtime/dev-namespace.d.ts.map +1 -0
  174. package/dist/runtime/error-boundary.d.ts +5 -0
  175. package/dist/runtime/error-boundary.d.ts.map +1 -0
  176. package/dist/runtime/error-boundary.js +31 -0
  177. package/dist/runtime/error-boundary.js.map +1 -0
  178. package/dist/runtime/events.d.ts +58 -0
  179. package/dist/runtime/events.d.ts.map +1 -0
  180. package/dist/runtime/events.js +1 -1
  181. package/dist/runtime/events.js.map +1 -1
  182. package/dist/runtime/execution-model.d.ts +7 -0
  183. package/dist/runtime/execution-model.d.ts.map +1 -0
  184. package/dist/runtime/fastlane.d.ts +34 -0
  185. package/dist/runtime/fastlane.d.ts.map +1 -0
  186. package/dist/runtime/for-internal.d.ts +5 -5
  187. package/dist/runtime/for-internal.d.ts.map +1 -1
  188. package/dist/runtime/for-internal.js.map +1 -1
  189. package/dist/runtime/for-signals.d.ts +1 -1
  190. package/dist/runtime/for-signals.d.ts.map +1 -1
  191. package/dist/runtime/for-signals.js +1 -1
  192. package/dist/runtime/for-signals.js.map +1 -1
  193. package/dist/runtime/for-types.d.ts +9 -0
  194. package/dist/runtime/for-types.d.ts.map +1 -0
  195. package/dist/runtime/index.d.ts +24 -0
  196. package/dist/runtime/index.js +31 -0
  197. package/dist/runtime/perf-metrics.d.ts +26 -0
  198. package/dist/runtime/perf-metrics.d.ts.map +1 -0
  199. package/dist/runtime/portal.d.ts +22 -0
  200. package/dist/runtime/portal.d.ts.map +1 -0
  201. package/dist/runtime/portal.js +213 -0
  202. package/dist/runtime/portal.js.map +1 -0
  203. package/dist/runtime/resource-cell.js +1 -1
  204. package/dist/runtime/resource-cell.js.map +1 -1
  205. package/dist/runtime/resource-operation.js +1 -1
  206. package/dist/runtime/runtime.d.ts +1 -1
  207. package/dist/runtime/scheduler.js +2 -2
  208. package/dist/runtime/scheduler.js.map +1 -1
  209. package/dist/runtime/selector-store.js +24 -0
  210. package/dist/runtime/selector-store.js.map +1 -0
  211. package/dist/runtime/selector.d.ts.map +1 -1
  212. package/dist/runtime/selector.js +3 -18
  213. package/dist/runtime/selector.js.map +1 -1
  214. package/dist/ssg/create-static-gen.js +1 -0
  215. package/dist/ssg/create-static-gen.js.map +1 -1
  216. package/dist/ssg/static-routes.js +1 -0
  217. package/dist/ssg/static-routes.js.map +1 -1
  218. package/dist/ssr/boundaries.js +2 -2
  219. package/dist/ssr/boundaries.js.map +1 -1
  220. package/dist/ssr/component-runtime.js +3 -3
  221. package/dist/ssr/component-runtime.js.map +1 -1
  222. package/dist/ssr/render-resolved.js +1 -1
  223. package/dist/ssr/render-sync.js +1 -1
  224. package/dist/ssr/render-sync.js.map +1 -1
  225. package/dist/ssr/route-policy-resolution.js +2 -1
  226. package/dist/ssr/route-policy-resolution.js.map +1 -1
  227. package/dist/ssr/route-render.js +2 -1
  228. package/dist/ssr/route-render.js.map +1 -1
  229. package/dist/testing/index.d.ts.map +1 -1
  230. package/dist/testing/index.js +3 -2
  231. package/dist/testing/index.js.map +1 -1
  232. package/package.json +4 -4
  233. package/dist/dev/invariant.js +0 -29
  234. package/dist/dev/invariant.js.map +0 -1
  235. package/dist/dev/logger.js.map +0 -1
  236. package/dist/foundations/structures/portal.d.ts.map +0 -1
  237. package/dist/foundations/structures/portal.js.map +0 -1
  238. package/dist/runtime/component-contracts.js +0 -5
@@ -1 +1 @@
1
- {"version":3,"file":"resource-cell.js","names":[],"sources":["../../src/runtime/resource-cell.ts"],"sourcesContent":["import { withAsyncResourceContext, type ContextFrame } from './context';\nimport { logger } from '../dev/logger';\nimport {\n brandSnapshotSource,\n type SnapshotSourceBrand,\n} from './snapshot-source';\nimport { isPromiseLike } from '../common/promise';\nimport { throwSSRDataMissing } from '../common/render-context';\n\n/**\n * Pure, component-agnostic ResourceCell state machine.\n * - Holds value/pending/error/generation/controller\n * - Exposes a stable `snapshot` object: { value, pending, error, refresh }\n * - Uses `withAsyncResourceContext` to bind the synchronous execution step\n * to a captured frame. Continuations after await do not see the frame.\n */\nexport class ResourceCell<U> {\n value: U | null = null;\n pending = true;\n error: Error | null = null;\n generation = 0;\n controller: AbortController | null = null;\n deps: readonly unknown[] | null = null;\n resourceFrame: ContextFrame | null = null;\n\n // Optional debug label set by caller (component name) to improve logs\n ownerName?: string;\n\n private subscribers = new Set<() => void>();\n private disposed = false;\n\n readonly snapshot: {\n value: U | null;\n pending: boolean;\n error: Error | null;\n refresh: () => void;\n } & SnapshotSourceBrand;\n\n private fn: (opts: { signal: AbortSignal }) => PromiseLike<U> | U;\n\n constructor(\n fn: (opts: { signal: AbortSignal }) => PromiseLike<U> | U,\n deps: readonly unknown[] | null,\n resourceFrame: ContextFrame | null\n ) {\n this.fn = fn;\n this.deps = deps ? deps.slice() : null;\n this.resourceFrame = resourceFrame;\n this.snapshot = brandSnapshotSource({\n value: null,\n pending: true,\n error: null,\n refresh: () => this.refresh(),\n });\n }\n\n setLoader(fn: (opts: { signal: AbortSignal }) => PromiseLike<U> | U): void {\n this.fn = fn;\n }\n\n subscribe(cb: () => void): () => void {\n this.subscribers.add(cb);\n return () => this.subscribers.delete(cb);\n }\n\n private notifySubscribers() {\n this.snapshot.value = this.value;\n this.snapshot.pending = this.pending;\n this.snapshot.error = this.error;\n for (const cb of this.subscribers) cb();\n }\n\n start(ssr = false, notify = true) {\n if (this.disposed) {\n return;\n }\n\n const generation = this.generation;\n\n this.controller?.abort();\n const controller = new AbortController();\n this.controller = controller;\n this.pending = true;\n this.error = null;\n if (notify) this.notifySubscribers();\n\n let result: PromiseLike<U> | U;\n try {\n // Execute only the synchronous step inside the frozen resource frame.\n result = withAsyncResourceContext(this.resourceFrame, () =>\n this.fn({ signal: controller.signal })\n );\n } catch (err) {\n this.pending = false;\n this.error = err as Error;\n if (notify) this.notifySubscribers();\n return;\n }\n\n if (!isPromiseLike<U>(result)) {\n this.value = result as U;\n this.pending = false;\n this.error = null;\n if (notify) this.notifySubscribers();\n return;\n }\n\n if (ssr) {\n // During SSR async results are disallowed\n throwSSRDataMissing();\n }\n\n Promise.resolve(result)\n .then((val) => {\n if (this.generation !== generation) return;\n if (this.controller !== controller) return;\n // A loader that does not reject on abort (e.g. a plain Promise) would\n // otherwise commit its value after the fetch was cancelled by a deps\n // change, refresh(), or unmount. Mirror the AbortError guard used in\n // the rejection path so an aborted fetch's resolution stays inert.\n if (controller.signal.aborted) return;\n this.value = val;\n this.pending = false;\n this.error = null;\n this.notifySubscribers();\n })\n .catch((err) => {\n if (this.generation !== generation) return;\n if (this.controller !== controller) return;\n\n const isAbortError =\n controller.signal.aborted ||\n (err instanceof Error && err.name === 'AbortError') ||\n (typeof DOMException !== 'undefined' &&\n err instanceof DOMException &&\n err.name === 'AbortError');\n\n if (isAbortError) {\n return;\n }\n\n this.pending = false;\n this.error = err as Error;\n try {\n if (this.ownerName) {\n logger.error(\n `[Askr] Async resource error in ${this.ownerName}:`,\n err\n );\n } else {\n logger.error('[Askr] Async resource error:', err);\n }\n } catch {\n /* ignore logging errors */\n }\n this.notifySubscribers();\n });\n }\n\n refresh() {\n if (this.disposed) {\n return;\n }\n\n this.generation++;\n this.controller?.abort();\n this.start();\n }\n\n abort() {\n this.controller?.abort();\n }\n\n dispose() {\n if (this.disposed) {\n return;\n }\n\n this.disposed = true;\n this.controller?.abort();\n this.subscribers.clear();\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,IAAa,eAAb,MAA6B;CAwB3B,YACE,IACA,MACA,eACA;eA3BgB;iBACR;eACY;oBACT;oBACwB;cACH;uBACG;qCAKf,IAAI,IAAgB;kBACvB;EAgBjB,KAAK,KAAK;EACV,KAAK,OAAO,OAAO,KAAK,MAAM,IAAI;EAClC,KAAK,gBAAgB;EACrB,KAAK,WAAW,oBAAoB;GAClC,OAAO;GACP,SAAS;GACT,OAAO;GACP,eAAe,KAAK,QAAQ;EAC9B,CAAC;CACH;CAEA,UAAU,IAAiE;EACzE,KAAK,KAAK;CACZ;CAEA,UAAU,IAA4B;EACpC,KAAK,YAAY,IAAI,EAAE;EACvB,aAAa,KAAK,YAAY,OAAO,EAAE;CACzC;CAEA,oBAA4B;EAC1B,KAAK,SAAS,QAAQ,KAAK;EAC3B,KAAK,SAAS,UAAU,KAAK;EAC7B,KAAK,SAAS,QAAQ,KAAK;EAC3B,KAAK,MAAM,MAAM,KAAK,aAAa,GAAG;CACxC;CAEA,MAAM,MAAM,OAAO,SAAS,MAAM;EAChC,IAAI,KAAK,UACP;EAGF,MAAM,aAAa,KAAK;EAExB,KAAK,YAAY,MAAM;EACvB,MAAM,aAAa,IAAI,gBAAgB;EACvC,KAAK,aAAa;EAClB,KAAK,UAAU;EACf,KAAK,QAAQ;EACb,IAAI,QAAQ,KAAK,kBAAkB;EAEnC,IAAI;EACJ,IAAI;GAEF,SAAS,yBAAyB,KAAK,qBACrC,KAAK,GAAG,EAAE,QAAQ,WAAW,OAAO,CAAC,CACvC;EACF,SAAS,KAAK;GACZ,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,IAAI,QAAQ,KAAK,kBAAkB;GACnC;EACF;EAEA,IAAI,CAAC,cAAiB,MAAM,GAAG;GAC7B,KAAK,QAAQ;GACb,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,IAAI,QAAQ,KAAK,kBAAkB;GACnC;EACF;EAEA,IAAI,KAEF,oBAAoB;EAGtB,QAAQ,QAAQ,MAAM,CAAC,CACpB,MAAM,QAAQ;GACb,IAAI,KAAK,eAAe,YAAY;GACpC,IAAI,KAAK,eAAe,YAAY;GAKpC,IAAI,WAAW,OAAO,SAAS;GAC/B,KAAK,QAAQ;GACb,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,KAAK,kBAAkB;EACzB,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,IAAI,KAAK,eAAe,YAAY;GACpC,IAAI,KAAK,eAAe,YAAY;GASpC,IANE,WAAW,OAAO,WACjB,eAAe,SAAS,IAAI,SAAS,gBACrC,OAAO,iBAAiB,eACvB,eAAe,gBACf,IAAI,SAAS,cAGf;GAGF,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,IAAI;IACF,IAAI,KAAK,WACP,OAAO,MACL,kCAAkC,KAAK,UAAU,IACjD,GACF;SAEA,OAAO,MAAM,gCAAgC,GAAG;GAEpD,QAAQ,CAER;GACA,KAAK,kBAAkB;EACzB,CAAC;CACL;CAEA,UAAU;EACR,IAAI,KAAK,UACP;EAGF,KAAK;EACL,KAAK,YAAY,MAAM;EACvB,KAAK,MAAM;CACb;CAEA,QAAQ;EACN,KAAK,YAAY,MAAM;CACzB;CAEA,UAAU;EACR,IAAI,KAAK,UACP;EAGF,KAAK,WAAW;EAChB,KAAK,YAAY,MAAM;EACvB,KAAK,YAAY,MAAM;CACzB;AACF"}
1
+ {"version":3,"file":"resource-cell.js","names":[],"sources":["../../src/runtime/resource-cell.ts"],"sourcesContent":["import { withAsyncResourceContext, type ContextFrame } from './context';\nimport { logger } from '../common/logger';\nimport {\n brandSnapshotSource,\n type SnapshotSourceBrand,\n} from './snapshot-source';\nimport { isPromiseLike } from '../common/promise';\nimport { throwSSRDataMissing } from '../common/render-context';\n\n/**\n * Pure, component-agnostic ResourceCell state machine.\n * - Holds value/pending/error/generation/controller\n * - Exposes a stable `snapshot` object: { value, pending, error, refresh }\n * - Uses `withAsyncResourceContext` to bind the synchronous execution step\n * to a captured frame. Continuations after await do not see the frame.\n */\nexport class ResourceCell<U> {\n value: U | null = null;\n pending = true;\n error: Error | null = null;\n generation = 0;\n controller: AbortController | null = null;\n deps: readonly unknown[] | null = null;\n resourceFrame: ContextFrame | null = null;\n\n // Optional debug label set by caller (component name) to improve logs\n ownerName?: string;\n\n private subscribers = new Set<() => void>();\n private disposed = false;\n\n readonly snapshot: {\n value: U | null;\n pending: boolean;\n error: Error | null;\n refresh: () => void;\n } & SnapshotSourceBrand;\n\n private fn: (opts: { signal: AbortSignal }) => PromiseLike<U> | U;\n\n constructor(\n fn: (opts: { signal: AbortSignal }) => PromiseLike<U> | U,\n deps: readonly unknown[] | null,\n resourceFrame: ContextFrame | null\n ) {\n this.fn = fn;\n this.deps = deps ? deps.slice() : null;\n this.resourceFrame = resourceFrame;\n this.snapshot = brandSnapshotSource({\n value: null,\n pending: true,\n error: null,\n refresh: () => this.refresh(),\n });\n }\n\n setLoader(fn: (opts: { signal: AbortSignal }) => PromiseLike<U> | U): void {\n this.fn = fn;\n }\n\n subscribe(cb: () => void): () => void {\n this.subscribers.add(cb);\n return () => this.subscribers.delete(cb);\n }\n\n private notifySubscribers() {\n this.snapshot.value = this.value;\n this.snapshot.pending = this.pending;\n this.snapshot.error = this.error;\n for (const cb of this.subscribers) cb();\n }\n\n start(ssr = false, notify = true) {\n if (this.disposed) {\n return;\n }\n\n const generation = this.generation;\n\n this.controller?.abort();\n const controller = new AbortController();\n this.controller = controller;\n this.pending = true;\n this.error = null;\n if (notify) this.notifySubscribers();\n\n let result: PromiseLike<U> | U;\n try {\n // Execute only the synchronous step inside the frozen resource frame.\n result = withAsyncResourceContext(this.resourceFrame, () =>\n this.fn({ signal: controller.signal })\n );\n } catch (err) {\n this.pending = false;\n this.error = err as Error;\n if (notify) this.notifySubscribers();\n return;\n }\n\n if (!isPromiseLike<U>(result)) {\n this.value = result as U;\n this.pending = false;\n this.error = null;\n if (notify) this.notifySubscribers();\n return;\n }\n\n if (ssr) {\n // During SSR async results are disallowed\n throwSSRDataMissing();\n }\n\n Promise.resolve(result)\n .then((val) => {\n if (this.generation !== generation) return;\n if (this.controller !== controller) return;\n // A loader that does not reject on abort (e.g. a plain Promise) would\n // otherwise commit its value after the fetch was cancelled by a deps\n // change, refresh(), or unmount. Mirror the AbortError guard used in\n // the rejection path so an aborted fetch's resolution stays inert.\n if (controller.signal.aborted) return;\n this.value = val;\n this.pending = false;\n this.error = null;\n this.notifySubscribers();\n })\n .catch((err) => {\n if (this.generation !== generation) return;\n if (this.controller !== controller) return;\n\n const isAbortError =\n controller.signal.aborted ||\n (err instanceof Error && err.name === 'AbortError') ||\n (typeof DOMException !== 'undefined' &&\n err instanceof DOMException &&\n err.name === 'AbortError');\n\n if (isAbortError) {\n return;\n }\n\n this.pending = false;\n this.error = err as Error;\n try {\n if (this.ownerName) {\n logger.error(\n `[Askr] Async resource error in ${this.ownerName}:`,\n err\n );\n } else {\n logger.error('[Askr] Async resource error:', err);\n }\n } catch {\n /* ignore logging errors */\n }\n this.notifySubscribers();\n });\n }\n\n refresh() {\n if (this.disposed) {\n return;\n }\n\n this.generation++;\n this.controller?.abort();\n this.start();\n }\n\n abort() {\n this.controller?.abort();\n }\n\n dispose() {\n if (this.disposed) {\n return;\n }\n\n this.disposed = true;\n this.controller?.abort();\n this.subscribers.clear();\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAgBA,IAAa,eAAb,MAA6B;CAwB3B,YACE,IACA,MACA,eACA;eA3BgB;iBACR;eACY;oBACT;oBACwB;cACH;uBACG;qCAKf,IAAI,IAAgB;kBACvB;EAgBjB,KAAK,KAAK;EACV,KAAK,OAAO,OAAO,KAAK,MAAM,IAAI;EAClC,KAAK,gBAAgB;EACrB,KAAK,WAAW,oBAAoB;GAClC,OAAO;GACP,SAAS;GACT,OAAO;GACP,eAAe,KAAK,QAAQ;EAC9B,CAAC;CACH;CAEA,UAAU,IAAiE;EACzE,KAAK,KAAK;CACZ;CAEA,UAAU,IAA4B;EACpC,KAAK,YAAY,IAAI,EAAE;EACvB,aAAa,KAAK,YAAY,OAAO,EAAE;CACzC;CAEA,oBAA4B;EAC1B,KAAK,SAAS,QAAQ,KAAK;EAC3B,KAAK,SAAS,UAAU,KAAK;EAC7B,KAAK,SAAS,QAAQ,KAAK;EAC3B,KAAK,MAAM,MAAM,KAAK,aAAa,GAAG;CACxC;CAEA,MAAM,MAAM,OAAO,SAAS,MAAM;EAChC,IAAI,KAAK,UACP;EAGF,MAAM,aAAa,KAAK;EAExB,KAAK,YAAY,MAAM;EACvB,MAAM,aAAa,IAAI,gBAAgB;EACvC,KAAK,aAAa;EAClB,KAAK,UAAU;EACf,KAAK,QAAQ;EACb,IAAI,QAAQ,KAAK,kBAAkB;EAEnC,IAAI;EACJ,IAAI;GAEF,SAAS,yBAAyB,KAAK,qBACrC,KAAK,GAAG,EAAE,QAAQ,WAAW,OAAO,CAAC,CACvC;EACF,SAAS,KAAK;GACZ,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,IAAI,QAAQ,KAAK,kBAAkB;GACnC;EACF;EAEA,IAAI,CAAC,cAAiB,MAAM,GAAG;GAC7B,KAAK,QAAQ;GACb,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,IAAI,QAAQ,KAAK,kBAAkB;GACnC;EACF;EAEA,IAAI,KAEF,oBAAoB;EAGtB,QAAQ,QAAQ,MAAM,CAAC,CACpB,MAAM,QAAQ;GACb,IAAI,KAAK,eAAe,YAAY;GACpC,IAAI,KAAK,eAAe,YAAY;GAKpC,IAAI,WAAW,OAAO,SAAS;GAC/B,KAAK,QAAQ;GACb,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,KAAK,kBAAkB;EACzB,CAAC,CAAC,CACD,OAAO,QAAQ;GACd,IAAI,KAAK,eAAe,YAAY;GACpC,IAAI,KAAK,eAAe,YAAY;GASpC,IANE,WAAW,OAAO,WACjB,eAAe,SAAS,IAAI,SAAS,gBACrC,OAAO,iBAAiB,eACvB,eAAe,gBACf,IAAI,SAAS,cAGf;GAGF,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,IAAI;IACF,IAAI,KAAK,WACP,OAAO,MACL,kCAAkC,KAAK,UAAU,IACjD,GACF;SAEA,OAAO,MAAM,gCAAgC,GAAG;GAEpD,QAAQ,CAER;GACA,KAAK,kBAAkB;EACzB,CAAC;CACL;CAEA,UAAU;EACR,IAAI,KAAK,UACP;EAGF,KAAK;EACL,KAAK,YAAY,MAAM;EACvB,KAAK,MAAM;CACb;CAEA,QAAQ;EACN,KAAK,YAAY,MAAM;CACzB;CAEA,UAAU;EACR,IAAI,KAAK,UACP;EAGF,KAAK,WAAW;EAChB,KAAK,YAAY,MAAM;EACvB,KAAK,YAAY,MAAM;CACzB;AACF"}
@@ -2,11 +2,11 @@ import { enqueueRuntimeLane } from "./access.js";
2
2
  import { getCurrentContextFrame } from "./context.js";
3
3
  import { getCurrentComponentInstance } from "./component-scope.js";
4
4
  import "./component.js";
5
- import { state } from "./state.js";
6
5
  import { brandSnapshotSource } from "./snapshot-source.js";
7
6
  import { SSRDataMissingError } from "../common/ssr-errors.js";
8
7
  import { getActiveRenderContext, getCurrentRenderData, getNextRenderKey, throwSSRDataMissing } from "../common/render-context.js";
9
8
  import { ResourceCell } from "./resource-cell.js";
9
+ import { state } from "./state.js";
10
10
  //#region src/runtime/resource-operation.ts
11
11
  /**
12
12
  * Resource primitive — simple, deterministic async primitive
@@ -1,5 +1,5 @@
1
- import { ReadableSource } from "./readable.js";
2
1
  import { ComponentInstance } from "./component-internal.js";
2
+ import { ReadableSource } from "./readable.js";
3
3
  import { Scheduler } from "./scheduler.js";
4
4
 
5
5
  //#region src/runtime/runtime.d.ts
@@ -1,6 +1,6 @@
1
1
  import { isDevelopmentEnvironment } from "../common/env.js";
2
- import { assertSchedulingPrecondition, invariant } from "../dev/invariant.js";
3
- import { logger } from "../dev/logger.js";
2
+ import { assertSchedulingPrecondition, invariant } from "../common/invariant.js";
3
+ import { logger } from "../common/logger.js";
4
4
  import { recordSchedulerFlushTaskCount } from "./perf-metrics.js";
5
5
  //#region src/runtime/scheduler.ts
6
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","names":[],"sources":["../../src/runtime/scheduler.ts"],"sourcesContent":["/**\n * Serialized update scheduler — safer design (no inline execution, explicit flush)\n *\n * Key ideas:\n * - Never execute a task inline from `enqueue`.\n * - `flush()` is explicit and non-reentrant.\n * - `runWithSyncProgress()` allows enqueues temporarily but does not run tasks\n * inline; it runs `fn` and then does an explicit `flush()`.\n * - `waitForFlush()` is race-free with a monotonic `flushVersion`.\n */\n\nimport { isDevelopmentEnvironment } from '../common/env';\nimport { assertSchedulingPrecondition, invariant } from '../dev/invariant';\nimport { logger } from '../dev/logger';\nimport { recordSchedulerFlushTaskCount } from './perf-metrics';\n\nconst MAX_FLUSH_DEPTH = 50;\n\ntype Task = () => void;\nexport type SchedulerLane = 'derived' | 'component' | 'reactive' | 'post';\nexport type SchedulerBulkCommitProbe = () => boolean;\n\nconst SCHEDULER_LANES: SchedulerLane[] = [\n 'derived',\n 'component',\n 'reactive',\n 'post',\n];\n\ninterface LaneQueue {\n tasks: Task[];\n head: number;\n}\n\nexport class Scheduler {\n private bulkCommitProbe: SchedulerBulkCommitProbe = () => false;\n\n private lanes: Record<SchedulerLane, LaneQueue> = {\n derived: { tasks: [], head: 0 },\n component: { tasks: [], head: 0 },\n reactive: { tasks: [], head: 0 },\n post: { tasks: [], head: 0 },\n };\n\n private running = false;\n private inHandler = false;\n private depth = 0;\n private executionDepth = 0; // for compat with existing diagnostics\n\n // Monotonic flush version increments at end of each flush\n private flushVersion = 0;\n\n // Best-effort microtask kick scheduling\n private kickScheduled = false;\n\n // Escape hatch flag for runWithSyncProgress\n private allowSyncProgress = false;\n\n // Waiters waiting for flushVersion >= target\n private waiters: Array<{\n target: number;\n resolve: () => void;\n reject: (err: unknown) => void;\n timer?: ReturnType<typeof setTimeout>;\n }> = [];\n\n // Keep a lightweight taskCount for compatibility/diagnostics\n private taskCount = 0;\n\n setBulkCommitProbe(probe: SchedulerBulkCommitProbe): void {\n this.bulkCommitProbe = probe;\n }\n\n private isBulkCommitActive(): boolean {\n try {\n return this.bulkCommitProbe();\n } catch (e) {\n void e;\n return false;\n }\n }\n\n private hasPendingTasks(): boolean {\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n if (queue.head < queue.tasks.length) {\n return true;\n }\n }\n return false;\n }\n\n private getPendingTaskCount(): number {\n let total = 0;\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n total += queue.tasks.length - queue.head;\n }\n return total;\n }\n\n private compactLane(queue: LaneQueue): void {\n if (queue.head >= queue.tasks.length) {\n queue.tasks.length = 0;\n queue.head = 0;\n return;\n }\n\n if (queue.head <= 0) {\n return;\n }\n\n const remaining = queue.tasks.length - queue.head;\n for (let i = 0; i < remaining; i++) {\n queue.tasks[i] = queue.tasks[queue.head + i];\n }\n queue.tasks.length = remaining;\n queue.head = 0;\n }\n\n private scheduleFlushKick(): void {\n if (\n this.running ||\n this.kickScheduled ||\n this.inHandler ||\n this.allowSyncProgress ||\n this.isBulkCommitActive() ||\n !this.hasPendingTasks()\n ) {\n return;\n }\n\n this.kickScheduled = true;\n queueMicrotask(() => {\n this.kickScheduled = false;\n if (\n this.running ||\n this.isBulkCommitActive() ||\n !this.hasPendingTasks()\n ) {\n return;\n }\n try {\n this.flush();\n } catch (err) {\n setTimeout(() => {\n throw err;\n });\n }\n });\n }\n\n enqueue(task: Task): void {\n this.enqueueInLane('component', task);\n }\n\n enqueueInLane(lane: SchedulerLane, task: Task): void {\n assertSchedulingPrecondition(\n typeof task === 'function',\n 'enqueue() requires a function'\n );\n\n // Strict rule: during bulk commit, only allow enqueues if runWithSyncProgress enabled\n if (this.isBulkCommitActive() && !this.allowSyncProgress) {\n if (isDevelopmentEnvironment()) {\n throw new Error(\n '[Scheduler] enqueue() during bulk commit (not allowed)'\n );\n }\n return;\n }\n\n // Enqueue task and account counts\n this.lanes[lane].tasks.push(task);\n this.taskCount++;\n\n this.scheduleFlushKick();\n }\n\n flush(): void {\n invariant(\n !this.running,\n '[Scheduler] flush() called while already running'\n );\n\n // Dev-only guard: disallow flush during bulk commit unless allowed\n if (isDevelopmentEnvironment()) {\n if (this.isBulkCommitActive() && !this.allowSyncProgress) {\n throw new Error(\n '[Scheduler] flush() started during bulk commit (not allowed)'\n );\n }\n }\n\n this.running = true;\n this.depth = 0;\n let fatal: unknown = null;\n let executedTaskCount = 0;\n const checkFlushDepth = isDevelopmentEnvironment();\n const executionsByTask = checkFlushDepth ? new Map<Task, number>() : null;\n\n try {\n while (fatal === null) {\n let didRunTask = false;\n\n for (const lane of SCHEDULER_LANES) {\n const laneQueue = this.lanes[lane];\n let executedInLane = 0;\n\n while (laneQueue.head < laneQueue.tasks.length) {\n const task = laneQueue.tasks[laneQueue.head++];\n if (executionsByTask) {\n const taskExecutions = (executionsByTask.get(task) ?? 0) + 1;\n executionsByTask.set(task, taskExecutions);\n this.depth = Math.max(this.depth, taskExecutions);\n if (taskExecutions > MAX_FLUSH_DEPTH) {\n throw new Error(\n `[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`\n );\n }\n }\n\n try {\n this.executionDepth++;\n task();\n this.executionDepth--;\n executedTaskCount++;\n executedInLane++;\n didRunTask = true;\n } catch (err) {\n // ensure executionDepth stays balanced for the task that threw\n if (this.executionDepth > 0) this.executionDepth--;\n fatal = err;\n break;\n }\n }\n\n if (executedInLane > 0) {\n this.taskCount = Math.max(0, this.taskCount - executedInLane);\n }\n\n if (fatal !== null) {\n break;\n }\n }\n\n if (!didRunTask) {\n break;\n }\n }\n } finally {\n this.running = false;\n this.depth = 0;\n this.executionDepth = 0;\n\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n if (queue.head > 0) {\n this.compactLane(queue);\n }\n }\n\n // Advance flush epoch and resolve waiters\n this.flushVersion++;\n this.resolveWaiters();\n recordSchedulerFlushTaskCount(executedTaskCount);\n }\n\n if (fatal) throw fatal;\n }\n\n runWithSyncProgress<T>(fn: () => T): T {\n const prev = this.allowSyncProgress;\n this.allowSyncProgress = true;\n\n // Snapshot flushVersion so we can ensure we always complete an epoch\n const startVersion = this.flushVersion;\n\n try {\n const res = fn();\n\n // Flush deterministically if tasks were enqueued (and we're not already running)\n if (!this.running && this.hasPendingTasks()) {\n this.flush();\n }\n\n if (isDevelopmentEnvironment()) {\n if (!this.running && this.hasPendingTasks()) {\n throw new Error(\n '[Scheduler] tasks remain after runWithSyncProgress flush'\n );\n }\n }\n\n return res;\n } finally {\n // If no flush happened during the protected window, complete an epoch so\n // observers (tests) see progress even when fast-lane did synchronous work\n // without enqueuing tasks.\n try {\n if (this.flushVersion === startVersion) {\n this.flushVersion++;\n this.resolveWaiters();\n }\n } catch (e) {\n void e;\n }\n\n this.allowSyncProgress = prev;\n }\n }\n\n waitForFlush(targetVersion?: number, timeoutMs = 2000): Promise<void> {\n const target =\n typeof targetVersion === 'number' ? targetVersion : this.flushVersion + 1;\n if (this.flushVersion >= target) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n const ns =\n (\n globalThis as unknown as Record<string, unknown> & {\n __ASKR__?: Record<string, unknown>;\n }\n ).__ASKR__ || {};\n const diag = {\n flushVersion: this.flushVersion,\n queueLen: this.getPendingTaskCount(),\n running: this.running,\n inHandler: this.inHandler,\n bulk: this.isBulkCommitActive(),\n namespace: ns,\n };\n reject(\n new Error(\n `waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`\n )\n );\n }, timeoutMs);\n\n this.waiters.push({ target, resolve, reject, timer });\n });\n }\n\n getState() {\n // Provide the compatibility shape expected by diagnostics/tests\n return {\n queueLength: this.getPendingTaskCount(),\n running: this.running,\n depth: this.depth,\n executionDepth: this.executionDepth,\n taskCount: this.taskCount,\n flushVersion: this.flushVersion,\n laneQueues: {\n derived: this.lanes.derived.tasks.length - this.lanes.derived.head,\n component:\n this.lanes.component.tasks.length - this.lanes.component.head,\n reactive: this.lanes.reactive.tasks.length - this.lanes.reactive.head,\n post: this.lanes.post.tasks.length - this.lanes.post.head,\n },\n // New fields for optional inspection\n inHandler: this.inHandler,\n allowSyncProgress: this.allowSyncProgress,\n };\n }\n\n getFlushVersion(): number {\n return this.flushVersion;\n }\n\n flushIfQueued(): void {\n if (!this.running && this.hasPendingTasks()) {\n this.flush();\n }\n }\n\n runInHandlerScope<T>(fn: () => T, flushMode: 'defer' | 'sync' = 'defer'): T {\n const prevInHandler = this.inHandler;\n this.inHandler = true;\n\n try {\n return fn();\n } finally {\n this.inHandler = prevInHandler;\n\n if (!this.inHandler) {\n if (flushMode === 'sync') {\n this.flushIfQueued();\n } else {\n this.scheduleFlushKick();\n }\n }\n }\n }\n\n setInHandler(v: boolean) {\n this.inHandler = v;\n if (!v) {\n this.scheduleFlushKick();\n }\n }\n\n isInHandler(): boolean {\n return this.inHandler;\n }\n\n isExecuting(): boolean {\n return this.running || this.executionDepth > 0;\n }\n\n // Clear pending synchronous tasks (used by fastlane enter/exit)\n clearPendingSyncTasks(): number {\n const remaining = this.getPendingTaskCount();\n if (remaining <= 0) return 0;\n\n if (this.running) {\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n queue.tasks.length = queue.head;\n }\n this.taskCount = Math.max(0, this.taskCount - remaining);\n queueMicrotask(() => {\n try {\n this.flushVersion++;\n this.resolveWaiters();\n } catch (e) {\n void e;\n }\n });\n return remaining;\n }\n\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n queue.tasks.length = 0;\n queue.head = 0;\n }\n this.taskCount = Math.max(0, this.taskCount - remaining);\n this.flushVersion++;\n this.resolveWaiters();\n return remaining;\n }\n\n private resolveWaiters() {\n if (this.waiters.length === 0) return;\n const ready: Array<() => void> = [];\n const remaining: typeof this.waiters = [];\n\n for (const w of this.waiters) {\n if (this.flushVersion >= w.target) {\n if (w.timer) clearTimeout(w.timer);\n ready.push(w.resolve);\n } else {\n remaining.push(w);\n }\n }\n\n this.waiters = remaining;\n for (const r of ready) r();\n }\n}\n\nexport const globalScheduler = new Scheduler();\n\nexport function isSchedulerExecuting(): boolean {\n return globalScheduler.isExecuting();\n}\n\nexport function scheduleEventHandler(handler: EventListener): EventListener {\n return (event: Event) => {\n try {\n globalScheduler.runInHandlerScope(() => {\n handler.call(null, event);\n });\n } catch (error) {\n logger.error('[Askr] Event handler error:', error);\n }\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scheduler.js","names":[],"sources":["../../src/runtime/scheduler.ts"],"sourcesContent":["/**\n * Serialized update scheduler — safer design (no inline execution, explicit flush)\n *\n * Key ideas:\n * - Never execute a task inline from `enqueue`.\n * - `flush()` is explicit and non-reentrant.\n * - `runWithSyncProgress()` allows enqueues temporarily but does not run tasks\n * inline; it runs `fn` and then does an explicit `flush()`.\n * - `waitForFlush()` is race-free with a monotonic `flushVersion`.\n */\n\nimport { isDevelopmentEnvironment } from '../common/env';\nimport { assertSchedulingPrecondition, invariant } from '../common/invariant';\nimport { logger } from '../common/logger';\nimport { recordSchedulerFlushTaskCount } from './perf-metrics';\n\nconst MAX_FLUSH_DEPTH = 50;\n\ntype Task = () => void;\nexport type SchedulerLane = 'derived' | 'component' | 'reactive' | 'post';\nexport type SchedulerBulkCommitProbe = () => boolean;\n\nconst SCHEDULER_LANES: SchedulerLane[] = [\n 'derived',\n 'component',\n 'reactive',\n 'post',\n];\n\ninterface LaneQueue {\n tasks: Task[];\n head: number;\n}\n\nexport class Scheduler {\n private bulkCommitProbe: SchedulerBulkCommitProbe = () => false;\n\n private lanes: Record<SchedulerLane, LaneQueue> = {\n derived: { tasks: [], head: 0 },\n component: { tasks: [], head: 0 },\n reactive: { tasks: [], head: 0 },\n post: { tasks: [], head: 0 },\n };\n\n private running = false;\n private inHandler = false;\n private depth = 0;\n private executionDepth = 0; // for compat with existing diagnostics\n\n // Monotonic flush version increments at end of each flush\n private flushVersion = 0;\n\n // Best-effort microtask kick scheduling\n private kickScheduled = false;\n\n // Escape hatch flag for runWithSyncProgress\n private allowSyncProgress = false;\n\n // Waiters waiting for flushVersion >= target\n private waiters: Array<{\n target: number;\n resolve: () => void;\n reject: (err: unknown) => void;\n timer?: ReturnType<typeof setTimeout>;\n }> = [];\n\n // Keep a lightweight taskCount for compatibility/diagnostics\n private taskCount = 0;\n\n setBulkCommitProbe(probe: SchedulerBulkCommitProbe): void {\n this.bulkCommitProbe = probe;\n }\n\n private isBulkCommitActive(): boolean {\n try {\n return this.bulkCommitProbe();\n } catch (e) {\n void e;\n return false;\n }\n }\n\n private hasPendingTasks(): boolean {\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n if (queue.head < queue.tasks.length) {\n return true;\n }\n }\n return false;\n }\n\n private getPendingTaskCount(): number {\n let total = 0;\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n total += queue.tasks.length - queue.head;\n }\n return total;\n }\n\n private compactLane(queue: LaneQueue): void {\n if (queue.head >= queue.tasks.length) {\n queue.tasks.length = 0;\n queue.head = 0;\n return;\n }\n\n if (queue.head <= 0) {\n return;\n }\n\n const remaining = queue.tasks.length - queue.head;\n for (let i = 0; i < remaining; i++) {\n queue.tasks[i] = queue.tasks[queue.head + i];\n }\n queue.tasks.length = remaining;\n queue.head = 0;\n }\n\n private scheduleFlushKick(): void {\n if (\n this.running ||\n this.kickScheduled ||\n this.inHandler ||\n this.allowSyncProgress ||\n this.isBulkCommitActive() ||\n !this.hasPendingTasks()\n ) {\n return;\n }\n\n this.kickScheduled = true;\n queueMicrotask(() => {\n this.kickScheduled = false;\n if (\n this.running ||\n this.isBulkCommitActive() ||\n !this.hasPendingTasks()\n ) {\n return;\n }\n try {\n this.flush();\n } catch (err) {\n setTimeout(() => {\n throw err;\n });\n }\n });\n }\n\n enqueue(task: Task): void {\n this.enqueueInLane('component', task);\n }\n\n enqueueInLane(lane: SchedulerLane, task: Task): void {\n assertSchedulingPrecondition(\n typeof task === 'function',\n 'enqueue() requires a function'\n );\n\n // Strict rule: during bulk commit, only allow enqueues if runWithSyncProgress enabled\n if (this.isBulkCommitActive() && !this.allowSyncProgress) {\n if (isDevelopmentEnvironment()) {\n throw new Error(\n '[Scheduler] enqueue() during bulk commit (not allowed)'\n );\n }\n return;\n }\n\n // Enqueue task and account counts\n this.lanes[lane].tasks.push(task);\n this.taskCount++;\n\n this.scheduleFlushKick();\n }\n\n flush(): void {\n invariant(\n !this.running,\n '[Scheduler] flush() called while already running'\n );\n\n // Dev-only guard: disallow flush during bulk commit unless allowed\n if (isDevelopmentEnvironment()) {\n if (this.isBulkCommitActive() && !this.allowSyncProgress) {\n throw new Error(\n '[Scheduler] flush() started during bulk commit (not allowed)'\n );\n }\n }\n\n this.running = true;\n this.depth = 0;\n let fatal: unknown = null;\n let executedTaskCount = 0;\n const checkFlushDepth = isDevelopmentEnvironment();\n const executionsByTask = checkFlushDepth ? new Map<Task, number>() : null;\n\n try {\n while (fatal === null) {\n let didRunTask = false;\n\n for (const lane of SCHEDULER_LANES) {\n const laneQueue = this.lanes[lane];\n let executedInLane = 0;\n\n while (laneQueue.head < laneQueue.tasks.length) {\n const task = laneQueue.tasks[laneQueue.head++];\n if (executionsByTask) {\n const taskExecutions = (executionsByTask.get(task) ?? 0) + 1;\n executionsByTask.set(task, taskExecutions);\n this.depth = Math.max(this.depth, taskExecutions);\n if (taskExecutions > MAX_FLUSH_DEPTH) {\n throw new Error(\n `[Scheduler] exceeded MAX_FLUSH_DEPTH (${MAX_FLUSH_DEPTH}). Likely infinite update loop.`\n );\n }\n }\n\n try {\n this.executionDepth++;\n task();\n this.executionDepth--;\n executedTaskCount++;\n executedInLane++;\n didRunTask = true;\n } catch (err) {\n // ensure executionDepth stays balanced for the task that threw\n if (this.executionDepth > 0) this.executionDepth--;\n fatal = err;\n break;\n }\n }\n\n if (executedInLane > 0) {\n this.taskCount = Math.max(0, this.taskCount - executedInLane);\n }\n\n if (fatal !== null) {\n break;\n }\n }\n\n if (!didRunTask) {\n break;\n }\n }\n } finally {\n this.running = false;\n this.depth = 0;\n this.executionDepth = 0;\n\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n if (queue.head > 0) {\n this.compactLane(queue);\n }\n }\n\n // Advance flush epoch and resolve waiters\n this.flushVersion++;\n this.resolveWaiters();\n recordSchedulerFlushTaskCount(executedTaskCount);\n }\n\n if (fatal) throw fatal;\n }\n\n runWithSyncProgress<T>(fn: () => T): T {\n const prev = this.allowSyncProgress;\n this.allowSyncProgress = true;\n\n // Snapshot flushVersion so we can ensure we always complete an epoch\n const startVersion = this.flushVersion;\n\n try {\n const res = fn();\n\n // Flush deterministically if tasks were enqueued (and we're not already running)\n if (!this.running && this.hasPendingTasks()) {\n this.flush();\n }\n\n if (isDevelopmentEnvironment()) {\n if (!this.running && this.hasPendingTasks()) {\n throw new Error(\n '[Scheduler] tasks remain after runWithSyncProgress flush'\n );\n }\n }\n\n return res;\n } finally {\n // If no flush happened during the protected window, complete an epoch so\n // observers (tests) see progress even when fast-lane did synchronous work\n // without enqueuing tasks.\n try {\n if (this.flushVersion === startVersion) {\n this.flushVersion++;\n this.resolveWaiters();\n }\n } catch (e) {\n void e;\n }\n\n this.allowSyncProgress = prev;\n }\n }\n\n waitForFlush(targetVersion?: number, timeoutMs = 2000): Promise<void> {\n const target =\n typeof targetVersion === 'number' ? targetVersion : this.flushVersion + 1;\n if (this.flushVersion >= target) return Promise.resolve();\n\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n const ns =\n (\n globalThis as unknown as Record<string, unknown> & {\n __ASKR__?: Record<string, unknown>;\n }\n ).__ASKR__ || {};\n const diag = {\n flushVersion: this.flushVersion,\n queueLen: this.getPendingTaskCount(),\n running: this.running,\n inHandler: this.inHandler,\n bulk: this.isBulkCommitActive(),\n namespace: ns,\n };\n reject(\n new Error(\n `waitForFlush timeout ${timeoutMs}ms: ${JSON.stringify(diag)}`\n )\n );\n }, timeoutMs);\n\n this.waiters.push({ target, resolve, reject, timer });\n });\n }\n\n getState() {\n // Provide the compatibility shape expected by diagnostics/tests\n return {\n queueLength: this.getPendingTaskCount(),\n running: this.running,\n depth: this.depth,\n executionDepth: this.executionDepth,\n taskCount: this.taskCount,\n flushVersion: this.flushVersion,\n laneQueues: {\n derived: this.lanes.derived.tasks.length - this.lanes.derived.head,\n component:\n this.lanes.component.tasks.length - this.lanes.component.head,\n reactive: this.lanes.reactive.tasks.length - this.lanes.reactive.head,\n post: this.lanes.post.tasks.length - this.lanes.post.head,\n },\n // New fields for optional inspection\n inHandler: this.inHandler,\n allowSyncProgress: this.allowSyncProgress,\n };\n }\n\n getFlushVersion(): number {\n return this.flushVersion;\n }\n\n flushIfQueued(): void {\n if (!this.running && this.hasPendingTasks()) {\n this.flush();\n }\n }\n\n runInHandlerScope<T>(fn: () => T, flushMode: 'defer' | 'sync' = 'defer'): T {\n const prevInHandler = this.inHandler;\n this.inHandler = true;\n\n try {\n return fn();\n } finally {\n this.inHandler = prevInHandler;\n\n if (!this.inHandler) {\n if (flushMode === 'sync') {\n this.flushIfQueued();\n } else {\n this.scheduleFlushKick();\n }\n }\n }\n }\n\n setInHandler(v: boolean) {\n this.inHandler = v;\n if (!v) {\n this.scheduleFlushKick();\n }\n }\n\n isInHandler(): boolean {\n return this.inHandler;\n }\n\n isExecuting(): boolean {\n return this.running || this.executionDepth > 0;\n }\n\n // Clear pending synchronous tasks (used by fastlane enter/exit)\n clearPendingSyncTasks(): number {\n const remaining = this.getPendingTaskCount();\n if (remaining <= 0) return 0;\n\n if (this.running) {\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n queue.tasks.length = queue.head;\n }\n this.taskCount = Math.max(0, this.taskCount - remaining);\n queueMicrotask(() => {\n try {\n this.flushVersion++;\n this.resolveWaiters();\n } catch (e) {\n void e;\n }\n });\n return remaining;\n }\n\n for (const lane of SCHEDULER_LANES) {\n const queue = this.lanes[lane];\n queue.tasks.length = 0;\n queue.head = 0;\n }\n this.taskCount = Math.max(0, this.taskCount - remaining);\n this.flushVersion++;\n this.resolveWaiters();\n return remaining;\n }\n\n private resolveWaiters() {\n if (this.waiters.length === 0) return;\n const ready: Array<() => void> = [];\n const remaining: typeof this.waiters = [];\n\n for (const w of this.waiters) {\n if (this.flushVersion >= w.target) {\n if (w.timer) clearTimeout(w.timer);\n ready.push(w.resolve);\n } else {\n remaining.push(w);\n }\n }\n\n this.waiters = remaining;\n for (const r of ready) r();\n }\n}\n\nexport const globalScheduler = new Scheduler();\n\nexport function isSchedulerExecuting(): boolean {\n return globalScheduler.isExecuting();\n}\n\nexport function scheduleEventHandler(handler: EventListener): EventListener {\n return (event: Event) => {\n try {\n globalScheduler.runInHandlerScope(() => {\n handler.call(null, event);\n });\n } catch (error) {\n logger.error('[Askr] Event handler error:', error);\n }\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { enqueueRuntimeLane } from "./access.js";
2
+ //#region src/runtime/selector-store.ts
3
+ const dirtySelectorRecords = /* @__PURE__ */ new Set();
4
+ let hasPendingSelectorFlush = false;
5
+ function markDirtySelectorRecord(record, flush) {
6
+ record._dirty = true;
7
+ if (record._scheduled) return;
8
+ record._scheduled = true;
9
+ dirtySelectorRecords.add(record);
10
+ if (hasPendingSelectorFlush) return;
11
+ hasPendingSelectorFlush = true;
12
+ enqueueRuntimeLane("derived", flush);
13
+ }
14
+ function takeDirtySelectorRecords() {
15
+ hasPendingSelectorFlush = false;
16
+ if (dirtySelectorRecords.size === 0) return [];
17
+ const pending = Array.from(dirtySelectorRecords);
18
+ dirtySelectorRecords.clear();
19
+ return pending;
20
+ }
21
+ //#endregion
22
+ export { markDirtySelectorRecord, takeDirtySelectorRecords };
23
+
24
+ //# sourceMappingURL=selector-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector-store.js","names":[],"sources":["../../src/runtime/selector-store.ts"],"sourcesContent":["import { enqueueRuntimeLane } from './access';\n\ntype DirtySelectorRecord = {\n _dirty: boolean;\n _scheduled: boolean;\n};\n\nconst dirtySelectorRecords = new Set<DirtySelectorRecord>();\nlet hasPendingSelectorFlush = false;\n\nexport function markDirtySelectorRecord<T extends DirtySelectorRecord>(\n record: T,\n flush: () => void\n): void {\n record._dirty = true;\n if (record._scheduled) {\n return;\n }\n\n record._scheduled = true;\n dirtySelectorRecords.add(record);\n\n if (hasPendingSelectorFlush) {\n return;\n }\n\n hasPendingSelectorFlush = true;\n enqueueRuntimeLane('derived', flush);\n}\n\nexport function takeDirtySelectorRecords<T extends DirtySelectorRecord>(): T[] {\n hasPendingSelectorFlush = false;\n\n if (dirtySelectorRecords.size === 0) {\n return [];\n }\n\n const pending = Array.from(dirtySelectorRecords);\n dirtySelectorRecords.clear();\n return pending as T[];\n}\n"],"mappings":";;AAOA,MAAM,uCAAuB,IAAI,IAAyB;AAC1D,IAAI,0BAA0B;AAE9B,SAAgB,wBACd,QACA,OACM;CACN,OAAO,SAAS;CAChB,IAAI,OAAO,YACT;CAGF,OAAO,aAAa;CACpB,qBAAqB,IAAI,MAAM;CAE/B,IAAI,yBACF;CAGF,0BAA0B;CAC1B,mBAAmB,WAAW,KAAK;AACrC;AAEA,SAAgB,2BAA+D;CAC7E,0BAA0B;CAE1B,IAAI,qBAAqB,SAAS,GAChC,OAAO,CAAC;CAGV,MAAM,UAAU,MAAM,KAAK,oBAAoB;CAC/C,qBAAqB,MAAM;CAC3B,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"selector.d.ts","names":[],"sources":["../../src/runtime/selector.ts"],"mappings":";UA6BiB,QAAA;EAAA,CACd,SAAA,EAAW,CAAC;AAAA;AAAA,KAOV,cAAA;EACH,cAAA,CAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC;AAAA;AAAA,iBA0dX,QAAA,IACd,MAAA,QAAc,CAAA,EACd,MAAA,GAAQ,cAAA,CAAe,CAAA,IACtB,QAAA,CAAS,CAAA"}
1
+ {"version":3,"file":"selector.d.ts","names":[],"sources":["../../src/runtime/selector.ts"],"mappings":";UAgCiB,QAAA;EAAA,CACd,SAAA,EAAW,CAAC;AAAA;AAAA,KAOV,cAAA;EACH,cAAA,CAAe,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC;AAAA;AAAA,iBAicX,QAAA,IACd,MAAA,QAAc,CAAA,EACd,MAAA,GAAQ,cAAA,CAAe,CAAA,IACtB,QAAA,CAAS,CAAA"}
@@ -1,13 +1,11 @@
1
1
  import { getPerfMetricsStore, incrementPerfMetric } from "./perf-metrics.js";
2
- import { enqueueRuntimeLane } from "./access.js";
3
2
  import { clearDerivedDependencySubscriptions, markReactivePropsDirtySource, markReadableDerivedSubscribersDirty, markReadableUsage, notifyReadableReaders, recordReadableRead, syncDerivedDependencySubscriptions, withDerivedReadTracking } from "./readable.js";
4
3
  import { claimHookIndex, getCurrentInstance } from "./component-scope.js";
5
4
  import "./component.js";
5
+ import { markDirtySelectorRecord, takeDirtySelectorRecords } from "./selector-store.js";
6
6
  //#region src/runtime/selector.ts
7
7
  const selectorCells = /* @__PURE__ */ new WeakMap();
8
8
  const selectorRecords = /* @__PURE__ */ new WeakMap();
9
- const dirtySelectorRecords = /* @__PURE__ */ new Set();
10
- let hasPendingSelectorFlush = false;
11
9
  function getSelectorStore(instance) {
12
10
  let store = selectorCells.get(instance);
13
11
  if (!store) {
@@ -16,24 +14,11 @@ function getSelectorStore(instance) {
16
14
  }
17
15
  return store;
18
16
  }
19
- function scheduleSelectorFlush() {
20
- if (hasPendingSelectorFlush) return;
21
- hasPendingSelectorFlush = true;
22
- enqueueRuntimeLane("derived", flushDirtySelectorRecords);
23
- }
24
17
  function markSelectorRecordDirty(record) {
25
- record._dirty = true;
26
- if (record._scheduled) return;
27
- record._scheduled = true;
28
- dirtySelectorRecords.add(record);
29
- scheduleSelectorFlush();
18
+ markDirtySelectorRecord(record, flushDirtySelectorRecords);
30
19
  }
31
20
  function flushDirtySelectorRecords() {
32
- hasPendingSelectorFlush = false;
33
- if (dirtySelectorRecords.size === 0) return;
34
- const pending = Array.from(dirtySelectorRecords);
35
- dirtySelectorRecords.clear();
36
- for (const record of pending) {
21
+ for (const record of takeDirtySelectorRecords()) {
37
22
  record._scheduled = false;
38
23
  if (!record._dirty) continue;
39
24
  recomputeSelectorSourceRecord(record, true);
@@ -1 +1 @@
1
- {"version":3,"file":"selector.js","names":[],"sources":["../../src/runtime/selector.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { enqueueRuntimeLane } from './access';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReadableUsage,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n withDerivedReadTracking,\n type DerivedSubscriber,\n type ReadableSource,\n} from './readable';\nimport { getPerfMetricsStore, incrementPerfMetric } from './perf-metrics';\n\ntype PrimitiveKey =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | null\n | undefined;\n\nexport interface Selector<T> {\n (candidate: T): boolean;\n}\n\ninterface SelectorCandidateSource<T> extends ReadableSource<boolean> {\n _candidate: T;\n}\n\ntype SelectorEquals<T> = {\n bivarianceHack(a: T, b: T): boolean;\n}['bivarianceHack'];\n\ninterface SelectorLane<T> {\n _record: SelectorSourceRecord<T>;\n _equals: SelectorEquals<T>;\n _bindingCount: number;\n _primitiveCandidates: Map<PrimitiveKey, SelectorCandidateSource<T>>;\n _objectCandidates: WeakMap<object, SelectorCandidateSource<T>>;\n _objectCandidateSources: Set<SelectorCandidateSource<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorSourceRecord<T> extends DerivedSubscriber {\n _source: () => T;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _lanes: Map<SelectorEquals<T>, SelectorLane<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorHook<T> extends Selector<T> {\n _owner: ComponentInstance;\n _hookIndex: number;\n _source: () => T;\n _equals: SelectorEquals<T>;\n _record: SelectorSourceRecord<T> | null;\n _lane: SelectorLane<T> | null;\n _cleanup(): void;\n}\n\nconst selectorCells = new WeakMap<\n ComponentInstance,\n Map<number, SelectorHook<unknown>>\n>();\nconst selectorRecords = new WeakMap<\n ReadableSource<unknown>,\n SelectorSourceRecord<unknown>\n>();\nconst dirtySelectorRecords = new Set<SelectorSourceRecord<unknown>>();\nlet hasPendingSelectorFlush = false;\n\nfunction getSelectorStore(\n instance: ComponentInstance\n): Map<number, SelectorHook<unknown>> {\n let store = selectorCells.get(instance);\n if (!store) {\n store = new Map();\n selectorCells.set(instance, store);\n }\n return store;\n}\n\nfunction scheduleSelectorFlush(): void {\n if (hasPendingSelectorFlush) {\n return;\n }\n\n hasPendingSelectorFlush = true;\n enqueueRuntimeLane('derived', flushDirtySelectorRecords);\n}\n\nfunction markSelectorRecordDirty(record: SelectorSourceRecord<unknown>): void {\n record._dirty = true;\n if (record._scheduled) {\n return;\n }\n\n record._scheduled = true;\n dirtySelectorRecords.add(record);\n scheduleSelectorFlush();\n}\n\nfunction flushDirtySelectorRecords(): void {\n hasPendingSelectorFlush = false;\n\n if (dirtySelectorRecords.size === 0) {\n return;\n }\n\n const pending = Array.from(dirtySelectorRecords);\n dirtySelectorRecords.clear();\n\n for (const record of pending) {\n record._scheduled = false;\n if (!record._dirty) {\n continue;\n }\n recomputeSelectorSourceRecord(record, true);\n }\n}\n\nfunction isObjectCandidate(value: unknown): value is object {\n return (\n (typeof value === 'object' && value !== null) || typeof value === 'function'\n );\n}\n\nfunction isDefaultSelectorEquals<T>(equals: SelectorEquals<T>): boolean {\n return equals === Object.is;\n}\n\nfunction createCandidateSource<T>(candidate: T): SelectorCandidateSource<T> {\n const source = (() => false) as SelectorCandidateSource<T>;\n source._candidate = candidate;\n return source;\n}\n\nfunction getCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> {\n if (isObjectCandidate(candidate)) {\n const cached = lane._objectCandidates.get(candidate);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._objectCandidates.set(candidate, created);\n lane._objectCandidateSources.add(created);\n return created;\n }\n\n const key = candidate as PrimitiveKey;\n const cached = lane._primitiveCandidates.get(key);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._primitiveCandidates.set(key, created);\n return created;\n}\n\nfunction peekCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> | undefined {\n if (isObjectCandidate(candidate)) {\n return lane._objectCandidates.get(candidate);\n }\n return lane._primitiveCandidates.get(candidate as PrimitiveKey);\n}\n\nfunction getSelectorSourceRecord<T>(source: () => T): SelectorSourceRecord<T> {\n const cached = selectorRecords.get(source);\n if (cached) {\n return cached as SelectorSourceRecord<T>;\n }\n\n const record = createSelectorSourceRecord(source);\n selectorRecords.set(source, record as SelectorSourceRecord<unknown>);\n return record;\n}\n\nfunction createSelectorSourceRecord<T>(\n source: () => T\n): SelectorSourceRecord<T> {\n let record!: SelectorSourceRecord<T>;\n\n record = {\n _source: source,\n _value: undefined as T,\n _hasValue: false,\n _dirty: true,\n _scheduled: false,\n _evaluating: false,\n _sources: new Set(),\n _lanes: new Map(),\n _markDirty: () => {\n markSelectorRecordDirty(record as SelectorSourceRecord<unknown>);\n },\n _cleanup: () => {\n record._scheduled = false;\n record._dirty = false;\n record._hasValue = false;\n record._evaluating = false;\n record._pendingDependencySources = undefined;\n clearDerivedDependencySubscriptions(record, record._sources);\n record._lanes.clear();\n selectorRecords.delete(source as ReadableSource<unknown>);\n },\n };\n\n return record;\n}\n\nfunction getSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const cached = record._lanes.get(equals);\n if (cached) {\n return cached;\n }\n\n const lane = createSelectorLane(record, equals);\n record._lanes.set(equals, lane);\n return lane;\n}\n\nfunction createSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const lane: SelectorLane<T> = {\n _record: record,\n _equals: equals,\n _bindingCount: 0,\n _primitiveCandidates: new Map(),\n _objectCandidates: new WeakMap(),\n _objectCandidateSources: new Set(),\n _cleanup: () => {\n for (const sourceRef of lane._primitiveCandidates.values()) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n for (const sourceRef of lane._objectCandidateSources) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n lane._primitiveCandidates.clear();\n lane._objectCandidates = new WeakMap();\n lane._objectCandidateSources.clear();\n },\n };\n\n return lane;\n}\n\nfunction notifySelectorSource(source: SelectorCandidateSource<unknown>): void {\n incrementPerfMetric('selectorInvalidations');\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n}\n\nfunction notifyAllSelectorSources<T>(lane: SelectorLane<T>): void {\n for (const source of lane._primitiveCandidates.values()) {\n notifySelectorSource(source);\n }\n for (const source of lane._objectCandidateSources) {\n notifySelectorSource(source);\n }\n}\n\nfunction notifySelectorLaneValueChange<T>(\n lane: SelectorLane<T>,\n prevValue: T,\n nextValue: T\n): void {\n if (!lane._bindingCount) {\n return;\n }\n\n if (!isDefaultSelectorEquals(lane._equals)) {\n if (lane._equals(prevValue, nextValue)) {\n return;\n }\n notifyAllSelectorSources(lane);\n return;\n }\n\n if (!Object.is(prevValue, nextValue)) {\n // Only notify candidate sources that were actually materialized by a read.\n // Using getCandidateSource here would create-on-miss and leak a candidate\n // source for every distinct value the source ever passed through, even\n // those no component reads. Peek instead so the candidate cache stays\n // bounded to values that components actually compare against.\n const prevSource = peekCandidateSource(lane, prevValue);\n if (prevSource) {\n notifySelectorSource(prevSource);\n }\n const nextSource = peekCandidateSource(lane, nextValue);\n if (nextSource) {\n notifySelectorSource(nextSource);\n }\n }\n}\n\nfunction recomputeSelectorSourceRecord<T>(\n record: SelectorSourceRecord<T>,\n notifyDownstream: boolean\n): T {\n if (!record._dirty && record._hasValue) {\n return record._value;\n }\n\n if (record._evaluating) {\n throw new Error('selector() cannot read itself recursively');\n }\n\n record._evaluating = true;\n record._dirty = false;\n record._pendingDependencySources = new Set();\n\n const prevSources = record._sources;\n const hadValue = record._hasValue;\n const prevValue = record._value;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(record, record._source);\n } catch (error) {\n record._dirty = true;\n record._pendingDependencySources = undefined;\n throw error;\n } finally {\n record._evaluating = false;\n }\n\n const nextSources = record._pendingDependencySources ?? new Set();\n record._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(record, prevSources, nextSources);\n record._sources = nextSources;\n\n const valueChanged = !record._hasValue || !Object.is(prevValue, nextValue);\n record._hasValue = true;\n record._value = nextValue;\n\n if (valueChanged && notifyDownstream && hadValue) {\n for (const lane of Array.from(record._lanes.values())) {\n notifySelectorLaneValueChange(lane, prevValue, nextValue);\n }\n }\n\n return record._value;\n}\n\nfunction attachSelectorHookBinding<T>(\n hook: SelectorHook<T>,\n source: () => T,\n equals: SelectorEquals<T>\n): void {\n const record = getSelectorSourceRecord(source);\n const lane = getSelectorLane(record, equals);\n\n hook._source = source;\n hook._equals = equals;\n hook._record = record;\n hook._lane = lane;\n lane._bindingCount += 1;\n}\n\nfunction detachSelectorHookBinding<T>(hook: SelectorHook<T>): void {\n const record = hook._record;\n const lane = hook._lane;\n\n hook._record = null;\n hook._lane = null;\n\n if (!record || !lane) {\n return;\n }\n\n if (lane._bindingCount > 0) {\n lane._bindingCount -= 1;\n }\n\n if (lane._bindingCount > 0) {\n return;\n }\n\n lane._cleanup();\n record._lanes.delete(lane._equals);\n\n if (record._lanes.size === 0) {\n record._cleanup();\n }\n}\n\nfunction ensureSelectorHookBinding<T>(\n hook: SelectorHook<T>\n): SelectorSourceRecord<T> {\n const record = hook._record;\n const lane = hook._lane;\n\n if (\n record &&\n lane &&\n lane._bindingCount > 0 &&\n record._lanes.get(hook._equals) === lane &&\n record._source === hook._source\n ) {\n return record;\n }\n\n if (hook._record || hook._lane) {\n detachSelectorHookBinding(hook);\n }\n\n attachSelectorHookBinding(hook, hook._source, hook._equals);\n return hook._record!;\n}\n\nfunction createSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const hook = function selectorPredicate(candidate: T): boolean {\n const selectorHook = hook as SelectorHook<T>;\n const record = ensureSelectorHookBinding(selectorHook);\n const lane = selectorHook._lane;\n if (!lane) {\n throw new Error('selector() binding could not be established.');\n }\n\n const sourceRef = getCandidateSource(lane, candidate);\n recordReadableRead(sourceRef);\n\n const perfMetricsStore = getPerfMetricsStore();\n if (perfMetricsStore) {\n perfMetricsStore.selectorCandidateReads += 1;\n }\n\n const current =\n record._dirty || !record._hasValue\n ? recomputeSelectorSourceRecord(record, record._scheduled)\n : record._value;\n\n return lane._equals(current, candidate);\n } as SelectorHook<T>;\n\n hook._owner = instance;\n hook._hookIndex = hookIndex;\n hook._source = source;\n hook._equals = equals;\n hook._record = null;\n hook._lane = null;\n hook._cleanup = () => {\n detachSelectorHookBinding(hook);\n };\n\n attachSelectorHookBinding(hook, source, equals);\n\n (instance.cleanupFns ??= []).push(() => {\n hook._cleanup();\n selectorCells.get(instance)?.delete(hookIndex);\n });\n\n return hook;\n}\n\nfunction getOrCreateSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const store = getSelectorStore(instance);\n const existing = store.get(hookIndex) as SelectorHook<T> | undefined;\n if (existing) {\n if (existing._source !== source || existing._equals !== equals) {\n detachSelectorHookBinding(existing);\n attachSelectorHookBinding(existing, source, equals);\n } else {\n ensureSelectorHookBinding(existing);\n }\n return existing;\n }\n\n const created = createSelectorHook(instance, hookIndex, source, equals);\n store.set(hookIndex, created as unknown as SelectorHook<unknown>);\n return created;\n}\n\nexport function selector<T>(\n source: () => T,\n equals: SelectorEquals<T> = Object.is\n): Selector<T> {\n markReadableUsage(source);\n\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'selector() can only be called during component render execution. ' +\n 'Move selector() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'selector');\n const hook = getOrCreateSelectorHook(instance, hookIndex, source, equals);\n if (!hook._record) {\n throw new Error('selector() record binding was not established.');\n }\n\n if (!hook._record._hasValue) {\n // Initialize the shared source once so downstream selectors can subscribe,\n // but do not consume a pending dirty state on later renders.\n recomputeSelectorSourceRecord(hook._record, false);\n }\n return hook;\n}\n"],"mappings":";;;;;;AA0EA,MAAM,gCAAgB,IAAI,QAGxB;AACF,MAAM,kCAAkB,IAAI,QAG1B;AACF,MAAM,uCAAuB,IAAI,IAAmC;AACpE,IAAI,0BAA0B;AAE9B,SAAS,iBACP,UACoC;CACpC,IAAI,QAAQ,cAAc,IAAI,QAAQ;CACtC,IAAI,CAAC,OAAO;EACV,wBAAQ,IAAI,IAAI;EAChB,cAAc,IAAI,UAAU,KAAK;CACnC;CACA,OAAO;AACT;AAEA,SAAS,wBAA8B;CACrC,IAAI,yBACF;CAGF,0BAA0B;CAC1B,mBAAmB,WAAW,yBAAyB;AACzD;AAEA,SAAS,wBAAwB,QAA6C;CAC5E,OAAO,SAAS;CAChB,IAAI,OAAO,YACT;CAGF,OAAO,aAAa;CACpB,qBAAqB,IAAI,MAAM;CAC/B,sBAAsB;AACxB;AAEA,SAAS,4BAAkC;CACzC,0BAA0B;CAE1B,IAAI,qBAAqB,SAAS,GAChC;CAGF,MAAM,UAAU,MAAM,KAAK,oBAAoB;CAC/C,qBAAqB,MAAM;CAE3B,KAAK,MAAM,UAAU,SAAS;EAC5B,OAAO,aAAa;EACpB,IAAI,CAAC,OAAO,QACV;EAEF,8BAA8B,QAAQ,IAAI;CAC5C;AACF;AAEA,SAAS,kBAAkB,OAAiC;CAC1D,OACG,OAAO,UAAU,YAAY,UAAU,QAAS,OAAO,UAAU;AAEtE;AAEA,SAAS,wBAA2B,QAAoC;CACtE,OAAO,WAAW,OAAO;AAC3B;AAEA,SAAS,sBAAyB,WAA0C;CAC1E,MAAM,gBAAgB;CACtB,OAAO,aAAa;CACpB,OAAO;AACT;AAEA,SAAS,mBACP,MACA,WAC4B;CAC5B,IAAI,kBAAkB,SAAS,GAAG;EAChC,MAAM,SAAS,KAAK,kBAAkB,IAAI,SAAS;EACnD,IAAI,QACF,OAAO;EAGT,MAAM,UAAU,sBAAsB,SAAS;EAC/C,KAAK,kBAAkB,IAAI,WAAW,OAAO;EAC7C,KAAK,wBAAwB,IAAI,OAAO;EACxC,OAAO;CACT;CAEA,MAAM,MAAM;CACZ,MAAM,SAAS,KAAK,qBAAqB,IAAI,GAAG;CAChD,IAAI,QACF,OAAO;CAGT,MAAM,UAAU,sBAAsB,SAAS;CAC/C,KAAK,qBAAqB,IAAI,KAAK,OAAO;CAC1C,OAAO;AACT;AAEA,SAAS,oBACP,MACA,WACwC;CACxC,IAAI,kBAAkB,SAAS,GAC7B,OAAO,KAAK,kBAAkB,IAAI,SAAS;CAE7C,OAAO,KAAK,qBAAqB,IAAI,SAAyB;AAChE;AAEA,SAAS,wBAA2B,QAA0C;CAC5E,MAAM,SAAS,gBAAgB,IAAI,MAAM;CACzC,IAAI,QACF,OAAO;CAGT,MAAM,SAAS,2BAA2B,MAAM;CAChD,gBAAgB,IAAI,QAAQ,MAAuC;CACnE,OAAO;AACT;AAEA,SAAS,2BACP,QACyB;CACzB,IAAI;CAEJ,SAAS;EACP,SAAS;EACT,QAAQ;EACR,WAAW;EACX,QAAQ;EACR,YAAY;EACZ,aAAa;EACb,0BAAU,IAAI,IAAI;EAClB,wBAAQ,IAAI,IAAI;EAChB,kBAAkB;GAChB,wBAAwB,MAAuC;EACjE;EACA,gBAAgB;GACd,OAAO,aAAa;GACpB,OAAO,SAAS;GAChB,OAAO,YAAY;GACnB,OAAO,cAAc;GACrB,OAAO,4BAA4B;GACnC,oCAAoC,QAAQ,OAAO,QAAQ;GAC3D,OAAO,OAAO,MAAM;GACpB,gBAAgB,OAAO,MAAiC;EAC1D;CACF;CAEA,OAAO;AACT;AAEA,SAAS,gBACP,QACA,QACiB;CACjB,MAAM,SAAS,OAAO,OAAO,IAAI,MAAM;CACvC,IAAI,QACF,OAAO;CAGT,MAAM,OAAO,mBAAmB,QAAQ,MAAM;CAC9C,OAAO,OAAO,IAAI,QAAQ,IAAI;CAC9B,OAAO;AACT;AAEA,SAAS,mBACP,QACA,QACiB;CACjB,MAAM,OAAwB;EAC5B,SAAS;EACT,SAAS;EACT,eAAe;EACf,sCAAsB,IAAI,IAAI;EAC9B,mCAAmB,IAAI,QAAQ;EAC/B,yCAAyB,IAAI,IAAI;EACjC,gBAAgB;GACd,KAAK,MAAM,aAAa,KAAK,qBAAqB,OAAO,GAAG;IAC1D,UAAU,UAAU,MAAM;IAC1B,UAAU,qBAAqB,MAAM;GACvC;GACA,KAAK,MAAM,aAAa,KAAK,yBAAyB;IACpD,UAAU,UAAU,MAAM;IAC1B,UAAU,qBAAqB,MAAM;GACvC;GACA,KAAK,qBAAqB,MAAM;GAChC,KAAK,oCAAoB,IAAI,QAAQ;GACrC,KAAK,wBAAwB,MAAM;EACrC;CACF;CAEA,OAAO;AACT;AAEA,SAAS,qBAAqB,QAAgD;CAC5E,oBAAoB,uBAAuB;CAC3C,oCAAoC,MAAM;CAC1C,6BAA6B,MAAM;CACnC,sBAAsB,MAAM;AAC9B;AAEA,SAAS,yBAA4B,MAA6B;CAChE,KAAK,MAAM,UAAU,KAAK,qBAAqB,OAAO,GACpD,qBAAqB,MAAM;CAE7B,KAAK,MAAM,UAAU,KAAK,yBACxB,qBAAqB,MAAM;AAE/B;AAEA,SAAS,8BACP,MACA,WACA,WACM;CACN,IAAI,CAAC,KAAK,eACR;CAGF,IAAI,CAAC,wBAAwB,KAAK,OAAO,GAAG;EAC1C,IAAI,KAAK,QAAQ,WAAW,SAAS,GACnC;EAEF,yBAAyB,IAAI;EAC7B;CACF;CAEA,IAAI,CAAC,OAAO,GAAG,WAAW,SAAS,GAAG;EAMpC,MAAM,aAAa,oBAAoB,MAAM,SAAS;EACtD,IAAI,YACF,qBAAqB,UAAU;EAEjC,MAAM,aAAa,oBAAoB,MAAM,SAAS;EACtD,IAAI,YACF,qBAAqB,UAAU;CAEnC;AACF;AAEA,SAAS,8BACP,QACA,kBACG;CACH,IAAI,CAAC,OAAO,UAAU,OAAO,WAC3B,OAAO,OAAO;CAGhB,IAAI,OAAO,aACT,MAAM,IAAI,MAAM,2CAA2C;CAG7D,OAAO,cAAc;CACrB,OAAO,SAAS;CAChB,OAAO,4CAA4B,IAAI,IAAI;CAE3C,MAAM,cAAc,OAAO;CAC3B,MAAM,WAAW,OAAO;CACxB,MAAM,YAAY,OAAO;CACzB,IAAI;CAEJ,IAAI;EACF,YAAY,wBAAwB,QAAQ,OAAO,OAAO;CAC5D,SAAS,OAAO;EACd,OAAO,SAAS;EAChB,OAAO,4BAA4B;EACnC,MAAM;CACR,UAAU;EACR,OAAO,cAAc;CACvB;CAEA,MAAM,cAAc,OAAO,6CAA6B,IAAI,IAAI;CAChE,OAAO,4BAA4B;CACnC,mCAAmC,QAAQ,aAAa,WAAW;CACnE,OAAO,WAAW;CAElB,MAAM,eAAe,CAAC,OAAO,aAAa,CAAC,OAAO,GAAG,WAAW,SAAS;CACzE,OAAO,YAAY;CACnB,OAAO,SAAS;CAEhB,IAAI,gBAAgB,oBAAoB,UACtC,KAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,OAAO,OAAO,CAAC,GAClD,8BAA8B,MAAM,WAAW,SAAS;CAI5D,OAAO,OAAO;AAChB;AAEA,SAAS,0BACP,MACA,QACA,QACM;CACN,MAAM,SAAS,wBAAwB,MAAM;CAC7C,MAAM,OAAO,gBAAgB,QAAQ,MAAM;CAE3C,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,QAAQ;CACb,KAAK,iBAAiB;AACxB;AAEA,SAAS,0BAA6B,MAA6B;CACjE,MAAM,SAAS,KAAK;CACpB,MAAM,OAAO,KAAK;CAElB,KAAK,UAAU;CACf,KAAK,QAAQ;CAEb,IAAI,CAAC,UAAU,CAAC,MACd;CAGF,IAAI,KAAK,gBAAgB,GACvB,KAAK,iBAAiB;CAGxB,IAAI,KAAK,gBAAgB,GACvB;CAGF,KAAK,SAAS;CACd,OAAO,OAAO,OAAO,KAAK,OAAO;CAEjC,IAAI,OAAO,OAAO,SAAS,GACzB,OAAO,SAAS;AAEpB;AAEA,SAAS,0BACP,MACyB;CACzB,MAAM,SAAS,KAAK;CACpB,MAAM,OAAO,KAAK;CAElB,IACE,UACA,QACA,KAAK,gBAAgB,KACrB,OAAO,OAAO,IAAI,KAAK,OAAO,MAAM,QACpC,OAAO,YAAY,KAAK,SAExB,OAAO;CAGT,IAAI,KAAK,WAAW,KAAK,OACvB,0BAA0B,IAAI;CAGhC,0BAA0B,MAAM,KAAK,SAAS,KAAK,OAAO;CAC1D,OAAO,KAAK;AACd;AAEA,SAAS,mBACP,UACA,WACA,QACA,QACiB;CACjB,MAAM,OAAO,SAAS,kBAAkB,WAAuB;EAC7D,MAAM,eAAe;EACrB,MAAM,SAAS,0BAA0B,YAAY;EACrD,MAAM,OAAO,aAAa;EAC1B,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,8CAA8C;EAIhE,mBADkB,mBAAmB,MAAM,SACxB,CAAS;EAE5B,MAAM,mBAAmB,oBAAoB;EAC7C,IAAI,kBACF,iBAAiB,0BAA0B;EAG7C,MAAM,UACJ,OAAO,UAAU,CAAC,OAAO,YACrB,8BAA8B,QAAQ,OAAO,UAAU,IACvD,OAAO;EAEb,OAAO,KAAK,QAAQ,SAAS,SAAS;CACxC;CAEA,KAAK,SAAS;CACd,KAAK,aAAa;CAClB,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,UAAU;CACf,KAAK,QAAQ;CACb,KAAK,iBAAiB;EACpB,0BAA0B,IAAI;CAChC;CAEA,0BAA0B,MAAM,QAAQ,MAAM;CAE9C,CAAC,SAAS,eAAe,CAAC,EAAA,CAAG,WAAW;EACtC,KAAK,SAAS;EACd,cAAc,IAAI,QAAQ,CAAC,EAAE,OAAO,SAAS;CAC/C,CAAC;CAED,OAAO;AACT;AAEA,SAAS,wBACP,UACA,WACA,QACA,QACiB;CACjB,MAAM,QAAQ,iBAAiB,QAAQ;CACvC,MAAM,WAAW,MAAM,IAAI,SAAS;CACpC,IAAI,UAAU;EACZ,IAAI,SAAS,YAAY,UAAU,SAAS,YAAY,QAAQ;GAC9D,0BAA0B,QAAQ;GAClC,0BAA0B,UAAU,QAAQ,MAAM;EACpD,OACE,0BAA0B,QAAQ;EAEpC,OAAO;CACT;CAEA,MAAM,UAAU,mBAAmB,UAAU,WAAW,QAAQ,MAAM;CACtE,MAAM,IAAI,WAAW,OAA2C;CAChE,OAAO;AACT;AAEA,SAAgB,SACd,QACA,SAA4B,OAAO,IACtB;CACb,kBAAkB,MAAM;CAExB,MAAM,WAAW,mBAAmB;CACpC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,qIAEF;CAIF,MAAM,OAAO,wBAAwB,UADnB,eAAe,UAAU,UACI,GAAW,QAAQ,MAAM;CACxE,IAAI,CAAC,KAAK,SACR,MAAM,IAAI,MAAM,gDAAgD;CAGlE,IAAI,CAAC,KAAK,QAAQ,WAGhB,8BAA8B,KAAK,SAAS,KAAK;CAEnD,OAAO;AACT"}
1
+ {"version":3,"file":"selector.js","names":[],"sources":["../../src/runtime/selector.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReadableUsage,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n withDerivedReadTracking,\n type DerivedSubscriber,\n type ReadableSource,\n} from './readable';\nimport { getPerfMetricsStore, incrementPerfMetric } from './perf-metrics';\nimport {\n markDirtySelectorRecord,\n takeDirtySelectorRecords,\n} from './selector-store';\n\ntype PrimitiveKey =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | null\n | undefined;\n\nexport interface Selector<T> {\n (candidate: T): boolean;\n}\n\ninterface SelectorCandidateSource<T> extends ReadableSource<boolean> {\n _candidate: T;\n}\n\ntype SelectorEquals<T> = {\n bivarianceHack(a: T, b: T): boolean;\n}['bivarianceHack'];\n\ninterface SelectorLane<T> {\n _record: SelectorSourceRecord<T>;\n _equals: SelectorEquals<T>;\n _bindingCount: number;\n _primitiveCandidates: Map<PrimitiveKey, SelectorCandidateSource<T>>;\n _objectCandidates: WeakMap<object, SelectorCandidateSource<T>>;\n _objectCandidateSources: Set<SelectorCandidateSource<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorSourceRecord<T> extends DerivedSubscriber {\n _source: () => T;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _lanes: Map<SelectorEquals<T>, SelectorLane<T>>;\n _cleanup(): void;\n}\n\ninterface SelectorHook<T> extends Selector<T> {\n _owner: ComponentInstance;\n _hookIndex: number;\n _source: () => T;\n _equals: SelectorEquals<T>;\n _record: SelectorSourceRecord<T> | null;\n _lane: SelectorLane<T> | null;\n _cleanup(): void;\n}\n\nconst selectorCells = new WeakMap<\n ComponentInstance,\n Map<number, SelectorHook<unknown>>\n>();\nconst selectorRecords = new WeakMap<\n ReadableSource<unknown>,\n SelectorSourceRecord<unknown>\n>();\n\nfunction getSelectorStore(\n instance: ComponentInstance\n): Map<number, SelectorHook<unknown>> {\n let store = selectorCells.get(instance);\n if (!store) {\n store = new Map();\n selectorCells.set(instance, store);\n }\n return store;\n}\n\nfunction markSelectorRecordDirty(record: SelectorSourceRecord<unknown>): void {\n markDirtySelectorRecord(record, flushDirtySelectorRecords);\n}\n\nfunction flushDirtySelectorRecords(): void {\n for (const record of takeDirtySelectorRecords<\n SelectorSourceRecord<unknown>\n >()) {\n record._scheduled = false;\n if (!record._dirty) {\n continue;\n }\n recomputeSelectorSourceRecord(record, true);\n }\n}\n\nfunction isObjectCandidate(value: unknown): value is object {\n return (\n (typeof value === 'object' && value !== null) || typeof value === 'function'\n );\n}\n\nfunction isDefaultSelectorEquals<T>(equals: SelectorEquals<T>): boolean {\n return equals === Object.is;\n}\n\nfunction createCandidateSource<T>(candidate: T): SelectorCandidateSource<T> {\n const source = (() => false) as SelectorCandidateSource<T>;\n source._candidate = candidate;\n return source;\n}\n\nfunction getCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> {\n if (isObjectCandidate(candidate)) {\n const cached = lane._objectCandidates.get(candidate);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._objectCandidates.set(candidate, created);\n lane._objectCandidateSources.add(created);\n return created;\n }\n\n const key = candidate as PrimitiveKey;\n const cached = lane._primitiveCandidates.get(key);\n if (cached) {\n return cached;\n }\n\n const created = createCandidateSource(candidate);\n lane._primitiveCandidates.set(key, created);\n return created;\n}\n\nfunction peekCandidateSource<T>(\n lane: SelectorLane<T>,\n candidate: T\n): SelectorCandidateSource<T> | undefined {\n if (isObjectCandidate(candidate)) {\n return lane._objectCandidates.get(candidate);\n }\n return lane._primitiveCandidates.get(candidate as PrimitiveKey);\n}\n\nfunction getSelectorSourceRecord<T>(source: () => T): SelectorSourceRecord<T> {\n const cached = selectorRecords.get(source);\n if (cached) {\n return cached as SelectorSourceRecord<T>;\n }\n\n const record = createSelectorSourceRecord(source);\n selectorRecords.set(source, record as SelectorSourceRecord<unknown>);\n return record;\n}\n\nfunction createSelectorSourceRecord<T>(\n source: () => T\n): SelectorSourceRecord<T> {\n let record!: SelectorSourceRecord<T>;\n\n record = {\n _source: source,\n _value: undefined as T,\n _hasValue: false,\n _dirty: true,\n _scheduled: false,\n _evaluating: false,\n _sources: new Set(),\n _lanes: new Map(),\n _markDirty: () => {\n markSelectorRecordDirty(record as SelectorSourceRecord<unknown>);\n },\n _cleanup: () => {\n record._scheduled = false;\n record._dirty = false;\n record._hasValue = false;\n record._evaluating = false;\n record._pendingDependencySources = undefined;\n clearDerivedDependencySubscriptions(record, record._sources);\n record._lanes.clear();\n selectorRecords.delete(source as ReadableSource<unknown>);\n },\n };\n\n return record;\n}\n\nfunction getSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const cached = record._lanes.get(equals);\n if (cached) {\n return cached;\n }\n\n const lane = createSelectorLane(record, equals);\n record._lanes.set(equals, lane);\n return lane;\n}\n\nfunction createSelectorLane<T>(\n record: SelectorSourceRecord<T>,\n equals: SelectorEquals<T>\n): SelectorLane<T> {\n const lane: SelectorLane<T> = {\n _record: record,\n _equals: equals,\n _bindingCount: 0,\n _primitiveCandidates: new Map(),\n _objectCandidates: new WeakMap(),\n _objectCandidateSources: new Set(),\n _cleanup: () => {\n for (const sourceRef of lane._primitiveCandidates.values()) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n for (const sourceRef of lane._objectCandidateSources) {\n sourceRef._readers?.clear();\n sourceRef._derivedSubscribers?.clear();\n }\n lane._primitiveCandidates.clear();\n lane._objectCandidates = new WeakMap();\n lane._objectCandidateSources.clear();\n },\n };\n\n return lane;\n}\n\nfunction notifySelectorSource(source: SelectorCandidateSource<unknown>): void {\n incrementPerfMetric('selectorInvalidations');\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n}\n\nfunction notifyAllSelectorSources<T>(lane: SelectorLane<T>): void {\n for (const source of lane._primitiveCandidates.values()) {\n notifySelectorSource(source);\n }\n for (const source of lane._objectCandidateSources) {\n notifySelectorSource(source);\n }\n}\n\nfunction notifySelectorLaneValueChange<T>(\n lane: SelectorLane<T>,\n prevValue: T,\n nextValue: T\n): void {\n if (!lane._bindingCount) {\n return;\n }\n\n if (!isDefaultSelectorEquals(lane._equals)) {\n if (lane._equals(prevValue, nextValue)) {\n return;\n }\n notifyAllSelectorSources(lane);\n return;\n }\n\n if (!Object.is(prevValue, nextValue)) {\n // Only notify candidate sources that were actually materialized by a read.\n // Using getCandidateSource here would create-on-miss and leak a candidate\n // source for every distinct value the source ever passed through, even\n // those no component reads. Peek instead so the candidate cache stays\n // bounded to values that components actually compare against.\n const prevSource = peekCandidateSource(lane, prevValue);\n if (prevSource) {\n notifySelectorSource(prevSource);\n }\n const nextSource = peekCandidateSource(lane, nextValue);\n if (nextSource) {\n notifySelectorSource(nextSource);\n }\n }\n}\n\nfunction recomputeSelectorSourceRecord<T>(\n record: SelectorSourceRecord<T>,\n notifyDownstream: boolean\n): T {\n if (!record._dirty && record._hasValue) {\n return record._value;\n }\n\n if (record._evaluating) {\n throw new Error('selector() cannot read itself recursively');\n }\n\n record._evaluating = true;\n record._dirty = false;\n record._pendingDependencySources = new Set();\n\n const prevSources = record._sources;\n const hadValue = record._hasValue;\n const prevValue = record._value;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(record, record._source);\n } catch (error) {\n record._dirty = true;\n record._pendingDependencySources = undefined;\n throw error;\n } finally {\n record._evaluating = false;\n }\n\n const nextSources = record._pendingDependencySources ?? new Set();\n record._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(record, prevSources, nextSources);\n record._sources = nextSources;\n\n const valueChanged = !record._hasValue || !Object.is(prevValue, nextValue);\n record._hasValue = true;\n record._value = nextValue;\n\n if (valueChanged && notifyDownstream && hadValue) {\n for (const lane of Array.from(record._lanes.values())) {\n notifySelectorLaneValueChange(lane, prevValue, nextValue);\n }\n }\n\n return record._value;\n}\n\nfunction attachSelectorHookBinding<T>(\n hook: SelectorHook<T>,\n source: () => T,\n equals: SelectorEquals<T>\n): void {\n const record = getSelectorSourceRecord(source);\n const lane = getSelectorLane(record, equals);\n\n hook._source = source;\n hook._equals = equals;\n hook._record = record;\n hook._lane = lane;\n lane._bindingCount += 1;\n}\n\nfunction detachSelectorHookBinding<T>(hook: SelectorHook<T>): void {\n const record = hook._record;\n const lane = hook._lane;\n\n hook._record = null;\n hook._lane = null;\n\n if (!record || !lane) {\n return;\n }\n\n if (lane._bindingCount > 0) {\n lane._bindingCount -= 1;\n }\n\n if (lane._bindingCount > 0) {\n return;\n }\n\n lane._cleanup();\n record._lanes.delete(lane._equals);\n\n if (record._lanes.size === 0) {\n record._cleanup();\n }\n}\n\nfunction ensureSelectorHookBinding<T>(\n hook: SelectorHook<T>\n): SelectorSourceRecord<T> {\n const record = hook._record;\n const lane = hook._lane;\n\n if (\n record &&\n lane &&\n lane._bindingCount > 0 &&\n record._lanes.get(hook._equals) === lane &&\n record._source === hook._source\n ) {\n return record;\n }\n\n if (hook._record || hook._lane) {\n detachSelectorHookBinding(hook);\n }\n\n attachSelectorHookBinding(hook, hook._source, hook._equals);\n return hook._record!;\n}\n\nfunction createSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const hook = function selectorPredicate(candidate: T): boolean {\n const selectorHook = hook as SelectorHook<T>;\n const record = ensureSelectorHookBinding(selectorHook);\n const lane = selectorHook._lane;\n if (!lane) {\n throw new Error('selector() binding could not be established.');\n }\n\n const sourceRef = getCandidateSource(lane, candidate);\n recordReadableRead(sourceRef);\n\n const perfMetricsStore = getPerfMetricsStore();\n if (perfMetricsStore) {\n perfMetricsStore.selectorCandidateReads += 1;\n }\n\n const current =\n record._dirty || !record._hasValue\n ? recomputeSelectorSourceRecord(record, record._scheduled)\n : record._value;\n\n return lane._equals(current, candidate);\n } as SelectorHook<T>;\n\n hook._owner = instance;\n hook._hookIndex = hookIndex;\n hook._source = source;\n hook._equals = equals;\n hook._record = null;\n hook._lane = null;\n hook._cleanup = () => {\n detachSelectorHookBinding(hook);\n };\n\n attachSelectorHookBinding(hook, source, equals);\n\n (instance.cleanupFns ??= []).push(() => {\n hook._cleanup();\n selectorCells.get(instance)?.delete(hookIndex);\n });\n\n return hook;\n}\n\nfunction getOrCreateSelectorHook<T>(\n instance: ComponentInstance,\n hookIndex: number,\n source: () => T,\n equals: SelectorEquals<T>\n): SelectorHook<T> {\n const store = getSelectorStore(instance);\n const existing = store.get(hookIndex) as SelectorHook<T> | undefined;\n if (existing) {\n if (existing._source !== source || existing._equals !== equals) {\n detachSelectorHookBinding(existing);\n attachSelectorHookBinding(existing, source, equals);\n } else {\n ensureSelectorHookBinding(existing);\n }\n return existing;\n }\n\n const created = createSelectorHook(instance, hookIndex, source, equals);\n store.set(hookIndex, created as unknown as SelectorHook<unknown>);\n return created;\n}\n\nexport function selector<T>(\n source: () => T,\n equals: SelectorEquals<T> = Object.is\n): Selector<T> {\n markReadableUsage(source);\n\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'selector() can only be called during component render execution. ' +\n 'Move selector() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'selector');\n const hook = getOrCreateSelectorHook(instance, hookIndex, source, equals);\n if (!hook._record) {\n throw new Error('selector() record binding was not established.');\n }\n\n if (!hook._record._hasValue) {\n // Initialize the shared source once so downstream selectors can subscribe,\n // but do not consume a pending dirty state on later renders.\n recomputeSelectorSourceRecord(hook._record, false);\n }\n return hook;\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { addPerfDuration, incrementPerfMetric } from "../runtime/perf-metrics.js";
2
+ import "../runtime/index.js";
2
3
  import { resolveRouteDescriptor } from "./route-utils.js";
3
4
  import { resolveSsgData, resolveSsgRouteData, validateRoutes } from "./resolve-ssg-data.js";
4
5
  import { batchRenderRoutes } from "./batch-render.js";
@@ -1 +1 @@
1
- {"version":3,"file":"create-static-gen.js","names":[],"sources":["../../src/ssg/create-static-gen.ts"],"sourcesContent":["/**\n * Static Site Generation API\n *\n * Main orchestrator for batch rendering, file I/O, and metadata generation\n */\n\nimport type {\n RouteConfig,\n RouteRenderResult,\n SSGGenerateOptions,\n SSGMode,\n SSGOptions,\n SSGResult,\n} from './types';\nimport type { RouteRegistry } from '../common/router';\nimport {\n resolveSsgRouteData,\n resolveSsgData,\n validateRoutes,\n} from './resolve-ssg-data';\nimport { batchRenderRoutes } from './batch-render';\nimport { writeStaticFiles } from './write-static-files';\nimport {\n generateSSGResult,\n resultToMetadata,\n writeMetadata,\n} from './generate-metadata';\nimport {\n getExistingOutputFileSize,\n outputFileExists,\n readIncrementalManifest,\n type IncrementalManifestRouteEntry,\n writeIncrementalManifest,\n hashHtml,\n SSG_MANIFEST_SCHEMA_VERSION,\n} from './incremental-manifest';\nimport { resolveRouteDescriptor } from './route-utils';\nimport {\n collectRemovedRouteResults,\n dedupeStrings,\n getRoutesToRender,\n selectRouteForGeneration,\n type SelectedRoute,\n} from './generation-plan';\nimport { normalizeStaticRoutes, splitStaticRoutes } from './static-routes';\nimport { addPerfDuration, incrementPerfMetric } from '../runtime/perf-metrics';\n\ntype AnyRouteConfig = RouteConfig<string>;\n\ntype StrictRouteConfig<TRoute extends AnyRouteConfig> = Omit<\n TRoute,\n 'params' | 'entries'\n> & {\n params?: RouteConfig<TRoute['path']>['params'];\n entries?: RouteConfig<TRoute['path']>['entries'];\n};\n\ntype StrictRouteConfigs<TRoutes extends readonly AnyRouteConfig[]> = {\n [TIndex in keyof TRoutes]: TRoutes[TIndex] extends AnyRouteConfig\n ? StrictRouteConfig<TRoutes[TIndex]>\n : never;\n};\n\ntype StaticGenRouteSource<TRoutes extends readonly AnyRouteConfig[]> =\n | {\n routes: TRoutes & StrictRouteConfigs<TRoutes>;\n registry?: never;\n }\n | {\n registry: RouteRegistry;\n routes?: never;\n };\n\nfunction resolveParallelism(requested: number | 'auto' | undefined): number {\n if (requested !== 'auto') {\n return Math.max(1, requested ?? 1);\n }\n\n const maybeNavigator = globalThis as typeof globalThis & {\n navigator?: { hardwareConcurrency?: number };\n process?: { env?: Record<string, string | undefined> };\n };\n\n const envWorkers = Number(\n maybeNavigator.process?.env?.ASKR_SSG_WORKERS ??\n maybeNavigator.process?.env?.NUMBER_OF_PROCESSORS ??\n maybeNavigator.process?.env?.UV_THREADPOOL_SIZE\n );\n if (Number.isFinite(envWorkers) && envWorkers > 0) {\n return Math.max(1, Math.trunc(envWorkers));\n }\n\n if (typeof maybeNavigator.navigator?.hardwareConcurrency === 'number') {\n return Math.max(1, maybeNavigator.navigator.hardwareConcurrency);\n }\n\n return 1;\n}\n\n/**\n * Create a Static Site Generator\n *\n * Usage:\n * ```ts\n * const ssg = createStaticGen({\n * routes: [\n * { path: '/', component: HomePage },\n * { path: '/about', component: AboutPage },\n * ],\n * outputDir: './dist',\n * dataOverrides: {\n * '/api/posts': { posts: [...] }\n * }\n * });\n *\n * const result = await ssg.generate();\n * console.log(`Generated ${result.successful}/${result.totalRoutes} routes`);\n * ```\n */\nexport function createStaticGen<\n const TRoutes extends readonly AnyRouteConfig[],\n>(\n options: Omit<SSGOptions<TRoutes>, 'routes' | 'registry'> &\n StaticGenRouteSource<TRoutes>\n) {\n let result: SSGResult | null = null;\n const configuredRoutes = normalizeStaticRoutes(options);\n const seed = options.seed ?? 12345;\n const resolvedParallelism = resolveParallelism(options.parallelism);\n const resolvedConcurrency = Math.max(\n 1,\n options.concurrency ?? resolvedParallelism\n );\n\n if (configuredRoutes.length === 0) {\n throw new Error('routes array or route registry is required');\n }\n\n if (!options.outputDir || options.outputDir.trim().length === 0) {\n throw new Error('outputDir is required');\n }\n\n return {\n /**\n * Generate static HTML for all routes\n * Writes to outputDir with metadata.json\n * Returns detailed results\n */\n async generate(\n generateOptions: SSGGenerateOptions = {}\n ): Promise<SSGResult> {\n const splitRoutes = await splitStaticRoutes(configuredRoutes);\n const routes = splitRoutes.routes;\n validateRoutes(routes);\n\n const changedKeys = dedupeStrings(generateOptions.changedKeys);\n const changedRoutes = dedupeStrings(generateOptions.changedRoutes);\n const requestedMode = generateOptions.mode ?? 'full';\n const previousManifest =\n !generateOptions.forceFull && requestedMode === 'incremental'\n ? readIncrementalManifest(options.outputDir, seed)\n : null;\n const effectiveMode: SSGMode =\n generateOptions.forceFull ||\n requestedMode !== 'incremental' ||\n previousManifest === null\n ? 'full'\n : 'incremental';\n\n // Resolve data\n const dataMap = resolveSsgData(routes, {\n dataOverrides: options.dataOverrides,\n });\n\n const descriptors = routes.map(resolveRouteDescriptor);\n const routeResultsById = new Map<string, RouteRenderResult>();\n for (const runtimeRoute of splitRoutes.runtimeOnly) {\n routeResultsById.set(runtimeRoute.routeId, runtimeRoute.result);\n }\n const eligibleDescriptors = descriptors;\n\n const previousEntries = new Map(\n (previousManifest?.routes ?? []).map((entry) => [entry.routeId, entry])\n );\n const currentRouteIds = new Set(\n eligibleDescriptors.map((descriptor) => descriptor.routeId)\n );\n\n const selected: SelectedRoute[] = [];\n const routesToRender: SelectedRoute[] = [];\n for (let index = 0; index < eligibleDescriptors.length; index += 1) {\n const descriptor = eligibleDescriptors[index];\n const entry = selectRouteForGeneration(\n descriptor,\n previousEntries.get(descriptor.routeId) ?? null,\n effectiveMode,\n changedKeys,\n changedRoutes\n );\n selected.push(entry);\n if (entry.reason !== 'unchanged') {\n routesToRender.push(entry);\n }\n }\n const renderStartTime = performance.now();\n incrementPerfMetric('ssgWorkerCount', resolvedParallelism);\n const renderedResults =\n routesToRender.length > 0\n ? await batchRenderRoutes(getRoutesToRender(routesToRender), {\n seed,\n dataMap,\n concurrency: resolvedConcurrency,\n document: options.document,\n })\n : [];\n addPerfDuration('ssgRenderTimeMs', performance.now() - renderStartTime);\n const renderedByRouteId = new Map<string, RouteRenderResult>();\n for (let index = 0; index < renderedResults.length; index += 1) {\n renderedByRouteId.set(\n routesToRender[index].descriptor.routeId,\n renderedResults[index]\n );\n }\n\n let cacheHits = 0;\n const nextManifestRoutes: IncrementalManifestRouteEntry[] = [];\n\n for (const entry of selected) {\n const { descriptor, previous, reason } = entry;\n const resolvedData = resolveSsgRouteData(\n dataMap,\n descriptor.route.path,\n descriptor.path\n );\n const baseData = resolvedData.hasData ? resolvedData.data : undefined;\n const resourceCount =\n resolvedData.hasData && baseData ? Object.keys(baseData).length : 0;\n\n if (reason === 'unchanged') {\n routeResultsById.set(descriptor.routeId, {\n path: descriptor.path,\n filePath: descriptor.filePath,\n html: '',\n fileSize:\n previous?.htmlHash !== null && previous !== null\n ? getExistingOutputFileSize(\n options.outputDir,\n descriptor.filePath\n )\n : 0,\n renderDuration: 0,\n resourceCount,\n status: 'skipped',\n reason: 'unchanged',\n written: false,\n });\n\n if (previous) {\n nextManifestRoutes.push({\n ...previous,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n });\n }\n continue;\n }\n\n const rendered = renderedByRouteId.get(descriptor.routeId);\n if (!rendered) {\n throw new Error(\n `Missing rendered result for route \"${descriptor.path}\"`\n );\n }\n\n const nextResult: RouteRenderResult = {\n ...rendered,\n path: descriptor.path,\n filePath: descriptor.filePath,\n resourceCount,\n reason,\n written: false,\n };\n\n if (nextResult.status === 'success') {\n const htmlDigest = hashHtml(nextResult.html);\n const shouldWrite =\n effectiveMode === 'full' ||\n !previous ||\n previous.htmlHash !== htmlDigest ||\n !outputFileExists(options.outputDir, descriptor.filePath);\n\n nextResult.written = shouldWrite;\n if (!shouldWrite) {\n cacheHits += 1;\n }\n\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: htmlDigest,\n lastStatus: 'success',\n });\n } else {\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: previous?.htmlHash ?? null,\n lastStatus: 'error',\n });\n }\n\n routeResultsById.set(descriptor.routeId, nextResult);\n }\n\n const removedResults = collectRemovedRouteResults(\n previousManifest,\n currentRouteIds\n );\n const routeResults: RouteRenderResult[] = [];\n for (const routeId of splitRoutes.outputRouteIds) {\n const routeResult = routeResultsById.get(routeId);\n if (routeResult) {\n routeResults.push(routeResult);\n }\n }\n routeResults.push(...removedResults);\n\n // Write HTML files to disk and remove stale output\n const writeStartTime = performance.now();\n await writeStaticFiles(routeResults, options.outputDir, {\n concurrency: resolvedConcurrency,\n });\n addPerfDuration('ssgWriteTimeMs', performance.now() - writeStartTime);\n\n // Generate result object\n result = generateSSGResult(routeResults, {\n mode: effectiveMode,\n cacheHits,\n invalidatedKeys: changedKeys,\n invalidatedRoutes: changedRoutes,\n });\n\n // Write metadata\n const metadata = resultToMetadata(result);\n await writeMetadata(metadata, options.outputDir);\n\n await writeIncrementalManifest(\n {\n schemaVersion: SSG_MANIFEST_SCHEMA_VERSION,\n seed,\n mode: effectiveMode,\n routes: nextManifestRoutes,\n },\n options.outputDir\n );\n\n return result;\n },\n\n /**\n * Get effective config in a serializable form for diagnostics.\n */\n getConfig() {\n return {\n routeCount: configuredRoutes.length,\n outputDir: options.outputDir,\n seed,\n concurrency: resolvedConcurrency,\n parallelism: resolvedParallelism,\n hasDataOverrides: !!options.dataOverrides,\n };\n },\n\n /**\n * Get the last generation result\n * Returns null if generate() hasn't been called\n */\n getResult(): SSGResult | null {\n return result;\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"create-static-gen.js","names":[],"sources":["../../src/ssg/create-static-gen.ts"],"sourcesContent":["/**\n * Static Site Generation API\n *\n * Main orchestrator for batch rendering, file I/O, and metadata generation\n */\n\nimport type {\n RouteConfig,\n RouteRenderResult,\n SSGGenerateOptions,\n SSGMode,\n SSGOptions,\n SSGResult,\n} from './types';\nimport type { RouteRegistry } from '../common/router';\nimport {\n resolveSsgRouteData,\n resolveSsgData,\n validateRoutes,\n} from './resolve-ssg-data';\nimport { batchRenderRoutes } from './batch-render';\nimport { writeStaticFiles } from './write-static-files';\nimport {\n generateSSGResult,\n resultToMetadata,\n writeMetadata,\n} from './generate-metadata';\nimport {\n getExistingOutputFileSize,\n outputFileExists,\n readIncrementalManifest,\n type IncrementalManifestRouteEntry,\n writeIncrementalManifest,\n hashHtml,\n SSG_MANIFEST_SCHEMA_VERSION,\n} from './incremental-manifest';\nimport { resolveRouteDescriptor } from './route-utils';\nimport {\n collectRemovedRouteResults,\n dedupeStrings,\n getRoutesToRender,\n selectRouteForGeneration,\n type SelectedRoute,\n} from './generation-plan';\nimport { normalizeStaticRoutes, splitStaticRoutes } from './static-routes';\nimport { addPerfDuration, incrementPerfMetric } from '../runtime';\n\ntype AnyRouteConfig = RouteConfig<string>;\n\ntype StrictRouteConfig<TRoute extends AnyRouteConfig> = Omit<\n TRoute,\n 'params' | 'entries'\n> & {\n params?: RouteConfig<TRoute['path']>['params'];\n entries?: RouteConfig<TRoute['path']>['entries'];\n};\n\ntype StrictRouteConfigs<TRoutes extends readonly AnyRouteConfig[]> = {\n [TIndex in keyof TRoutes]: TRoutes[TIndex] extends AnyRouteConfig\n ? StrictRouteConfig<TRoutes[TIndex]>\n : never;\n};\n\ntype StaticGenRouteSource<TRoutes extends readonly AnyRouteConfig[]> =\n | {\n routes: TRoutes & StrictRouteConfigs<TRoutes>;\n registry?: never;\n }\n | {\n registry: RouteRegistry;\n routes?: never;\n };\n\nfunction resolveParallelism(requested: number | 'auto' | undefined): number {\n if (requested !== 'auto') {\n return Math.max(1, requested ?? 1);\n }\n\n const maybeNavigator = globalThis as typeof globalThis & {\n navigator?: { hardwareConcurrency?: number };\n process?: { env?: Record<string, string | undefined> };\n };\n\n const envWorkers = Number(\n maybeNavigator.process?.env?.ASKR_SSG_WORKERS ??\n maybeNavigator.process?.env?.NUMBER_OF_PROCESSORS ??\n maybeNavigator.process?.env?.UV_THREADPOOL_SIZE\n );\n if (Number.isFinite(envWorkers) && envWorkers > 0) {\n return Math.max(1, Math.trunc(envWorkers));\n }\n\n if (typeof maybeNavigator.navigator?.hardwareConcurrency === 'number') {\n return Math.max(1, maybeNavigator.navigator.hardwareConcurrency);\n }\n\n return 1;\n}\n\n/**\n * Create a Static Site Generator\n *\n * Usage:\n * ```ts\n * const ssg = createStaticGen({\n * routes: [\n * { path: '/', component: HomePage },\n * { path: '/about', component: AboutPage },\n * ],\n * outputDir: './dist',\n * dataOverrides: {\n * '/api/posts': { posts: [...] }\n * }\n * });\n *\n * const result = await ssg.generate();\n * console.log(`Generated ${result.successful}/${result.totalRoutes} routes`);\n * ```\n */\nexport function createStaticGen<\n const TRoutes extends readonly AnyRouteConfig[],\n>(\n options: Omit<SSGOptions<TRoutes>, 'routes' | 'registry'> &\n StaticGenRouteSource<TRoutes>\n) {\n let result: SSGResult | null = null;\n const configuredRoutes = normalizeStaticRoutes(options);\n const seed = options.seed ?? 12345;\n const resolvedParallelism = resolveParallelism(options.parallelism);\n const resolvedConcurrency = Math.max(\n 1,\n options.concurrency ?? resolvedParallelism\n );\n\n if (configuredRoutes.length === 0) {\n throw new Error('routes array or route registry is required');\n }\n\n if (!options.outputDir || options.outputDir.trim().length === 0) {\n throw new Error('outputDir is required');\n }\n\n return {\n /**\n * Generate static HTML for all routes\n * Writes to outputDir with metadata.json\n * Returns detailed results\n */\n async generate(\n generateOptions: SSGGenerateOptions = {}\n ): Promise<SSGResult> {\n const splitRoutes = await splitStaticRoutes(configuredRoutes);\n const routes = splitRoutes.routes;\n validateRoutes(routes);\n\n const changedKeys = dedupeStrings(generateOptions.changedKeys);\n const changedRoutes = dedupeStrings(generateOptions.changedRoutes);\n const requestedMode = generateOptions.mode ?? 'full';\n const previousManifest =\n !generateOptions.forceFull && requestedMode === 'incremental'\n ? readIncrementalManifest(options.outputDir, seed)\n : null;\n const effectiveMode: SSGMode =\n generateOptions.forceFull ||\n requestedMode !== 'incremental' ||\n previousManifest === null\n ? 'full'\n : 'incremental';\n\n // Resolve data\n const dataMap = resolveSsgData(routes, {\n dataOverrides: options.dataOverrides,\n });\n\n const descriptors = routes.map(resolveRouteDescriptor);\n const routeResultsById = new Map<string, RouteRenderResult>();\n for (const runtimeRoute of splitRoutes.runtimeOnly) {\n routeResultsById.set(runtimeRoute.routeId, runtimeRoute.result);\n }\n const eligibleDescriptors = descriptors;\n\n const previousEntries = new Map(\n (previousManifest?.routes ?? []).map((entry) => [entry.routeId, entry])\n );\n const currentRouteIds = new Set(\n eligibleDescriptors.map((descriptor) => descriptor.routeId)\n );\n\n const selected: SelectedRoute[] = [];\n const routesToRender: SelectedRoute[] = [];\n for (let index = 0; index < eligibleDescriptors.length; index += 1) {\n const descriptor = eligibleDescriptors[index];\n const entry = selectRouteForGeneration(\n descriptor,\n previousEntries.get(descriptor.routeId) ?? null,\n effectiveMode,\n changedKeys,\n changedRoutes\n );\n selected.push(entry);\n if (entry.reason !== 'unchanged') {\n routesToRender.push(entry);\n }\n }\n const renderStartTime = performance.now();\n incrementPerfMetric('ssgWorkerCount', resolvedParallelism);\n const renderedResults =\n routesToRender.length > 0\n ? await batchRenderRoutes(getRoutesToRender(routesToRender), {\n seed,\n dataMap,\n concurrency: resolvedConcurrency,\n document: options.document,\n })\n : [];\n addPerfDuration('ssgRenderTimeMs', performance.now() - renderStartTime);\n const renderedByRouteId = new Map<string, RouteRenderResult>();\n for (let index = 0; index < renderedResults.length; index += 1) {\n renderedByRouteId.set(\n routesToRender[index].descriptor.routeId,\n renderedResults[index]\n );\n }\n\n let cacheHits = 0;\n const nextManifestRoutes: IncrementalManifestRouteEntry[] = [];\n\n for (const entry of selected) {\n const { descriptor, previous, reason } = entry;\n const resolvedData = resolveSsgRouteData(\n dataMap,\n descriptor.route.path,\n descriptor.path\n );\n const baseData = resolvedData.hasData ? resolvedData.data : undefined;\n const resourceCount =\n resolvedData.hasData && baseData ? Object.keys(baseData).length : 0;\n\n if (reason === 'unchanged') {\n routeResultsById.set(descriptor.routeId, {\n path: descriptor.path,\n filePath: descriptor.filePath,\n html: '',\n fileSize:\n previous?.htmlHash !== null && previous !== null\n ? getExistingOutputFileSize(\n options.outputDir,\n descriptor.filePath\n )\n : 0,\n renderDuration: 0,\n resourceCount,\n status: 'skipped',\n reason: 'unchanged',\n written: false,\n });\n\n if (previous) {\n nextManifestRoutes.push({\n ...previous,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n });\n }\n continue;\n }\n\n const rendered = renderedByRouteId.get(descriptor.routeId);\n if (!rendered) {\n throw new Error(\n `Missing rendered result for route \"${descriptor.path}\"`\n );\n }\n\n const nextResult: RouteRenderResult = {\n ...rendered,\n path: descriptor.path,\n filePath: descriptor.filePath,\n resourceCount,\n reason,\n written: false,\n };\n\n if (nextResult.status === 'success') {\n const htmlDigest = hashHtml(nextResult.html);\n const shouldWrite =\n effectiveMode === 'full' ||\n !previous ||\n previous.htmlHash !== htmlDigest ||\n !outputFileExists(options.outputDir, descriptor.filePath);\n\n nextResult.written = shouldWrite;\n if (!shouldWrite) {\n cacheHits += 1;\n }\n\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: htmlDigest,\n lastStatus: 'success',\n });\n } else {\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: previous?.htmlHash ?? null,\n lastStatus: 'error',\n });\n }\n\n routeResultsById.set(descriptor.routeId, nextResult);\n }\n\n const removedResults = collectRemovedRouteResults(\n previousManifest,\n currentRouteIds\n );\n const routeResults: RouteRenderResult[] = [];\n for (const routeId of splitRoutes.outputRouteIds) {\n const routeResult = routeResultsById.get(routeId);\n if (routeResult) {\n routeResults.push(routeResult);\n }\n }\n routeResults.push(...removedResults);\n\n // Write HTML files to disk and remove stale output\n const writeStartTime = performance.now();\n await writeStaticFiles(routeResults, options.outputDir, {\n concurrency: resolvedConcurrency,\n });\n addPerfDuration('ssgWriteTimeMs', performance.now() - writeStartTime);\n\n // Generate result object\n result = generateSSGResult(routeResults, {\n mode: effectiveMode,\n cacheHits,\n invalidatedKeys: changedKeys,\n invalidatedRoutes: changedRoutes,\n });\n\n // Write metadata\n const metadata = resultToMetadata(result);\n await writeMetadata(metadata, options.outputDir);\n\n await writeIncrementalManifest(\n {\n schemaVersion: SSG_MANIFEST_SCHEMA_VERSION,\n seed,\n mode: effectiveMode,\n routes: nextManifestRoutes,\n },\n options.outputDir\n );\n\n return result;\n },\n\n /**\n * Get effective config in a serializable form for diagnostics.\n */\n getConfig() {\n return {\n routeCount: configuredRoutes.length,\n outputDir: options.outputDir,\n seed,\n concurrency: resolvedConcurrency,\n parallelism: resolvedParallelism,\n hasDataOverrides: !!options.dataOverrides,\n };\n },\n\n /**\n * Get the last generation result\n * Returns null if generate() hasn't been called\n */\n getResult(): SSGResult | null {\n return result;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;AAyEA,SAAS,mBAAmB,WAAgD;CAC1E,IAAI,cAAc,QAChB,OAAO,KAAK,IAAI,GAAG,aAAa,CAAC;CAGnC,MAAM,iBAAiB;CAKvB,MAAM,aAAa,OACjB,eAAe,SAAS,KAAK,oBAC3B,eAAe,SAAS,KAAK,wBAC7B,eAAe,SAAS,KAAK,kBACjC;CACA,IAAI,OAAO,SAAS,UAAU,KAAK,aAAa,GAC9C,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,CAAC;CAG3C,IAAI,OAAO,eAAe,WAAW,wBAAwB,UAC3D,OAAO,KAAK,IAAI,GAAG,eAAe,UAAU,mBAAmB;CAGjE,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,gBAGd,SAEA;CACA,IAAI,SAA2B;CAC/B,MAAM,mBAAmB,sBAAsB,OAAO;CACtD,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,sBAAsB,mBAAmB,QAAQ,WAAW;CAClE,MAAM,sBAAsB,KAAK,IAC/B,GACA,QAAQ,eAAe,mBACzB;CAEA,IAAI,iBAAiB,WAAW,GAC9B,MAAM,IAAI,MAAM,4CAA4C;CAG9D,IAAI,CAAC,QAAQ,aAAa,QAAQ,UAAU,KAAK,CAAC,CAAC,WAAW,GAC5D,MAAM,IAAI,MAAM,uBAAuB;CAGzC,OAAO;;;;;;EAML,MAAM,SACJ,kBAAsC,CAAC,GACnB;GACpB,MAAM,cAAc,MAAM,kBAAkB,gBAAgB;GAC5D,MAAM,SAAS,YAAY;GAC3B,eAAe,MAAM;GAErB,MAAM,cAAc,cAAc,gBAAgB,WAAW;GAC7D,MAAM,gBAAgB,cAAc,gBAAgB,aAAa;GACjE,MAAM,gBAAgB,gBAAgB,QAAQ;GAC9C,MAAM,mBACJ,CAAC,gBAAgB,aAAa,kBAAkB,gBAC5C,wBAAwB,QAAQ,WAAW,IAAI,IAC/C;GACN,MAAM,gBACJ,gBAAgB,aAChB,kBAAkB,iBAClB,qBAAqB,OACjB,SACA;GAGN,MAAM,UAAU,eAAe,QAAQ,EACrC,eAAe,QAAQ,cACzB,CAAC;GAED,MAAM,cAAc,OAAO,IAAI,sBAAsB;GACrD,MAAM,mCAAmB,IAAI,IAA+B;GAC5D,KAAK,MAAM,gBAAgB,YAAY,aACrC,iBAAiB,IAAI,aAAa,SAAS,aAAa,MAAM;GAEhE,MAAM,sBAAsB;GAE5B,MAAM,kBAAkB,IAAI,KACzB,kBAAkB,UAAU,CAAC,EAAA,CAAG,KAAK,UAAU,CAAC,MAAM,SAAS,KAAK,CAAC,CACxE;GACA,MAAM,kBAAkB,IAAI,IAC1B,oBAAoB,KAAK,eAAe,WAAW,OAAO,CAC5D;GAEA,MAAM,WAA4B,CAAC;GACnC,MAAM,iBAAkC,CAAC;GACzC,KAAK,IAAI,QAAQ,GAAG,QAAQ,oBAAoB,QAAQ,SAAS,GAAG;IAClE,MAAM,aAAa,oBAAoB;IACvC,MAAM,QAAQ,yBACZ,YACA,gBAAgB,IAAI,WAAW,OAAO,KAAK,MAC3C,eACA,aACA,aACF;IACA,SAAS,KAAK,KAAK;IACnB,IAAI,MAAM,WAAW,aACnB,eAAe,KAAK,KAAK;GAE7B;GACA,MAAM,kBAAkB,YAAY,IAAI;GACxC,oBAAoB,kBAAkB,mBAAmB;GACzD,MAAM,kBACJ,eAAe,SAAS,IACpB,MAAM,kBAAkB,kBAAkB,cAAc,GAAG;IACzD;IACA;IACA,aAAa;IACb,UAAU,QAAQ;GACpB,CAAC,IACD,CAAC;GACP,gBAAgB,mBAAmB,YAAY,IAAI,IAAI,eAAe;GACtE,MAAM,oCAAoB,IAAI,IAA+B;GAC7D,KAAK,IAAI,QAAQ,GAAG,QAAQ,gBAAgB,QAAQ,SAAS,GAC3D,kBAAkB,IAChB,eAAe,MAAM,CAAC,WAAW,SACjC,gBAAgB,MAClB;GAGF,IAAI,YAAY;GAChB,MAAM,qBAAsD,CAAC;GAE7D,KAAK,MAAM,SAAS,UAAU;IAC5B,MAAM,EAAE,YAAY,UAAU,WAAW;IACzC,MAAM,eAAe,oBACnB,SACA,WAAW,MAAM,MACjB,WAAW,IACb;IACA,MAAM,WAAW,aAAa,UAAU,aAAa,OAAO;IAC5D,MAAM,gBACJ,aAAa,WAAW,WAAW,OAAO,KAAK,QAAQ,CAAC,CAAC,SAAS;IAEpE,IAAI,WAAW,aAAa;KAC1B,iBAAiB,IAAI,WAAW,SAAS;MACvC,MAAM,WAAW;MACjB,UAAU,WAAW;MACrB,MAAM;MACN,UACE,UAAU,aAAa,QAAQ,aAAa,OACxC,0BACE,QAAQ,WACR,WAAW,QACb,IACA;MACN,gBAAgB;MAChB;MACA,QAAQ;MACR,QAAQ;MACR,SAAS;KACX,CAAC;KAED,IAAI,UACF,mBAAmB,KAAK;MACtB,GAAG;MACH,MAAM,WAAW;MACjB,UAAU,WAAW;MACrB,kBAAkB,WAAW,iBAAiB,MAAM;KACtD,CAAC;KAEH;IACF;IAEA,MAAM,WAAW,kBAAkB,IAAI,WAAW,OAAO;IACzD,IAAI,CAAC,UACH,MAAM,IAAI,MACR,sCAAsC,WAAW,KAAK,EACxD;IAGF,MAAM,aAAgC;KACpC,GAAG;KACH,MAAM,WAAW;KACjB,UAAU,WAAW;KACrB;KACA;KACA,SAAS;IACX;IAEA,IAAI,WAAW,WAAW,WAAW;KACnC,MAAM,aAAa,SAAS,WAAW,IAAI;KAC3C,MAAM,cACJ,kBAAkB,UAClB,CAAC,YACD,SAAS,aAAa,cACtB,CAAC,iBAAiB,QAAQ,WAAW,WAAW,QAAQ;KAE1D,WAAW,UAAU;KACrB,IAAI,CAAC,aACH,aAAa;KAGf,mBAAmB,KAAK;MACtB,SAAS,WAAW;MACpB,MAAM,WAAW;MACjB,UAAU,WAAW;MACrB,kBAAkB,WAAW,iBAAiB,MAAM;MACpD,UAAU;MACV,YAAY;KACd,CAAC;IACH,OACE,mBAAmB,KAAK;KACtB,SAAS,WAAW;KACpB,MAAM,WAAW;KACjB,UAAU,WAAW;KACrB,kBAAkB,WAAW,iBAAiB,MAAM;KACpD,UAAU,UAAU,YAAY;KAChC,YAAY;IACd,CAAC;IAGH,iBAAiB,IAAI,WAAW,SAAS,UAAU;GACrD;GAEA,MAAM,iBAAiB,2BACrB,kBACA,eACF;GACA,MAAM,eAAoC,CAAC;GAC3C,KAAK,MAAM,WAAW,YAAY,gBAAgB;IAChD,MAAM,cAAc,iBAAiB,IAAI,OAAO;IAChD,IAAI,aACF,aAAa,KAAK,WAAW;GAEjC;GACA,aAAa,KAAK,GAAG,cAAc;GAGnC,MAAM,iBAAiB,YAAY,IAAI;GACvC,MAAM,iBAAiB,cAAc,QAAQ,WAAW,EACtD,aAAa,oBACf,CAAC;GACD,gBAAgB,kBAAkB,YAAY,IAAI,IAAI,cAAc;GAGpE,SAAS,kBAAkB,cAAc;IACvC,MAAM;IACN;IACA,iBAAiB;IACjB,mBAAmB;GACrB,CAAC;GAID,MAAM,cADW,iBAAiB,MACd,GAAU,QAAQ,SAAS;GAE/C,MAAM,yBACJ;IACE,eAAA;IACA;IACA,MAAM;IACN,QAAQ;GACV,GACA,QAAQ,SACV;GAEA,OAAO;EACT;;;;EAKA,YAAY;GACV,OAAO;IACL,YAAY,iBAAiB;IAC7B,WAAW,QAAQ;IACnB;IACA,aAAa;IACb,aAAa;IACb,kBAAkB,CAAC,CAAC,QAAQ;GAC9B;EACF;;;;;EAMA,YAA8B;GAC5B,OAAO;EACT;CACF;AACF"}
@@ -1,4 +1,5 @@
1
1
  import { _getBuiltInRoutePolicy } from "../router/policy.js";
2
+ import "../router/route.js";
2
3
  import { getOutputFilePath, interpolateRoutePath, resolveRouteDescriptor } from "./route-utils.js";
3
4
  import { expandRoutes } from "./resolve-ssg-data.js";
4
5
  //#region src/ssg/static-routes.ts
@@ -1 +1 @@
1
- {"version":3,"file":"static-routes.js","names":[],"sources":["../../src/ssg/static-routes.ts"],"sourcesContent":["/**\n * SSG route source normalization and runtime-only filtering.\n */\n\nimport type { RouteConfig, RouteRenderResult } from './types';\nimport type { RoutePolicy, RouteRegistry } from '../common/router';\nimport { _getBuiltInRoutePolicy } from '../router/policy';\nimport { expandRoutes } from './resolve-ssg-data';\nimport {\n getOutputFilePath,\n interpolateRoutePath,\n resolveRouteDescriptor,\n} from './route-utils';\n\ntype StaticRouteSource = {\n registry?: RouteRegistry;\n routes?: readonly RouteConfig[];\n};\n\nexport type RuntimeOnlyRoute = {\n routeId: string;\n result: RouteRenderResult;\n};\n\nexport interface SplitStaticRoutesResult {\n routes: RouteConfig[];\n runtimeOnly: RuntimeOnlyRoute[];\n outputRouteIds: string[];\n}\n\nfunction getRuntimeOnlyDiagnostic(\n route: RouteConfig,\n path: string\n): string | null {\n const policies = route.policies ?? [];\n\n if (route.auth === true) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (route.role) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (route.permission) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n if (policies.length > 0) {\n let hasAuthPolicy = false;\n let hasRolePolicy = false;\n let hasPermissionPolicy = false;\n\n for (const policy of policies) {\n const metadata = _getBuiltInRoutePolicy(policy);\n if (!metadata) {\n return `Skipped prerender for \"${path}\": routes with custom policies are runtime-only by default.`;\n }\n\n if (metadata.kind === 'auth') {\n hasAuthPolicy = true;\n } else if (metadata.kind === 'role') {\n hasRolePolicy = true;\n } else if (metadata.kind === 'permission') {\n hasPermissionPolicy = true;\n }\n }\n\n if (hasAuthPolicy) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (hasRolePolicy) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (hasPermissionPolicy) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n return null;\n }\n\n return null;\n}\n\nfunction getRouteResultPath(route: RouteConfig): string {\n return route.params\n ? interpolateRoutePath(route.path, route.params)\n : route.path;\n}\n\nfunction createRuntimeOnlyRoute(\n route: RouteConfig,\n diagnostic: string\n): RuntimeOnlyRoute {\n const path = getRouteResultPath(route);\n const filePath = getOutputFilePath(path);\n\n return {\n routeId: `${path}::${filePath}`,\n result: {\n path,\n filePath,\n html: '',\n fileSize: 0,\n renderDuration: 0,\n resourceCount: 0,\n status: 'skipped',\n reason: 'runtime-only',\n written: false,\n error: diagnostic,\n },\n };\n}\n\nexport async function splitStaticRoutes(\n routes: readonly RouteConfig[]\n): Promise<SplitStaticRoutesResult> {\n const prerenderableRoutes: RouteConfig[] = [];\n const runtimeOnly: RuntimeOnlyRoute[] = [];\n const outputRouteIds: string[] = [];\n\n for (const route of routes) {\n const routePath = getRouteResultPath(route);\n const diagnostic = getRuntimeOnlyDiagnostic(route, routePath);\n if (diagnostic) {\n const runtimeRoute = createRuntimeOnlyRoute(route, diagnostic);\n runtimeOnly.push(runtimeRoute);\n outputRouteIds.push(runtimeRoute.routeId);\n continue;\n }\n\n const expanded = await expandRoutes([route]);\n prerenderableRoutes.push(...expanded);\n for (const expandedRoute of expanded) {\n outputRouteIds.push(resolveRouteDescriptor(expandedRoute).routeId);\n }\n }\n\n return {\n routes: prerenderableRoutes,\n runtimeOnly,\n outputRouteIds,\n };\n}\n\nexport function normalizeStaticRoutes(\n options: StaticRouteSource\n): RouteConfig[] {\n if (options.registry) {\n return routeRegistryToRouteConfigs(options.registry);\n }\n\n return [...(options.routes ?? [])];\n}\n\nfunction routeRegistryToRouteConfigs(registry: RouteRegistry): RouteConfig[] {\n const routeConfigs: RouteConfig[] = [];\n\n for (const record of registry.manifest.records) {\n if (record.isFallback) {\n continue;\n }\n\n routeConfigs.push({\n path: record.path,\n handler: record.handler,\n namespace: record.options.namespace,\n auth: record.options.auth,\n role: record.options.role,\n permission: record.options.permission,\n policies: stripRegistryGuestPolicies(record.options.policies),\n entries: record.options.entries,\n });\n }\n\n return routeConfigs;\n}\n\nfunction stripRegistryGuestPolicies(\n policies: readonly RoutePolicy[] | undefined\n): readonly RoutePolicy[] | undefined {\n if (!policies || policies.length === 0) {\n return undefined;\n }\n\n const filtered = policies.filter(\n (policy) => _getBuiltInRoutePolicy(policy)?.kind !== 'guest'\n );\n\n return filtered.length > 0 ? filtered : undefined;\n}\n"],"mappings":";;;;AA8BA,SAAS,yBACP,OACA,MACe;CACf,MAAM,WAAW,MAAM,YAAY,CAAC;CAEpC,IAAI,MAAM,SAAS,MACjB,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,MACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,YACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,SAAS,SAAS,GAAG;EACvB,IAAI,gBAAgB;EACpB,IAAI,gBAAgB;EACpB,IAAI,sBAAsB;EAE1B,KAAK,MAAM,UAAU,UAAU;GAC7B,MAAM,WAAW,uBAAuB,MAAM;GAC9C,IAAI,CAAC,UACH,OAAO,0BAA0B,KAAK;GAGxC,IAAI,SAAS,SAAS,QACpB,gBAAgB;QACX,IAAI,SAAS,SAAS,QAC3B,gBAAgB;QACX,IAAI,SAAS,SAAS,cAC3B,sBAAsB;EAE1B;EAEA,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,qBACF,OAAO,0BAA0B,KAAK;EAGxC,OAAO;CACT;CAEA,OAAO;AACT;AAEA,SAAS,mBAAmB,OAA4B;CACtD,OAAO,MAAM,SACT,qBAAqB,MAAM,MAAM,MAAM,MAAM,IAC7C,MAAM;AACZ;AAEA,SAAS,uBACP,OACA,YACkB;CAClB,MAAM,OAAO,mBAAmB,KAAK;CACrC,MAAM,WAAW,kBAAkB,IAAI;CAEvC,OAAO;EACL,SAAS,GAAG,KAAK,IAAI;EACrB,QAAQ;GACN;GACA;GACA,MAAM;GACN,UAAU;GACV,gBAAgB;GAChB,eAAe;GACf,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,OAAO;EACT;CACF;AACF;AAEA,eAAsB,kBACpB,QACkC;CAClC,MAAM,sBAAqC,CAAC;CAC5C,MAAM,cAAkC,CAAC;CACzC,MAAM,iBAA2B,CAAC;CAElC,KAAK,MAAM,SAAS,QAAQ;EAE1B,MAAM,aAAa,yBAAyB,OAD1B,mBAAmB,KACc,CAAS;EAC5D,IAAI,YAAY;GACd,MAAM,eAAe,uBAAuB,OAAO,UAAU;GAC7D,YAAY,KAAK,YAAY;GAC7B,eAAe,KAAK,aAAa,OAAO;GACxC;EACF;EAEA,MAAM,WAAW,MAAM,aAAa,CAAC,KAAK,CAAC;EAC3C,oBAAoB,KAAK,GAAG,QAAQ;EACpC,KAAK,MAAM,iBAAiB,UAC1B,eAAe,KAAK,uBAAuB,aAAa,CAAC,CAAC,OAAO;CAErE;CAEA,OAAO;EACL,QAAQ;EACR;EACA;CACF;AACF;AAEA,SAAgB,sBACd,SACe;CACf,IAAI,QAAQ,UACV,OAAO,4BAA4B,QAAQ,QAAQ;CAGrD,OAAO,CAAC,GAAI,QAAQ,UAAU,CAAC,CAAE;AACnC;AAEA,SAAS,4BAA4B,UAAwC;CAC3E,MAAM,eAA8B,CAAC;CAErC,KAAK,MAAM,UAAU,SAAS,SAAS,SAAS;EAC9C,IAAI,OAAO,YACT;EAGF,aAAa,KAAK;GAChB,MAAM,OAAO;GACb,SAAS,OAAO;GAChB,WAAW,OAAO,QAAQ;GAC1B,MAAM,OAAO,QAAQ;GACrB,MAAM,OAAO,QAAQ;GACrB,YAAY,OAAO,QAAQ;GAC3B,UAAU,2BAA2B,OAAO,QAAQ,QAAQ;GAC5D,SAAS,OAAO,QAAQ;EAC1B,CAAC;CACH;CAEA,OAAO;AACT;AAEA,SAAS,2BACP,UACoC;CACpC,IAAI,CAAC,YAAY,SAAS,WAAW,GACnC;CAGF,MAAM,WAAW,SAAS,QACvB,WAAW,uBAAuB,MAAM,CAAC,EAAE,SAAS,OACvD;CAEA,OAAO,SAAS,SAAS,IAAI,WAAW;AAC1C"}
1
+ {"version":3,"file":"static-routes.js","names":[],"sources":["../../src/ssg/static-routes.ts"],"sourcesContent":["/**\n * SSG route source normalization and runtime-only filtering.\n */\n\nimport type { RouteConfig, RouteRenderResult } from './types';\nimport type { RoutePolicy, RouteRegistry } from '../common/router';\nimport { _getBuiltInRoutePolicy } from '../router/route';\nimport { expandRoutes } from './resolve-ssg-data';\nimport {\n getOutputFilePath,\n interpolateRoutePath,\n resolveRouteDescriptor,\n} from './route-utils';\n\ntype StaticRouteSource = {\n registry?: RouteRegistry;\n routes?: readonly RouteConfig[];\n};\n\nexport type RuntimeOnlyRoute = {\n routeId: string;\n result: RouteRenderResult;\n};\n\nexport interface SplitStaticRoutesResult {\n routes: RouteConfig[];\n runtimeOnly: RuntimeOnlyRoute[];\n outputRouteIds: string[];\n}\n\nfunction getRuntimeOnlyDiagnostic(\n route: RouteConfig,\n path: string\n): string | null {\n const policies = route.policies ?? [];\n\n if (route.auth === true) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (route.role) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (route.permission) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n if (policies.length > 0) {\n let hasAuthPolicy = false;\n let hasRolePolicy = false;\n let hasPermissionPolicy = false;\n\n for (const policy of policies) {\n const metadata = _getBuiltInRoutePolicy(policy);\n if (!metadata) {\n return `Skipped prerender for \"${path}\": routes with custom policies are runtime-only by default.`;\n }\n\n if (metadata.kind === 'auth') {\n hasAuthPolicy = true;\n } else if (metadata.kind === 'role') {\n hasRolePolicy = true;\n } else if (metadata.kind === 'permission') {\n hasPermissionPolicy = true;\n }\n }\n\n if (hasAuthPolicy) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (hasRolePolicy) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (hasPermissionPolicy) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n return null;\n }\n\n return null;\n}\n\nfunction getRouteResultPath(route: RouteConfig): string {\n return route.params\n ? interpolateRoutePath(route.path, route.params)\n : route.path;\n}\n\nfunction createRuntimeOnlyRoute(\n route: RouteConfig,\n diagnostic: string\n): RuntimeOnlyRoute {\n const path = getRouteResultPath(route);\n const filePath = getOutputFilePath(path);\n\n return {\n routeId: `${path}::${filePath}`,\n result: {\n path,\n filePath,\n html: '',\n fileSize: 0,\n renderDuration: 0,\n resourceCount: 0,\n status: 'skipped',\n reason: 'runtime-only',\n written: false,\n error: diagnostic,\n },\n };\n}\n\nexport async function splitStaticRoutes(\n routes: readonly RouteConfig[]\n): Promise<SplitStaticRoutesResult> {\n const prerenderableRoutes: RouteConfig[] = [];\n const runtimeOnly: RuntimeOnlyRoute[] = [];\n const outputRouteIds: string[] = [];\n\n for (const route of routes) {\n const routePath = getRouteResultPath(route);\n const diagnostic = getRuntimeOnlyDiagnostic(route, routePath);\n if (diagnostic) {\n const runtimeRoute = createRuntimeOnlyRoute(route, diagnostic);\n runtimeOnly.push(runtimeRoute);\n outputRouteIds.push(runtimeRoute.routeId);\n continue;\n }\n\n const expanded = await expandRoutes([route]);\n prerenderableRoutes.push(...expanded);\n for (const expandedRoute of expanded) {\n outputRouteIds.push(resolveRouteDescriptor(expandedRoute).routeId);\n }\n }\n\n return {\n routes: prerenderableRoutes,\n runtimeOnly,\n outputRouteIds,\n };\n}\n\nexport function normalizeStaticRoutes(\n options: StaticRouteSource\n): RouteConfig[] {\n if (options.registry) {\n return routeRegistryToRouteConfigs(options.registry);\n }\n\n return [...(options.routes ?? [])];\n}\n\nfunction routeRegistryToRouteConfigs(registry: RouteRegistry): RouteConfig[] {\n const routeConfigs: RouteConfig[] = [];\n\n for (const record of registry.manifest.records) {\n if (record.isFallback) {\n continue;\n }\n\n routeConfigs.push({\n path: record.path,\n handler: record.handler,\n namespace: record.options.namespace,\n auth: record.options.auth,\n role: record.options.role,\n permission: record.options.permission,\n policies: stripRegistryGuestPolicies(record.options.policies),\n entries: record.options.entries,\n });\n }\n\n return routeConfigs;\n}\n\nfunction stripRegistryGuestPolicies(\n policies: readonly RoutePolicy[] | undefined\n): readonly RoutePolicy[] | undefined {\n if (!policies || policies.length === 0) {\n return undefined;\n }\n\n const filtered = policies.filter(\n (policy) => _getBuiltInRoutePolicy(policy)?.kind !== 'guest'\n );\n\n return filtered.length > 0 ? filtered : undefined;\n}\n"],"mappings":";;;;;AA8BA,SAAS,yBACP,OACA,MACe;CACf,MAAM,WAAW,MAAM,YAAY,CAAC;CAEpC,IAAI,MAAM,SAAS,MACjB,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,MACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,YACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,SAAS,SAAS,GAAG;EACvB,IAAI,gBAAgB;EACpB,IAAI,gBAAgB;EACpB,IAAI,sBAAsB;EAE1B,KAAK,MAAM,UAAU,UAAU;GAC7B,MAAM,WAAW,uBAAuB,MAAM;GAC9C,IAAI,CAAC,UACH,OAAO,0BAA0B,KAAK;GAGxC,IAAI,SAAS,SAAS,QACpB,gBAAgB;QACX,IAAI,SAAS,SAAS,QAC3B,gBAAgB;QACX,IAAI,SAAS,SAAS,cAC3B,sBAAsB;EAE1B;EAEA,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,qBACF,OAAO,0BAA0B,KAAK;EAGxC,OAAO;CACT;CAEA,OAAO;AACT;AAEA,SAAS,mBAAmB,OAA4B;CACtD,OAAO,MAAM,SACT,qBAAqB,MAAM,MAAM,MAAM,MAAM,IAC7C,MAAM;AACZ;AAEA,SAAS,uBACP,OACA,YACkB;CAClB,MAAM,OAAO,mBAAmB,KAAK;CACrC,MAAM,WAAW,kBAAkB,IAAI;CAEvC,OAAO;EACL,SAAS,GAAG,KAAK,IAAI;EACrB,QAAQ;GACN;GACA;GACA,MAAM;GACN,UAAU;GACV,gBAAgB;GAChB,eAAe;GACf,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,OAAO;EACT;CACF;AACF;AAEA,eAAsB,kBACpB,QACkC;CAClC,MAAM,sBAAqC,CAAC;CAC5C,MAAM,cAAkC,CAAC;CACzC,MAAM,iBAA2B,CAAC;CAElC,KAAK,MAAM,SAAS,QAAQ;EAE1B,MAAM,aAAa,yBAAyB,OAD1B,mBAAmB,KACc,CAAS;EAC5D,IAAI,YAAY;GACd,MAAM,eAAe,uBAAuB,OAAO,UAAU;GAC7D,YAAY,KAAK,YAAY;GAC7B,eAAe,KAAK,aAAa,OAAO;GACxC;EACF;EAEA,MAAM,WAAW,MAAM,aAAa,CAAC,KAAK,CAAC;EAC3C,oBAAoB,KAAK,GAAG,QAAQ;EACpC,KAAK,MAAM,iBAAiB,UAC1B,eAAe,KAAK,uBAAuB,aAAa,CAAC,CAAC,OAAO;CAErE;CAEA,OAAO;EACL,QAAQ;EACR;EACA;CACF;AACF;AAEA,SAAgB,sBACd,SACe;CACf,IAAI,QAAQ,UACV,OAAO,4BAA4B,QAAQ,QAAQ;CAGrD,OAAO,CAAC,GAAI,QAAQ,UAAU,CAAC,CAAE;AACnC;AAEA,SAAS,4BAA4B,UAAwC;CAC3E,MAAM,eAA8B,CAAC;CAErC,KAAK,MAAM,UAAU,SAAS,SAAS,SAAS;EAC9C,IAAI,OAAO,YACT;EAGF,aAAa,KAAK;GAChB,MAAM,OAAO;GACb,SAAS,OAAO;GAChB,WAAW,OAAO,QAAQ;GAC1B,MAAM,OAAO,QAAQ;GACrB,MAAM,OAAO,QAAQ;GACrB,YAAY,OAAO,QAAQ;GAC3B,UAAU,2BAA2B,OAAO,QAAQ,QAAQ;GAC5D,SAAS,OAAO,QAAQ;EAC1B,CAAC;CACH;CAEA,OAAO;AACT;AAEA,SAAS,2BACP,UACoC;CACpC,IAAI,CAAC,YAAY,SAAS,WAAW,GACnC;CAGF,MAAM,WAAW,SAAS,QACvB,WAAW,uBAAuB,MAAM,CAAC,EAAE,SAAS,OACvD;CAEA,OAAO,SAAS,SAAS,IAAI,WAAW;AAC1C"}
@@ -1,8 +1,8 @@
1
1
  import { __CONTROL_BOUNDARY__ } from "../common/control.js";
2
2
  import { ELEMENT_TYPE } from "../common/jsx.js";
3
- import { evaluateForState } from "../runtime/for-internal.js";
4
- import "../runtime/for.js";
5
3
  import { evaluateCaseState, evaluateShowState } from "../runtime/control.js";
4
+ import { evaluateForState } from "../runtime/for-internal.js";
5
+ import "../runtime/index.js";
6
6
  import "../jsx/index.js";
7
7
  //#region src/ssr/boundaries.ts
8
8
  function normalizeRenderableChildren(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"boundaries.js","names":[],"sources":["../../src/ssr/boundaries.ts"],"sourcesContent":["/**\n * Shared SSR boundary state and renderable child helpers.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport { __CONTROL_BOUNDARY__ } from '../common/control';\nimport type { DOMElement } from '../common/vnode';\nimport { ELEMENT_TYPE } from '../jsx';\nimport type { ComponentInstance } from '../runtime/component';\nimport {\n type ControlBoundaryState,\n evaluateCaseState,\n evaluateShowState,\n} from '../runtime/control';\nimport { evaluateForState } from '../runtime/for';\nimport type { VNode } from './types';\n\ntype ErrorBoundaryState = NonNullable<ComponentInstance['errorBoundaryState']>;\n\nexport function normalizeRenderableChildren(value: unknown): unknown[] {\n if (value === null || value === undefined || value === false) {\n return [];\n }\n\n return Array.isArray(value) ? value : [value];\n}\n\nexport function getRenderableChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (Array.isArray((node as VNode).children)) {\n return (node as VNode).children;\n }\n if (Array.isArray(node.props?.children)) {\n return node.props.children as unknown[];\n }\n if (\n node.props?.children !== undefined &&\n node.props.children !== null &&\n node.props.children !== false\n ) {\n return [node.props.children];\n }\n return undefined;\n}\n\nexport function getErrorBoundaryState(\n node: VNode | JSXElement\n): ErrorBoundaryState | null {\n return (\n (node as DOMElement & { __instance?: ComponentInstance }).__instance\n ?.errorBoundaryState ?? null\n );\n}\n\nexport function resetErrorBoundaryState(node: VNode | JSXElement): void {\n const instance = (node as DOMElement & { __instance?: ComponentInstance })\n .__instance;\n const state = instance?.errorBoundaryState;\n if (state) {\n state.error = null;\n state.notified = false;\n }\n}\n\nexport function createErrorBoundaryReset(node: VNode | JSXElement): () => void {\n return () => resetErrorBoundaryState(node);\n}\n\nfunction createDefaultErrorBoundaryFallbackVNode(error: unknown): JSXElement {\n const message =\n error instanceof Error\n ? error.stack || error.message || error.name\n : typeof error === 'string'\n ? error\n : (() => {\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n })();\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: 'div',\n props: {\n role: 'alert',\n 'data-askr-error-boundary': 'true',\n style: {\n boxSizing: 'border-box',\n padding: '1rem',\n border: '1px solid currentColor',\n borderRadius: '0.75rem',\n display: 'grid',\n gap: '0.75rem',\n maxWidth: '100%',\n },\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'strong',\n props: {\n children: ['Something went wrong while rendering this view.'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'p',\n props: {\n style: { margin: '0' },\n children: [\n 'The app recovered into a visible fallback so the error is not hidden in the console.',\n ],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'details',\n props: {\n open: process.env.NODE_ENV !== 'production',\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'summary',\n props: {\n children: ['Error details'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'pre',\n props: {\n style: {\n margin: '0',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n },\n children: [message],\n },\n },\n ],\n },\n },\n ],\n },\n key: null,\n } as JSXElement;\n}\n\nexport function resolveErrorBoundaryFallbackNode(\n fallback: unknown,\n error: unknown,\n reset: () => void\n): unknown {\n return typeof fallback === 'function'\n ? (fallback as (error: unknown, reset: () => void) => unknown)(error, reset)\n : fallback !== undefined\n ? fallback\n : createDefaultErrorBoundaryFallbackVNode(error);\n}\n\nexport function getControlBoundaryState(\n node: VNode | JSXElement\n): ControlBoundaryState | null {\n const boundaryNode = node as DOMElement;\n\n return (\n boundaryNode._controlState ??\n (boundaryNode._forState as ControlBoundaryState | undefined) ??\n null\n );\n}\n\nexport function evaluateControlBoundaryChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (node.type !== __CONTROL_BOUNDARY__) {\n return undefined;\n }\n\n const controlState = getControlBoundaryState(node);\n if (!controlState) {\n return [];\n }\n\n if (controlState.kind === 'for') {\n return evaluateForState(controlState);\n }\n if (controlState.kind === 'show') {\n return evaluateShowState(controlState);\n }\n return evaluateCaseState(controlState);\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,4BAA4B,OAA2B;CACrE,IAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,OACrD,OAAO,CAAC;CAGV,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAEA,SAAgB,sBACd,MACuB;CACvB,IAAI,MAAM,QAAS,KAAe,QAAQ,GACxC,OAAQ,KAAe;CAEzB,IAAI,MAAM,QAAQ,KAAK,OAAO,QAAQ,GACpC,OAAO,KAAK,MAAM;CAEpB,IACE,KAAK,OAAO,aAAa,UACzB,KAAK,MAAM,aAAa,QACxB,KAAK,MAAM,aAAa,OAExB,OAAO,CAAC,KAAK,MAAM,QAAQ;AAG/B;AAEA,SAAgB,sBACd,MAC2B;CAC3B,OACG,KAAyD,YACtD,sBAAsB;AAE9B;AAEA,SAAgB,wBAAwB,MAAgC;CAGtE,MAAM,QAFY,KACf,YACqB;CACxB,IAAI,OAAO;EACT,MAAM,QAAQ;EACd,MAAM,WAAW;CACnB;AACF;AAEA,SAAgB,yBAAyB,MAAsC;CAC7E,aAAa,wBAAwB,IAAI;AAC3C;AAEA,SAAS,wCAAwC,OAA4B;CAC3E,MAAM,UACJ,iBAAiB,QACb,MAAM,SAAS,MAAM,WAAW,MAAM,OACtC,OAAO,UAAU,WACf,eACO;EACL,IAAI;GACF,OAAO,KAAK,UAAU,KAAK;EAC7B,QAAQ;GACN,OAAO,OAAO,KAAK;EACrB;CACF,EAAA,CAAG;CAEX,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO;GACL,MAAM;GACN,4BAA4B;GAC5B,OAAO;IACL,WAAW;IACX,SAAS;IACT,QAAQ;IACR,cAAc;IACd,SAAS;IACT,KAAK;IACL,UAAU;GACZ;GACA,UAAU;IACR;KACE,UAAU;KACV,MAAM;KACN,OAAO,EACL,UAAU,CAAC,iDAAiD,EAC9D;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,OAAO,EAAE,QAAQ,IAAI;MACrB,UAAU,CACR,sFACF;KACF;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,MAAA;MACA,UAAU,CACR;OACE,UAAU;OACV,MAAM;OACN,OAAO,EACL,UAAU,CAAC,eAAe,EAC5B;MACF,GACA;OACE,UAAU;OACV,MAAM;OACN,OAAO;QACL,OAAO;SACL,QAAQ;SACR,YAAY;SACZ,WAAW;QACb;QACA,UAAU,CAAC,OAAO;OACpB;MACF,CACF;KACF;IACF;GACF;EACF;EACA,KAAK;CACP;AACF;AAEA,SAAgB,iCACd,UACA,OACA,OACS;CACT,OAAO,OAAO,aAAa,aACtB,SAA4D,OAAO,KAAK,IACzE,aAAa,SACX,WACA,wCAAwC,KAAK;AACrD;AAEA,SAAgB,wBACd,MAC6B;CAC7B,MAAM,eAAe;CAErB,OACE,aAAa,iBACZ,aAAa,aACd;AAEJ;AAEA,SAAgB,gCACd,MACuB;CACvB,IAAI,KAAK,SAAS,sBAChB;CAGF,MAAM,eAAe,wBAAwB,IAAI;CACjD,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,IAAI,aAAa,SAAS,OACxB,OAAO,iBAAiB,YAAY;CAEtC,IAAI,aAAa,SAAS,QACxB,OAAO,kBAAkB,YAAY;CAEvC,OAAO,kBAAkB,YAAY;AACvC"}
1
+ {"version":3,"file":"boundaries.js","names":[],"sources":["../../src/ssr/boundaries.ts"],"sourcesContent":["/**\n * Shared SSR boundary state and renderable child helpers.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport { __CONTROL_BOUNDARY__ } from '../common/control';\nimport type { DOMElement } from '../common/vnode';\nimport { ELEMENT_TYPE } from '../jsx';\nimport type { ComponentInstance } from '../runtime';\nimport {\n type ControlBoundaryState,\n evaluateCaseState,\n evaluateShowState,\n} from '../runtime';\nimport { evaluateForState } from '../runtime';\nimport type { VNode } from './types';\n\ntype ErrorBoundaryState = NonNullable<ComponentInstance['errorBoundaryState']>;\n\nexport function normalizeRenderableChildren(value: unknown): unknown[] {\n if (value === null || value === undefined || value === false) {\n return [];\n }\n\n return Array.isArray(value) ? value : [value];\n}\n\nexport function getRenderableChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (Array.isArray((node as VNode).children)) {\n return (node as VNode).children;\n }\n if (Array.isArray(node.props?.children)) {\n return node.props.children as unknown[];\n }\n if (\n node.props?.children !== undefined &&\n node.props.children !== null &&\n node.props.children !== false\n ) {\n return [node.props.children];\n }\n return undefined;\n}\n\nexport function getErrorBoundaryState(\n node: VNode | JSXElement\n): ErrorBoundaryState | null {\n return (\n (node as DOMElement & { __instance?: ComponentInstance }).__instance\n ?.errorBoundaryState ?? null\n );\n}\n\nexport function resetErrorBoundaryState(node: VNode | JSXElement): void {\n const instance = (node as DOMElement & { __instance?: ComponentInstance })\n .__instance;\n const state = instance?.errorBoundaryState;\n if (state) {\n state.error = null;\n state.notified = false;\n }\n}\n\nexport function createErrorBoundaryReset(node: VNode | JSXElement): () => void {\n return () => resetErrorBoundaryState(node);\n}\n\nfunction createDefaultErrorBoundaryFallbackVNode(error: unknown): JSXElement {\n const message =\n error instanceof Error\n ? error.stack || error.message || error.name\n : typeof error === 'string'\n ? error\n : (() => {\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n })();\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: 'div',\n props: {\n role: 'alert',\n 'data-askr-error-boundary': 'true',\n style: {\n boxSizing: 'border-box',\n padding: '1rem',\n border: '1px solid currentColor',\n borderRadius: '0.75rem',\n display: 'grid',\n gap: '0.75rem',\n maxWidth: '100%',\n },\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'strong',\n props: {\n children: ['Something went wrong while rendering this view.'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'p',\n props: {\n style: { margin: '0' },\n children: [\n 'The app recovered into a visible fallback so the error is not hidden in the console.',\n ],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'details',\n props: {\n open: process.env.NODE_ENV !== 'production',\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'summary',\n props: {\n children: ['Error details'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'pre',\n props: {\n style: {\n margin: '0',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n },\n children: [message],\n },\n },\n ],\n },\n },\n ],\n },\n key: null,\n } as JSXElement;\n}\n\nexport function resolveErrorBoundaryFallbackNode(\n fallback: unknown,\n error: unknown,\n reset: () => void\n): unknown {\n return typeof fallback === 'function'\n ? (fallback as (error: unknown, reset: () => void) => unknown)(error, reset)\n : fallback !== undefined\n ? fallback\n : createDefaultErrorBoundaryFallbackVNode(error);\n}\n\nexport function getControlBoundaryState(\n node: VNode | JSXElement\n): ControlBoundaryState | null {\n const boundaryNode = node as DOMElement;\n\n return (\n boundaryNode._controlState ??\n (boundaryNode._forState as ControlBoundaryState | undefined) ??\n null\n );\n}\n\nexport function evaluateControlBoundaryChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (node.type !== __CONTROL_BOUNDARY__) {\n return undefined;\n }\n\n const controlState = getControlBoundaryState(node);\n if (!controlState) {\n return [];\n }\n\n if (controlState.kind === 'for') {\n return evaluateForState(controlState);\n }\n if (controlState.kind === 'show') {\n return evaluateShowState(controlState);\n }\n return evaluateCaseState(controlState);\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,4BAA4B,OAA2B;CACrE,IAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,OACrD,OAAO,CAAC;CAGV,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAEA,SAAgB,sBACd,MACuB;CACvB,IAAI,MAAM,QAAS,KAAe,QAAQ,GACxC,OAAQ,KAAe;CAEzB,IAAI,MAAM,QAAQ,KAAK,OAAO,QAAQ,GACpC,OAAO,KAAK,MAAM;CAEpB,IACE,KAAK,OAAO,aAAa,UACzB,KAAK,MAAM,aAAa,QACxB,KAAK,MAAM,aAAa,OAExB,OAAO,CAAC,KAAK,MAAM,QAAQ;AAG/B;AAEA,SAAgB,sBACd,MAC2B;CAC3B,OACG,KAAyD,YACtD,sBAAsB;AAE9B;AAEA,SAAgB,wBAAwB,MAAgC;CAGtE,MAAM,QAFY,KACf,YACqB;CACxB,IAAI,OAAO;EACT,MAAM,QAAQ;EACd,MAAM,WAAW;CACnB;AACF;AAEA,SAAgB,yBAAyB,MAAsC;CAC7E,aAAa,wBAAwB,IAAI;AAC3C;AAEA,SAAS,wCAAwC,OAA4B;CAC3E,MAAM,UACJ,iBAAiB,QACb,MAAM,SAAS,MAAM,WAAW,MAAM,OACtC,OAAO,UAAU,WACf,eACO;EACL,IAAI;GACF,OAAO,KAAK,UAAU,KAAK;EAC7B,QAAQ;GACN,OAAO,OAAO,KAAK;EACrB;CACF,EAAA,CAAG;CAEX,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO;GACL,MAAM;GACN,4BAA4B;GAC5B,OAAO;IACL,WAAW;IACX,SAAS;IACT,QAAQ;IACR,cAAc;IACd,SAAS;IACT,KAAK;IACL,UAAU;GACZ;GACA,UAAU;IACR;KACE,UAAU;KACV,MAAM;KACN,OAAO,EACL,UAAU,CAAC,iDAAiD,EAC9D;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,OAAO,EAAE,QAAQ,IAAI;MACrB,UAAU,CACR,sFACF;KACF;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,MAAA;MACA,UAAU,CACR;OACE,UAAU;OACV,MAAM;OACN,OAAO,EACL,UAAU,CAAC,eAAe,EAC5B;MACF,GACA;OACE,UAAU;OACV,MAAM;OACN,OAAO;QACL,OAAO;SACL,QAAQ;SACR,YAAY;SACZ,WAAW;QACb;QACA,UAAU,CAAC,OAAO;OACpB;MACF,CACF;KACF;IACF;GACF;EACF;EACA,KAAK;CACP;AACF;AAEA,SAAgB,iCACd,UACA,OACA,OACS;CACT,OAAO,OAAO,aAAa,aACtB,SAA4D,OAAO,KAAK,IACzE,aAAa,SACX,WACA,wCAAwC,KAAK;AACrD;AAEA,SAAgB,wBACd,MAC6B;CAC7B,MAAM,eAAe;CAErB,OACE,aAAa,iBACZ,aAAa,aACd;AAEJ;AAEA,SAAgB,gCACd,MACuB;CACvB,IAAI,KAAK,SAAS,sBAChB;CAGF,MAAM,eAAe,wBAAwB,IAAI;CACjD,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,IAAI,aAAa,SAAS,OACxB,OAAO,iBAAiB,YAAY;CAEtC,IAAI,aAAa,SAAS,QACxB,OAAO,kBAAkB,YAAY;CAEvC,OAAO,kBAAkB,YAAY;AACvC"}
@@ -3,8 +3,8 @@ import { getCurrentComponentInstance, setCurrentComponentInstance } from "../run
3
3
  import { cleanupComponent } from "../runtime/component-cleanup.js";
4
4
  import { isPromiseLike } from "../common/promise.js";
5
5
  import { createComponentInstance } from "../runtime/component-internal.js";
6
- import "../runtime/component.js";
7
- import { DefaultPortal, disposeDefaultPortalScope } from "../foundations/structures/portal.js";
6
+ import { DefaultPortal, disposeDefaultPortalScope } from "../runtime/portal.js";
7
+ import "../runtime/index.js";
8
8
  import "../jsx/index.js";
9
9
  import { throwSSRDataMissing } from "./context.js";
10
10
  //#region src/ssr/component-runtime.ts
@@ -87,7 +87,7 @@ function wrapWithDefaultPortal(out) {
87
87
  const portalVNode = {
88
88
  $$typeof: ELEMENT_TYPE,
89
89
  type: DefaultPortal,
90
- props: {},
90
+ props: { __askrAutoDefaultPortal: true },
91
91
  key: "__default_portal"
92
92
  };
93
93
  if (out == null) return {
@@ -1 +1 @@
1
- {"version":3,"file":"component-runtime.js","names":[],"sources":["../../src/ssr/component-runtime.ts"],"sourcesContent":["/**\n * SSR component execution and temporary owner lifecycle.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport type { Props } from '../common/props';\nimport type { ComponentFunction } from '../common/component';\nimport { isPromiseLike } from '../common/promise';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport { DefaultPortal } from '../foundations/structures/portal';\nimport { disposeDefaultPortalScope } from '../foundations/structures/portal';\nimport {\n cleanupComponent,\n createComponentInstance,\n getCurrentComponentInstance,\n setCurrentComponentInstance,\n} from '../runtime/component';\nimport { throwSSRDataMissing, type RenderContext } from './context';\nimport type { SSRComponent, VNode } from './types';\n\nexport type Component = SSRComponent;\n\nconst __ssrGuardStack: Array<{ random: () => number; now: () => number }> = [];\n\nfunction pushSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n __ssrGuardStack.push({\n random: Reflect.get(Math, 'random') as () => number,\n now: Reflect.get(Date, 'now') as () => number,\n });\n Reflect.set(Math, 'random', () => {\n throw new Error(\n 'SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead.'\n );\n });\n Reflect.set(Date, 'now', () => {\n throw new Error(\n 'SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers.'\n );\n });\n}\n\nfunction popSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n const prev = __ssrGuardStack.pop();\n if (prev) {\n Reflect.set(Math, 'random', prev.random);\n Reflect.set(Date, 'now', prev.now);\n }\n}\n\nexport function executeComponentSync(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n try {\n if (process.env.NODE_ENV !== 'production') {\n pushSSRStrictPurityGuard();\n }\n const prev = getCurrentComponentInstance();\n const temp = createComponentInstance(\n 'ssr-temp',\n component as ComponentFunction,\n (props || {}) as Props,\n null\n );\n temp.ssr = true;\n temp.portalScope = temp;\n ctx.ssrCleanupFns.push(() => {\n let cleanupError: unknown = null;\n\n try {\n cleanupComponent(temp);\n } catch (error) {\n cleanupError = error;\n }\n\n try {\n disposeDefaultPortalScope(temp);\n } catch (error) {\n if (cleanupError) {\n throw new AggregateError(\n [cleanupError, error],\n 'SSR temporary owner cleanup failed'\n );\n }\n throw error;\n }\n\n if (cleanupError) {\n throw cleanupError;\n }\n });\n setCurrentComponentInstance(temp);\n try {\n const result = component((props || {}) as Props, { ssr: ctx });\n if (isPromiseLike(result)) {\n throwSSRDataMissing();\n }\n if (\n typeof result === 'string' ||\n typeof result === 'number' ||\n typeof result === 'boolean' ||\n result === null ||\n result === undefined\n ) {\n const inner =\n result === null || result === undefined || result === false\n ? ''\n : String(result);\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: inner ? [inner] : [] },\n } as unknown as VNode | JSXElement;\n }\n return result as VNode | JSXElement;\n } finally {\n setCurrentComponentInstance(prev);\n }\n } finally {\n if (process.env.NODE_ENV !== 'production') popSSRStrictPurityGuard();\n }\n}\n\nexport function disposeSSRTemporaryOwners(ctx: RenderContext): void {\n const cleanupFns = ctx.ssrCleanupFns;\n ctx.ssrCleanupFns = [];\n const cleanupErrors: unknown[] = [];\n\n for (let index = cleanupFns.length - 1; index >= 0; index -= 1) {\n try {\n cleanupFns[index]();\n } catch (error) {\n cleanupErrors.push(error);\n }\n }\n\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n\n if (cleanupErrors.length > 1) {\n throw new AggregateError(\n cleanupErrors,\n 'SSR temporary owner cleanup failed'\n );\n }\n}\n\nfunction wrapWithDefaultPortal(out: unknown): VNode | JSXElement {\n if (isPromiseLike(out)) {\n throwSSRDataMissing();\n }\n\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: {},\n key: '__default_portal',\n } as unknown;\n\n if (out == null) {\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [portalVNode] },\n } as unknown as VNode | JSXElement;\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [out as unknown, portalVNode] },\n } as unknown as VNode | JSXElement;\n}\n\nexport function renderSyncComponentRoot(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n const wrapped: Component = (\n p?: Record<string, unknown>,\n c?: { signal?: AbortSignal; ssr?: RenderContext }\n ) => wrapWithDefaultPortal(component(p ?? {}, c));\n\n return executeComponentSync(wrapped, props || {}, ctx);\n}\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,kBAAsE,CAAC;AAE7E,SAAS,2BAA2B;CAGlC,gBAAgB,KAAK;EACnB,QAAQ,QAAQ,IAAI,MAAM,QAAQ;EAClC,KAAK,QAAQ,IAAI,MAAM,KAAK;CAC9B,CAAC;CACD,QAAQ,IAAI,MAAM,gBAAgB;EAChC,MAAM,IAAI,MACR,mHACF;CACF,CAAC;CACD,QAAQ,IAAI,MAAM,aAAa;EAC7B,MAAM,IAAI,MACR,6HACF;CACF,CAAC;AACH;AAEA,SAAS,0BAA0B;CAGjC,MAAM,OAAO,gBAAgB,IAAI;CACjC,IAAI,MAAM;EACR,QAAQ,IAAI,MAAM,UAAU,KAAK,MAAM;EACvC,QAAQ,IAAI,MAAM,OAAO,KAAK,GAAG;CACnC;AACF;AAEA,SAAgB,qBACd,WACA,OACA,KACoB;CACpB,IAAI;EAEA,yBAAyB;EAE3B,MAAM,OAAO,4BAA4B;EACzC,MAAM,OAAO,wBACX,YACA,WACC,SAAS,CAAC,GACX,IACF;EACA,KAAK,MAAM;EACX,KAAK,cAAc;EACnB,IAAI,cAAc,WAAW;GAC3B,IAAI,eAAwB;GAE5B,IAAI;IACF,iBAAiB,IAAI;GACvB,SAAS,OAAO;IACd,eAAe;GACjB;GAEA,IAAI;IACF,0BAA0B,IAAI;GAChC,SAAS,OAAO;IACd,IAAI,cACF,MAAM,IAAI,eACR,CAAC,cAAc,KAAK,GACpB,oCACF;IAEF,MAAM;GACR;GAEA,IAAI,cACF,MAAM;EAEV,CAAC;EACD,4BAA4B,IAAI;EAChC,IAAI;GACF,MAAM,SAAS,UAAW,SAAS,CAAC,GAAa,EAAE,KAAK,IAAI,CAAC;GAC7D,IAAI,cAAc,MAAM,GACtB,oBAAoB;GAEtB,IACE,OAAO,WAAW,YAClB,OAAO,WAAW,YAClB,OAAO,WAAW,aAClB,WAAW,QACX,WAAW,QACX;IACA,MAAM,QACJ,WAAW,QAAQ,WAAW,UAAa,WAAW,QAClD,KACA,OAAO,MAAM;IACnB,OAAO;KACL,UAAU;KACV,MAAM;KACN,OAAO,EAAE,UAAU,QAAQ,CAAC,KAAK,IAAI,CAAC,EAAE;IAC1C;GACF;GACA,OAAO;EACT,UAAU;GACR,4BAA4B,IAAI;EAClC;CACF,UAAU;EACmC,wBAAwB;CACrE;AACF;AAEA,SAAgB,0BAA0B,KAA0B;CAClE,MAAM,aAAa,IAAI;CACvB,IAAI,gBAAgB,CAAC;CACrB,MAAM,gBAA2B,CAAC;CAElC,KAAK,IAAI,QAAQ,WAAW,SAAS,GAAG,SAAS,GAAG,SAAS,GAC3D,IAAI;EACF,WAAW,MAAM,CAAC;CACpB,SAAS,OAAO;EACd,cAAc,KAAK,KAAK;CAC1B;CAGF,IAAI,cAAc,WAAW,GAC3B,MAAM,cAAc;CAGtB,IAAI,cAAc,SAAS,GACzB,MAAM,IAAI,eACR,eACA,oCACF;AAEJ;AAEA,SAAS,sBAAsB,KAAkC;CAC/D,IAAI,cAAc,GAAG,GACnB,oBAAoB;CAGtB,MAAM,cAAc;EAClB,UAAU;EACV,MAAM;EACN,OAAO,CAAC;EACR,KAAK;CACP;CAEA,IAAI,OAAO,MACT,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU,CAAC,WAAW,EAAE;CACnC;CAGF,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU,CAAC,KAAgB,WAAW,EAAE;CACnD;AACF;AAEA,SAAgB,wBACd,WACA,OACA,KACoB;CACpB,MAAM,WACJ,GACA,MACG,sBAAsB,UAAU,KAAK,CAAC,GAAG,CAAC,CAAC;CAEhD,OAAO,qBAAqB,SAAS,SAAS,CAAC,GAAG,GAAG;AACvD"}
1
+ {"version":3,"file":"component-runtime.js","names":[],"sources":["../../src/ssr/component-runtime.ts"],"sourcesContent":["/**\n * SSR component execution and temporary owner lifecycle.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport type { Props } from '../common/props';\nimport type { ComponentFunction } from '../common/component';\nimport { isPromiseLike } from '../common/promise';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport {\n cleanupComponent,\n createComponentInstance,\n DefaultPortal,\n disposeDefaultPortalScope,\n getCurrentComponentInstance,\n setCurrentComponentInstance,\n} from '../runtime';\nimport { throwSSRDataMissing, type RenderContext } from './context';\nimport type { SSRComponent, VNode } from './types';\n\nexport type Component = SSRComponent;\n\nconst __ssrGuardStack: Array<{ random: () => number; now: () => number }> = [];\n\nfunction pushSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n __ssrGuardStack.push({\n random: Reflect.get(Math, 'random') as () => number,\n now: Reflect.get(Date, 'now') as () => number,\n });\n Reflect.set(Math, 'random', () => {\n throw new Error(\n 'SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead.'\n );\n });\n Reflect.set(Date, 'now', () => {\n throw new Error(\n 'SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers.'\n );\n });\n}\n\nfunction popSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n const prev = __ssrGuardStack.pop();\n if (prev) {\n Reflect.set(Math, 'random', prev.random);\n Reflect.set(Date, 'now', prev.now);\n }\n}\n\nexport function executeComponentSync(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n try {\n if (process.env.NODE_ENV !== 'production') {\n pushSSRStrictPurityGuard();\n }\n const prev = getCurrentComponentInstance();\n const temp = createComponentInstance(\n 'ssr-temp',\n component as ComponentFunction,\n (props || {}) as Props,\n null\n );\n temp.ssr = true;\n temp.portalScope = temp;\n ctx.ssrCleanupFns.push(() => {\n let cleanupError: unknown = null;\n\n try {\n cleanupComponent(temp);\n } catch (error) {\n cleanupError = error;\n }\n\n try {\n disposeDefaultPortalScope(temp);\n } catch (error) {\n if (cleanupError) {\n throw new AggregateError(\n [cleanupError, error],\n 'SSR temporary owner cleanup failed'\n );\n }\n throw error;\n }\n\n if (cleanupError) {\n throw cleanupError;\n }\n });\n setCurrentComponentInstance(temp);\n try {\n const result = component((props || {}) as Props, { ssr: ctx });\n if (isPromiseLike(result)) {\n throwSSRDataMissing();\n }\n if (\n typeof result === 'string' ||\n typeof result === 'number' ||\n typeof result === 'boolean' ||\n result === null ||\n result === undefined\n ) {\n const inner =\n result === null || result === undefined || result === false\n ? ''\n : String(result);\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: inner ? [inner] : [] },\n } as unknown as VNode | JSXElement;\n }\n return result as VNode | JSXElement;\n } finally {\n setCurrentComponentInstance(prev);\n }\n } finally {\n if (process.env.NODE_ENV !== 'production') popSSRStrictPurityGuard();\n }\n}\n\nexport function disposeSSRTemporaryOwners(ctx: RenderContext): void {\n const cleanupFns = ctx.ssrCleanupFns;\n ctx.ssrCleanupFns = [];\n const cleanupErrors: unknown[] = [];\n\n for (let index = cleanupFns.length - 1; index >= 0; index -= 1) {\n try {\n cleanupFns[index]();\n } catch (error) {\n cleanupErrors.push(error);\n }\n }\n\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n\n if (cleanupErrors.length > 1) {\n throw new AggregateError(\n cleanupErrors,\n 'SSR temporary owner cleanup failed'\n );\n }\n}\n\nfunction wrapWithDefaultPortal(out: unknown): VNode | JSXElement {\n if (isPromiseLike(out)) {\n throwSSRDataMissing();\n }\n\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: { __askrAutoDefaultPortal: true },\n key: '__default_portal',\n } as unknown;\n\n if (out == null) {\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [portalVNode] },\n } as unknown as VNode | JSXElement;\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [out as unknown, portalVNode] },\n } as unknown as VNode | JSXElement;\n}\n\nexport function renderSyncComponentRoot(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n const wrapped: Component = (\n p?: Record<string, unknown>,\n c?: { signal?: AbortSignal; ssr?: RenderContext }\n ) => wrapWithDefaultPortal(component(p ?? {}, c));\n\n return executeComponentSync(wrapped, props || {}, ctx);\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { resolveRouteFromRoutes } from "../router/resolution.js";
1
+ import { resolveRouteFromRoutes } from "../router/route-matching.js";
2
2
  import "../router/route.js";
3
3
  import { renderToString } from "./index-internal.js";
4
4
  import "./index.js";