@askrjs/askr 0.0.50 → 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 (227) 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/{dev → common}/logger.js +5 -6
  18. package/dist/common/logger.js.map +1 -0
  19. package/dist/common/vnode.js.map +1 -1
  20. package/dist/components/error-boundary.d.ts +2 -15
  21. package/dist/components/error-boundary.d.ts.map +1 -1
  22. package/dist/components/error-boundary.js +2 -74
  23. package/dist/components/error-boundary.js.map +1 -1
  24. package/dist/components/index.d.ts +2 -1
  25. package/dist/components/link.js +2 -0
  26. package/dist/components/link.js.map +1 -1
  27. package/dist/control/case.d.ts.map +1 -1
  28. package/dist/control/case.js +1 -0
  29. package/dist/control/case.js.map +1 -1
  30. package/dist/control/for.d.ts +3 -3
  31. package/dist/control/for.d.ts.map +1 -1
  32. package/dist/control/for.js +2 -2
  33. package/dist/control/for.js.map +1 -1
  34. package/dist/control/show.js +1 -0
  35. package/dist/control/show.js.map +1 -1
  36. package/dist/data/data-runtime.js.map +1 -1
  37. package/dist/data/invalidation.js +2 -2
  38. package/dist/data/invalidation.js.map +1 -1
  39. package/dist/data/mutation-cell.d.ts.map +1 -1
  40. package/dist/data/mutation-cell.js +1 -1
  41. package/dist/data/mutation-cell.js.map +1 -1
  42. package/dist/data/query-cell.js +2 -2
  43. package/dist/data/query-cell.js.map +1 -1
  44. package/dist/data/shared.js +1 -0
  45. package/dist/data/shared.js.map +1 -1
  46. package/dist/data/testing.js +2 -0
  47. package/dist/foundations/index.d.ts +1 -1
  48. package/dist/foundations/index.js +1 -1
  49. package/dist/foundations/state/controllable.d.ts +0 -1
  50. package/dist/foundations/state/controllable.d.ts.map +1 -1
  51. package/dist/foundations/state/controllable.js +1 -0
  52. package/dist/foundations/state/controllable.js.map +1 -1
  53. package/dist/foundations/structures/index.d.ts +1 -1
  54. package/dist/foundations/structures/index.js +2 -1
  55. package/dist/foundations/structures/portal.d.ts +2 -24
  56. package/dist/foundations/structures/portal.js +3 -187
  57. package/dist/fx/fx.js +2 -2
  58. package/dist/fx/fx.js.map +1 -1
  59. package/dist/fx/index.js +1 -0
  60. package/dist/index.d.ts +3 -3
  61. package/dist/index.js +4 -4
  62. package/dist/index.js.map +1 -1
  63. package/dist/jsx/types.d.ts.map +1 -1
  64. package/dist/jsx-dev-runtime.js +1 -0
  65. package/dist/jsx-dev-runtime.js.map +1 -1
  66. package/dist/jsx-runtime.js +1 -0
  67. package/dist/jsx-runtime.js.map +1 -1
  68. package/dist/renderer/attributes.js +1 -0
  69. package/dist/renderer/attributes.js.map +1 -1
  70. package/dist/renderer/boundaries.js +5 -5
  71. package/dist/renderer/boundaries.js.map +1 -1
  72. package/dist/renderer/child-shape.js +2 -2
  73. package/dist/renderer/child-shape.js.map +1 -1
  74. package/dist/renderer/children-fastpath.js +149 -0
  75. package/dist/renderer/children-fastpath.js.map +1 -0
  76. package/dist/renderer/children.js +3 -138
  77. package/dist/renderer/children.js.map +1 -1
  78. package/dist/renderer/cleanup.js +2 -2
  79. package/dist/renderer/cleanup.js.map +1 -1
  80. package/dist/renderer/component-host-cleanup.js +1 -1
  81. package/dist/renderer/component-host-cleanup.js.map +1 -1
  82. package/dist/renderer/component-host-instances.js +1 -1
  83. package/dist/renderer/component-host-instances.js.map +1 -1
  84. package/dist/renderer/component-host.js +1 -1
  85. package/dist/renderer/component-host.js.map +1 -1
  86. package/dist/renderer/dom-host.js.map +1 -1
  87. package/dist/renderer/dom-internal.js +5 -4
  88. package/dist/renderer/dom-internal.js.map +1 -1
  89. package/dist/renderer/dom.js +2 -1
  90. package/dist/renderer/element-children.js.map +1 -1
  91. package/dist/renderer/error-boundary-dom.js +51 -2
  92. package/dist/renderer/error-boundary-dom.js.map +1 -1
  93. package/dist/renderer/evaluate-reconcile.js +6 -5
  94. package/dist/renderer/evaluate-reconcile.js.map +1 -1
  95. package/dist/renderer/evaluate.js.map +1 -1
  96. package/dist/renderer/fastpath.js +3 -2
  97. package/dist/renderer/fastpath.js.map +1 -1
  98. package/dist/renderer/for-commit-dom-map.js.map +1 -1
  99. package/dist/renderer/for-commit-removal.js +2 -2
  100. package/dist/renderer/for-commit-removal.js.map +1 -1
  101. package/dist/renderer/for-commit-reorder.js +2 -2
  102. package/dist/renderer/for-commit-reorder.js.map +1 -1
  103. package/dist/renderer/for-commit.js +3 -3
  104. package/dist/renderer/for-commit.js.map +1 -1
  105. package/dist/renderer/index.js +3 -1
  106. package/dist/renderer/index.js.map +1 -1
  107. package/dist/renderer/prop-bindings.js +4 -4
  108. package/dist/renderer/prop-bindings.js.map +1 -1
  109. package/dist/renderer/reactive-child-dom.js.map +1 -1
  110. package/dist/renderer/reactive-children.js +4 -4
  111. package/dist/renderer/reactive-children.js.map +1 -1
  112. package/dist/renderer/reconcile-fastpaths.js +2 -1
  113. package/dist/renderer/reconcile-fastpaths.js.map +1 -1
  114. package/dist/renderer/reconcile-resolution.js +3 -3
  115. package/dist/renderer/reconcile-resolution.js.map +1 -1
  116. package/dist/renderer/retained-element-rollback.js +2 -1
  117. package/dist/renderer/retained-element-rollback.js.map +1 -1
  118. package/dist/renderer/stable-patch.js +2 -3
  119. package/dist/renderer/stable-patch.js.map +1 -1
  120. package/dist/renderer/utils.js +2 -1
  121. package/dist/renderer/utils.js.map +1 -1
  122. package/dist/resources/index.js +1 -2
  123. package/dist/router/activity.d.ts.map +1 -1
  124. package/dist/router/activity.js +20 -22
  125. package/dist/router/activity.js.map +1 -1
  126. package/dist/router/authoring.js +1 -1
  127. package/dist/router/authoring.js.map +1 -1
  128. package/dist/router/index.d.ts +1 -1
  129. package/dist/router/navigate.js +1 -1
  130. package/dist/router/navigate.js.map +1 -1
  131. package/dist/router/navigation-registry.js +1 -1
  132. package/dist/router/navigation-registry.js.map +1 -1
  133. package/dist/router/navigation-targets.d.ts.map +1 -1
  134. package/dist/router/navigation-targets.js +7 -5
  135. package/dist/router/navigation-targets.js.map +1 -1
  136. package/dist/router/rendering.js +1 -0
  137. package/dist/router/rendering.js.map +1 -1
  138. package/dist/router/resolution.d.ts +1 -14
  139. package/dist/router/resolution.d.ts.map +1 -1
  140. package/dist/router/resolution.js +6 -173
  141. package/dist/router/resolution.js.map +1 -1
  142. package/dist/router/route-matching.d.ts +20 -0
  143. package/dist/router/route-matching.d.ts.map +1 -0
  144. package/dist/router/route-matching.js +175 -0
  145. package/dist/router/route-matching.js.map +1 -0
  146. package/dist/router/route.js +4 -2
  147. package/dist/router/testing.js +4 -0
  148. package/dist/runtime/access.d.ts +20 -0
  149. package/dist/runtime/access.d.ts.map +1 -0
  150. package/dist/runtime/component-cleanup.js +1 -1
  151. package/dist/runtime/component-cleanup.js.map +1 -1
  152. package/dist/runtime/component-commit.js +1 -1
  153. package/dist/runtime/component-commit.js.map +1 -1
  154. package/dist/runtime/component-internal.d.ts +1 -1
  155. package/dist/runtime/component-internal.js +1 -1
  156. package/dist/runtime/component-internal.js.map +1 -1
  157. package/dist/runtime/component-lifecycle.d.ts +1 -1
  158. package/dist/runtime/component-lifecycle.js +1 -1
  159. package/dist/runtime/component-lifecycle.js.map +1 -1
  160. package/dist/runtime/component-scope.d.ts +1 -1
  161. package/dist/runtime/dev-namespace.d.ts +31 -0
  162. package/dist/runtime/dev-namespace.d.ts.map +1 -0
  163. package/dist/runtime/error-boundary.d.ts +5 -0
  164. package/dist/runtime/error-boundary.d.ts.map +1 -0
  165. package/dist/runtime/error-boundary.js +31 -0
  166. package/dist/runtime/error-boundary.js.map +1 -0
  167. package/dist/runtime/events.d.ts +58 -0
  168. package/dist/runtime/events.d.ts.map +1 -0
  169. package/dist/runtime/events.js +1 -1
  170. package/dist/runtime/events.js.map +1 -1
  171. package/dist/runtime/execution-model.d.ts +7 -0
  172. package/dist/runtime/execution-model.d.ts.map +1 -0
  173. package/dist/runtime/fastlane.d.ts +34 -0
  174. package/dist/runtime/fastlane.d.ts.map +1 -0
  175. package/dist/runtime/for-internal.d.ts +5 -5
  176. package/dist/runtime/for-internal.d.ts.map +1 -1
  177. package/dist/runtime/for-internal.js.map +1 -1
  178. package/dist/runtime/for-signals.d.ts +1 -1
  179. package/dist/runtime/for-signals.d.ts.map +1 -1
  180. package/dist/runtime/for-signals.js +1 -1
  181. package/dist/runtime/for-signals.js.map +1 -1
  182. package/dist/runtime/for-types.d.ts +9 -0
  183. package/dist/runtime/for-types.d.ts.map +1 -0
  184. package/dist/runtime/index.d.ts +24 -0
  185. package/dist/runtime/index.js +31 -0
  186. package/dist/runtime/perf-metrics.d.ts +26 -0
  187. package/dist/runtime/perf-metrics.d.ts.map +1 -0
  188. package/dist/runtime/portal.d.ts +22 -0
  189. package/dist/runtime/portal.d.ts.map +1 -0
  190. package/dist/runtime/portal.js +213 -0
  191. package/dist/runtime/portal.js.map +1 -0
  192. package/dist/runtime/resource-cell.js +1 -1
  193. package/dist/runtime/resource-cell.js.map +1 -1
  194. package/dist/runtime/resource-operation.js +1 -1
  195. package/dist/runtime/runtime.d.ts +1 -1
  196. package/dist/runtime/scheduler.js +2 -2
  197. package/dist/runtime/scheduler.js.map +1 -1
  198. package/dist/runtime/selector-store.js +24 -0
  199. package/dist/runtime/selector-store.js.map +1 -0
  200. package/dist/runtime/selector.d.ts.map +1 -1
  201. package/dist/runtime/selector.js +3 -18
  202. package/dist/runtime/selector.js.map +1 -1
  203. package/dist/ssg/create-static-gen.js +1 -0
  204. package/dist/ssg/create-static-gen.js.map +1 -1
  205. package/dist/ssg/static-routes.js +1 -0
  206. package/dist/ssg/static-routes.js.map +1 -1
  207. package/dist/ssr/boundaries.js +2 -2
  208. package/dist/ssr/boundaries.js.map +1 -1
  209. package/dist/ssr/component-runtime.js +3 -3
  210. package/dist/ssr/component-runtime.js.map +1 -1
  211. package/dist/ssr/render-resolved.js +1 -1
  212. package/dist/ssr/render-sync.js +1 -1
  213. package/dist/ssr/render-sync.js.map +1 -1
  214. package/dist/ssr/route-policy-resolution.js +2 -1
  215. package/dist/ssr/route-policy-resolution.js.map +1 -1
  216. package/dist/ssr/route-render.js +2 -1
  217. package/dist/ssr/route-render.js.map +1 -1
  218. package/dist/testing/index.d.ts.map +1 -1
  219. package/dist/testing/index.js +3 -2
  220. package/dist/testing/index.js.map +1 -1
  221. package/package.json +4 -4
  222. package/dist/dev/invariant.js +0 -29
  223. package/dist/dev/invariant.js.map +0 -1
  224. package/dist/dev/logger.js.map +0 -1
  225. package/dist/foundations/structures/portal.d.ts.map +0 -1
  226. package/dist/foundations/structures/portal.js.map +0 -1
  227. package/dist/runtime/component-contracts.js +0 -5
@@ -1 +1 @@
1
- {"version":3,"file":"benchmark-table.js","names":[],"sources":["../../../src/bench/components/benchmark-table.tsx"],"sourcesContent":["import { For } from '../../control';\nimport type { State } from '../../runtime/state';\nimport { BenchmarkRow, type BenchmarkRowData } from './benchmark-row';\n\ninterface BenchmarkTableProps {\n rows: State<BenchmarkRowData[]>;\n isSelected: (id: number) => boolean;\n onSelect: (id: number) => void;\n onRemove: (id: number) => void;\n}\n\nexport function BenchmarkTable({\n rows,\n isSelected,\n onSelect,\n onRemove,\n}: BenchmarkTableProps) {\n return (\n <table class=\"table table-hover table-striped test-data\">\n <tbody>\n {\n <For each={() => rows()} by={(item) => item.id}>\n {(item) => (\n <BenchmarkRow\n item={item}\n isSelected={isSelected}\n onSelect={onSelect}\n onRemove={onRemove}\n />\n )}\n </For>\n }\n </tbody>\n </table>\n );\n}\n"],"mappings":";;;;;;AAWA,SAAgB,eAAe,EAC7B,MACA,YACA,UACA,YACsB;CACtB,OACE,oBAAC,SAAD;EAAO,OAAM;YACX,oBAAC,SAAD,EAAA,UAEI,oBAAC,KAAD;GAAK,YAAY,KAAK;GAAG,KAAK,SAAS,KAAK;cACxC,SACA,oBAAC,cAAD;IACQ;IACM;IACF;IACA;GACX,CAAA;EAEA,CAAA,EAEF,CAAA;CACF,CAAA;AAEX"}
1
+ {"version":3,"file":"benchmark-table.js","names":[],"sources":["../../../src/bench/components/benchmark-table.tsx"],"sourcesContent":["import { For } from '../../control';\nimport type { State } from '../../runtime';\nimport { BenchmarkRow, type BenchmarkRowData } from './benchmark-row';\n\ninterface BenchmarkTableProps {\n rows: State<BenchmarkRowData[]>;\n isSelected: (id: number) => boolean;\n onSelect: (id: number) => void;\n onRemove: (id: number) => void;\n}\n\nexport function BenchmarkTable({\n rows,\n isSelected,\n onSelect,\n onRemove,\n}: BenchmarkTableProps) {\n return (\n <table class=\"table table-hover table-striped test-data\">\n <tbody>\n {\n <For each={() => rows()} by={(item) => item.id}>\n {(item) => (\n <BenchmarkRow\n item={item}\n isSelected={isSelected}\n onSelect={onSelect}\n onRemove={onRemove}\n />\n )}\n </For>\n }\n </tbody>\n </table>\n );\n}\n"],"mappings":";;;;;;AAWA,SAAgB,eAAe,EAC7B,MACA,YACA,UACA,YACsB;CACtB,OACE,oBAAC,SAAD;EAAO,OAAM;YACX,oBAAC,SAAD,EAAA,UAEI,oBAAC,KAAD;GAAK,YAAY,KAAK;GAAG,KAAK,SAAS,KAAK;cACxC,SACA,oBAAC,cAAD;IACQ;IACM;IACF;IACA;GACX,CAAA;EAEA,CAAA,EAEF,CAAA;CACF,CAAA;AAEX"}
package/dist/benchmark.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { flushRuntimeScheduler } from "./runtime/access.js";
2
- import { jsx } from "./jsx-runtime.js";
3
- import { installRendererBridge } from "./renderer/index.js";
4
2
  import { state } from "./runtime/state.js";
5
3
  import { selector } from "./runtime/selector.js";
4
+ import "./runtime/index.js";
5
+ import { jsx } from "./jsx-runtime.js";
6
+ import { installRendererBridge } from "./renderer/index.js";
6
7
  import "./jsx-runtime2.js";
7
8
  import { createIsland } from "./boot/index.js";
8
9
  import { BenchmarkTable } from "./bench/components/benchmark-table.js";
@@ -10,8 +11,8 @@ import { BenchmarkTable } from "./bench/components/benchmark-table.js";
10
11
  installRendererBridge();
11
12
  const benchmarkMetadata = {
12
13
  packageName: "@askrjs/askr",
13
- packageVersion: "0.0.50",
14
- buildLabel: "0.0.50-local"
14
+ packageVersion: "0.0.51",
15
+ buildLabel: "0.0.51-local"
15
16
  };
16
17
  function getBenchmarkMetadata() {
17
18
  return { ...benchmarkMetadata };
@@ -1 +1 @@
1
- {"version":3,"file":"benchmark.js","names":[],"sources":["../src/bench/benchmark-entry.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { createIsland } from '../boot';\nimport { installRendererBridge } from '../renderer';\nimport { flushRuntimeScheduler } from '../runtime/access';\nimport { selector } from '../runtime/selector';\nimport { state, State } from '../runtime/state';\nimport { BenchmarkTable } from './components/benchmark-table';\nimport type { BenchmarkRowData } from './components/benchmark-row';\n\ninstallRendererBridge();\n\ntype RowData = BenchmarkRowData;\n\nexport interface BenchmarkMetadata {\n packageName: string;\n packageVersion: string;\n buildLabel: string;\n}\n\nconst packageName =\n process.env.ASKR_PACKAGE_NAME ||\n process.env.npm_package_name ||\n '@askrjs/askr';\nconst packageVersion =\n process.env.ASKR_PACKAGE_VERSION ||\n process.env.npm_package_version ||\n '0.0.0';\n\nexport const benchmarkMetadata: BenchmarkMetadata = {\n packageName,\n packageVersion,\n buildLabel:\n process.env.ASKR_BENCHMARK_BUILD_LABEL || `${packageVersion}-local`,\n};\n\nexport function getBenchmarkMetadata(): BenchmarkMetadata {\n return { ...benchmarkMetadata };\n}\n\nexport function mountBenchmark(root: Element, initialRows?: RowData[]) {\n const initialRowsTyped: RowData[] = Array.isArray(initialRows)\n ? initialRows\n : [];\n let dataState!: State<RowData[]>;\n let selectedState!: State<number | null>;\n\n const App = () => {\n dataState = state<RowData[]>(initialRowsTyped);\n selectedState = state<number | null>(null);\n dataState._hasBeenRead = true;\n const isSelected = selector(selectedState);\n\n const select = (id: number) => selectedState.set(id);\n const remove = (id: number) => {\n dataState.set((rows) => rows.filter((item) => item.id !== id));\n selectedState.set((selected) => (selected === id ? null : selected));\n };\n\n return (\n <div class=\"container\">\n <BenchmarkTable\n rows={dataState}\n isSelected={isSelected}\n onSelect={select}\n onRemove={remove}\n />\n </div>\n );\n };\n\n createIsland({ root, component: App as any });\n flushRuntimeScheduler();\n\n return {\n setRows(rows: RowData[]) {\n dataState.set(rows);\n // Ensure work is flushed so external harnesses (like JFB) that check the DOM\n // immediately after calling `setRows` observe the committed DOM.\n flushRuntimeScheduler();\n },\n setSelected(id: number | null) {\n selectedState.set(id);\n flushRuntimeScheduler();\n },\n cleanup() {\n // nothing to do; outer test may clean the container\n },\n };\n}\n\nexport default { mountBenchmark };\n"],"mappings":";;;;;;;;;AASA,sBAAsB;AAmBtB,MAAa,oBAAuC;CAClD;CACA;CACA,YAAA;AAEF;AAEA,SAAgB,uBAA0C;CACxD,OAAO,EAAE,GAAG,kBAAkB;AAChC;AAEA,SAAgB,eAAe,MAAe,aAAyB;CACrE,MAAM,mBAA8B,MAAM,QAAQ,WAAW,IACzD,cACA,CAAC;CACL,IAAI;CACJ,IAAI;CAEJ,MAAM,YAAY;EAChB,YAAY,MAAiB,gBAAgB;EAC7C,gBAAgB,MAAqB,IAAI;EACzC,UAAU,eAAe;EACzB,MAAM,aAAa,SAAS,aAAa;EAEzC,MAAM,UAAU,OAAe,cAAc,IAAI,EAAE;EACnD,MAAM,UAAU,OAAe;GAC7B,UAAU,KAAK,SAAS,KAAK,QAAQ,SAAS,KAAK,OAAO,EAAE,CAAC;GAC7D,cAAc,KAAK,aAAc,aAAa,KAAK,OAAO,QAAS;EACrE;EAEA,OACE,oBAAC,OAAD;GAAK,OAAM;aACT,oBAAC,gBAAD;IACE,MAAM;IACM;IACZ,UAAU;IACV,UAAU;GACX,CAAA;EACE,CAAA;CAET;CAEA,aAAa;EAAE;EAAM,WAAW;CAAW,CAAC;CAC5C,sBAAsB;CAEtB,OAAO;EACL,QAAQ,MAAiB;GACvB,UAAU,IAAI,IAAI;GAGlB,sBAAsB;EACxB;EACA,YAAY,IAAmB;GAC7B,cAAc,IAAI,EAAE;GACpB,sBAAsB;EACxB;EACA,UAAU,CAEV;CACF;AACF;AAEA,IAAA,0BAAe,EAAE,eAAe"}
1
+ {"version":3,"file":"benchmark.js","names":[],"sources":["../src/bench/benchmark-entry.tsx"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { createIsland } from '../boot';\nimport { installRendererBridge } from '../renderer';\nimport { flushRuntimeScheduler } from '../runtime';\nimport { selector } from '../runtime';\nimport { state, State } from '../runtime';\nimport { BenchmarkTable } from './components/benchmark-table';\nimport type { BenchmarkRowData } from './components/benchmark-row';\n\ninstallRendererBridge();\n\ntype RowData = BenchmarkRowData;\n\nexport interface BenchmarkMetadata {\n packageName: string;\n packageVersion: string;\n buildLabel: string;\n}\n\nconst packageName =\n process.env.ASKR_PACKAGE_NAME ||\n process.env.npm_package_name ||\n '@askrjs/askr';\nconst packageVersion =\n process.env.ASKR_PACKAGE_VERSION ||\n process.env.npm_package_version ||\n '0.0.0';\n\nexport const benchmarkMetadata: BenchmarkMetadata = {\n packageName,\n packageVersion,\n buildLabel:\n process.env.ASKR_BENCHMARK_BUILD_LABEL || `${packageVersion}-local`,\n};\n\nexport function getBenchmarkMetadata(): BenchmarkMetadata {\n return { ...benchmarkMetadata };\n}\n\nexport function mountBenchmark(root: Element, initialRows?: RowData[]) {\n const initialRowsTyped: RowData[] = Array.isArray(initialRows)\n ? initialRows\n : [];\n let dataState!: State<RowData[]>;\n let selectedState!: State<number | null>;\n\n const App = () => {\n dataState = state<RowData[]>(initialRowsTyped);\n selectedState = state<number | null>(null);\n dataState._hasBeenRead = true;\n const isSelected = selector(selectedState);\n\n const select = (id: number) => selectedState.set(id);\n const remove = (id: number) => {\n dataState.set((rows) => rows.filter((item) => item.id !== id));\n selectedState.set((selected) => (selected === id ? null : selected));\n };\n\n return (\n <div class=\"container\">\n <BenchmarkTable\n rows={dataState}\n isSelected={isSelected}\n onSelect={select}\n onRemove={remove}\n />\n </div>\n );\n };\n\n createIsland({ root, component: App as any });\n flushRuntimeScheduler();\n\n return {\n setRows(rows: RowData[]) {\n dataState.set(rows);\n // Ensure work is flushed so external harnesses (like JFB) that check the DOM\n // immediately after calling `setRows` observe the committed DOM.\n flushRuntimeScheduler();\n },\n setSelected(id: number | null) {\n selectedState.set(id);\n flushRuntimeScheduler();\n },\n cleanup() {\n // nothing to do; outer test may clean the container\n },\n };\n}\n\nexport default { mountBenchmark };\n"],"mappings":";;;;;;;;;;AASA,sBAAsB;AAmBtB,MAAa,oBAAuC;CAClD;CACA;CACA,YAAA;AAEF;AAEA,SAAgB,uBAA0C;CACxD,OAAO,EAAE,GAAG,kBAAkB;AAChC;AAEA,SAAgB,eAAe,MAAe,aAAyB;CACrE,MAAM,mBAA8B,MAAM,QAAQ,WAAW,IACzD,cACA,CAAC;CACL,IAAI;CACJ,IAAI;CAEJ,MAAM,YAAY;EAChB,YAAY,MAAiB,gBAAgB;EAC7C,gBAAgB,MAAqB,IAAI;EACzC,UAAU,eAAe;EACzB,MAAM,aAAa,SAAS,aAAa;EAEzC,MAAM,UAAU,OAAe,cAAc,IAAI,EAAE;EACnD,MAAM,UAAU,OAAe;GAC7B,UAAU,KAAK,SAAS,KAAK,QAAQ,SAAS,KAAK,OAAO,EAAE,CAAC;GAC7D,cAAc,KAAK,aAAc,aAAa,KAAK,OAAO,QAAS;EACrE;EAEA,OACE,oBAAC,OAAD;GAAK,OAAM;aACT,oBAAC,gBAAD;IACE,MAAM;IACM;IACZ,UAAU;IACV,UAAU;GACX,CAAA;EACE,CAAA;CAET;CAEA,aAAa;EAAE;EAAM,WAAW;CAAW,CAAC;CAC5C,sBAAsB;CAEtB,OAAO;EACL,QAAQ,MAAiB;GACvB,UAAU,IAAI,IAAI;GAGlB,sBAAsB;EACxB;EACA,YAAY,IAAmB;GAC7B,cAAc,IAAI,EAAE;GACpB,sBAAsB;EACxB;EACA,UAAU,CAEV;CACF;AACF;AAEA,IAAA,0BAAe,EAAE,eAAe"}
@@ -1 +1 @@
1
- {"version":3,"file":"askr-ssg.d.ts","names":[],"sources":["../../src/bin/askr-ssg.ts"],"mappings":";;UAuBiB,aAAA;EACf,UAAA;EACA,SAAA;EACA,OAAA;EACA,WAAA;EACA,WAAA;EACA,aAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,UAGQ,KAAA;EACR,GAAA,MAAS,IAAA;EACT,KAAA,MAAW,IAAA;AAAA;AAAA,UAGH,OAAA;EACR,GAAA;EACA,GAAA;EACA,UAAA,GAAa,IAAA;EACb,YAAA,GAAe,IAAA,aAAiB,OAAA,CAAQ,MAAA;EACxC,eAAA,SAAwB,eAAA;AAAA;AAAA,iBA2CV,YAAA,CAAa,IAAA,aAAiB,aAAa;AAAA,iBAqErC,MAAA,CACpB,IAAA,YACA,IAAA,GAAM,OAAA,CAAQ,OAAA,GACd,EAAA,GAAI,KAAA,GACH,OAAA"}
1
+ {"version":3,"file":"askr-ssg.d.ts","names":[],"sources":["../../src/bin/askr-ssg.ts"],"mappings":";;UAsBiB,aAAA;EACf,UAAA;EACA,SAAA;EACA,OAAA;EACA,WAAA;EACA,WAAA;EACA,aAAA;EACA,SAAA;EACA,IAAA;AAAA;AAAA,UAGQ,KAAA;EACR,GAAA,MAAS,IAAA;EACT,KAAA,MAAW,IAAA;AAAA;AAAA,UAGH,OAAA;EACR,GAAA;EACA,GAAA;EACA,UAAA,GAAa,IAAA;EACb,YAAA,GAAe,IAAA,aAAiB,OAAA,CAAQ,MAAA;EACxC,eAAA,SAAwB,eAAA;AAAA;AAAA,iBA2CV,YAAA,CAAa,IAAA,aAAiB,aAAa;AAAA,iBAqErC,MAAA,CACpB,IAAA,YACA,IAAA,GAAM,OAAA,CAAQ,OAAA,GACd,EAAA,GAAI,KAAA,GACH,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"askr-ssg.js","names":[],"sources":["../../src/bin/askr-ssg.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * askr-ssg CLI\n *\n * Usage: askr-ssg --config path/to/config.ts --output dist/static\n */\n\nimport * as pathModule from 'path';\nimport * as fsModule from 'fs';\nimport { createStaticGen } from '../ssg/index';\nimport type { RouteConfig } from '../ssg/types';\nimport type { SSGGenerateOptions, SSGResult } from '../ssg/types';\n\nconst { resolve } = pathModule;\nconst { existsSync } = fsModule;\n\nfunction toFileUrl(filePath: string): string {\n const normalized = resolve(filePath).replace(/\\\\/g, '/');\n const leadingSlash = normalized.startsWith('/') ? '' : '/';\n return `file://${leadingSlash}${encodeURI(normalized)}`;\n}\n\nexport interface ParsedCliArgs {\n configPath: string;\n outputDir: string;\n workers: number | 'auto';\n incremental: boolean;\n changedKeys: string[];\n changedRoutes: string[];\n forceFull: boolean;\n help: boolean;\n}\n\ninterface CliIo {\n log: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\ninterface CliDeps {\n cwd: () => string;\n now: () => number;\n existsSync: (path: string) => boolean;\n importConfig: (path: string) => Promise<Record<string, unknown>>;\n createStaticGen: typeof createStaticGen;\n}\n\ninterface CliConfig {\n routes: RouteConfig[];\n seed?: number;\n dataOverrides?: Record<string, unknown>;\n concurrency?: number;\n}\n\nconst defaultCliDeps: CliDeps = {\n cwd: () => process.cwd(),\n now: () => performance.now(),\n existsSync,\n importConfig: async (path: string) =>\n (await import(toFileUrl(path))) as Record<string, unknown>,\n createStaticGen,\n};\n\nconst helpText = `\naskr-ssg - Static Site Generation for Askr\n\nUsage:\n askr-ssg --config <path> --output <dir> [--incremental]\n\nOptions:\n --config <path> Path to SSG config file (TypeScript module)\n --output <dir> Output directory for generated HTML\n --workers <n|auto> Preferred render worker count for SSG throughput\n --incremental Use incremental generation if a manifest exists\n --changed-key <key> Mark an invalidation key as changed (repeatable)\n --changed-route <path> Mark a concrete route path as changed (repeatable)\n --force-full Force a full rebuild even with incremental flags\n --help Show this help message\n\nExample:\n askr-ssg --config ./ssg.config.ts --output ./dist/static --incremental --changed-key blog/post-123\n\nTypeScript config execution:\n Use tsx to run the CLI with TS config loading:\n tsx node_modules/@askrjs/askr/dist/bin/askr-ssg.js --config ./ssg.config.ts --output ./dist/static\n`;\n\nexport function parseCliArgs(args: string[]): ParsedCliArgs {\n const parsed: ParsedCliArgs = {\n configPath: '',\n outputDir: '',\n workers: 1,\n incremental: false,\n changedKeys: [],\n changedRoutes: [],\n forceFull: false,\n help: false,\n };\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--config' && i + 1 < args.length) {\n parsed.configPath = args[i + 1];\n i++;\n } else if (args[i] === '--output' && i + 1 < args.length) {\n parsed.outputDir = args[i + 1];\n i++;\n } else if (args[i] === '--workers' && i + 1 < args.length) {\n parsed.workers = args[i + 1] === 'auto' ? 'auto' : Number(args[i + 1]);\n i++;\n } else if (args[i] === '--changed-key' && i + 1 < args.length) {\n parsed.changedKeys.push(args[i + 1]);\n i++;\n } else if (args[i] === '--changed-route' && i + 1 < args.length) {\n parsed.changedRoutes.push(args[i + 1]);\n i++;\n } else if (args[i] === '--incremental') {\n parsed.incremental = true;\n } else if (args[i] === '--force-full') {\n parsed.forceFull = true;\n } else if (args[i] === '--help' || args[i] === '-h') {\n parsed.help = true;\n }\n }\n\n return parsed;\n}\n\nfunction toGenerateOptions(args: ParsedCliArgs): SSGGenerateOptions {\n return {\n mode: args.incremental ? 'incremental' : 'full',\n changedKeys: args.changedKeys,\n changedRoutes: args.changedRoutes,\n forceFull: args.forceFull,\n };\n}\n\nfunction printSummary(\n io: CliIo,\n outputDir: string,\n durationSeconds: string,\n result: SSGResult\n) {\n io.log('');\n io.log(`Generation complete in ${durationSeconds}s`);\n io.log(` Mode: ${result.mode}`);\n io.log(` Generated: ${result.successful}/${result.totalRoutes} routes`);\n io.log(` Failed: ${result.failed} routes`);\n io.log(` Rebuilt: ${result.rebuilt} routes`);\n io.log(` Skipped: ${result.skipped} routes`);\n io.log(` Removed: ${result.removed} routes`);\n io.log(` CacheHit: ${result.cacheHits} routes`);\n io.log(` Output: ${outputDir}`);\n io.log(` Metadata: ${outputDir}/metadata.json`);\n io.log('');\n}\n\nexport async function runCli(\n args: string[],\n deps: Partial<CliDeps> = {},\n io: CliIo = console\n): Promise<number> {\n const parsed = parseCliArgs(args);\n if (parsed.help) {\n io.log(helpText);\n return 0;\n }\n\n if (!parsed.configPath) {\n io.error('Error: --config argument is required');\n return 1;\n }\n\n if (!parsed.configPath.endsWith('.ts')) {\n io.error('Error: --config must point to a TypeScript file (.ts)');\n return 1;\n }\n\n if (!parsed.outputDir) {\n io.error('Error: --output argument is required');\n return 1;\n }\n\n const resolvedDeps = { ...defaultCliDeps, ...deps };\n const resolvedConfigPath = resolve(resolvedDeps.cwd(), parsed.configPath);\n const resolvedOutputDir = resolve(resolvedDeps.cwd(), parsed.outputDir);\n\n if (!resolvedDeps.existsSync(resolvedConfigPath)) {\n io.error(`Error: Config file not found: ${resolvedConfigPath}`);\n return 1;\n }\n\n try {\n io.log(`Loading config: ${resolvedConfigPath}`);\n\n const configModule = await resolvedDeps.importConfig(resolvedConfigPath);\n const config = (configModule.default || configModule) as Partial<CliConfig>;\n\n if (!Array.isArray(config.routes)) {\n io.error('Error: Config must export routes array');\n return 1;\n }\n\n io.log(`Generating ${config.routes.length} routes...`);\n\n const ssg = resolvedDeps.createStaticGen({\n routes: config.routes,\n outputDir: resolvedOutputDir,\n seed: config.seed,\n dataOverrides: config.dataOverrides,\n concurrency: config.concurrency,\n parallelism: parsed.workers,\n });\n\n const startTime = resolvedDeps.now();\n const result = await ssg.generate(toGenerateOptions(parsed));\n const duration = ((resolvedDeps.now() - startTime) / 1000).toFixed(2);\n\n printSummary(io, resolvedOutputDir, duration, result);\n\n if (result.failed > 0) {\n io.log('Errors encountered:');\n for (const route of result.routes) {\n if (route.status === 'error') {\n io.log(` ${route.path}: ${route.error}`);\n }\n }\n io.log('');\n return 1;\n }\n\n return 0;\n } catch (error) {\n io.error('Generation failed:');\n io.error(error instanceof Error ? error.message : String(error));\n if (error instanceof Error && error.stack) {\n io.error(error.stack);\n }\n return 1;\n }\n}\n\nasync function main() {\n const exitCode = await runCli(process.argv.slice(2));\n process.exit(exitCode);\n}\n\nif (process.argv[1] && import.meta.url === toFileUrl(process.argv[1])) {\n void main();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"askr-ssg.js","names":[],"sources":["../../src/bin/askr-ssg.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * askr-ssg CLI\n *\n * Usage: askr-ssg --config path/to/config.ts --output dist/static\n */\n\nimport * as pathModule from 'path';\nimport * as fsModule from 'fs';\nimport { createStaticGen } from '../ssg/index';\nimport type { RouteConfig, SSGGenerateOptions, SSGResult } from '../ssg/index';\n\nconst { resolve } = pathModule;\nconst { existsSync } = fsModule;\n\nfunction toFileUrl(filePath: string): string {\n const normalized = resolve(filePath).replace(/\\\\/g, '/');\n const leadingSlash = normalized.startsWith('/') ? '' : '/';\n return `file://${leadingSlash}${encodeURI(normalized)}`;\n}\n\nexport interface ParsedCliArgs {\n configPath: string;\n outputDir: string;\n workers: number | 'auto';\n incremental: boolean;\n changedKeys: string[];\n changedRoutes: string[];\n forceFull: boolean;\n help: boolean;\n}\n\ninterface CliIo {\n log: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n}\n\ninterface CliDeps {\n cwd: () => string;\n now: () => number;\n existsSync: (path: string) => boolean;\n importConfig: (path: string) => Promise<Record<string, unknown>>;\n createStaticGen: typeof createStaticGen;\n}\n\ninterface CliConfig {\n routes: RouteConfig[];\n seed?: number;\n dataOverrides?: Record<string, unknown>;\n concurrency?: number;\n}\n\nconst defaultCliDeps: CliDeps = {\n cwd: () => process.cwd(),\n now: () => performance.now(),\n existsSync,\n importConfig: async (path: string) =>\n (await import(toFileUrl(path))) as Record<string, unknown>,\n createStaticGen,\n};\n\nconst helpText = `\naskr-ssg - Static Site Generation for Askr\n\nUsage:\n askr-ssg --config <path> --output <dir> [--incremental]\n\nOptions:\n --config <path> Path to SSG config file (TypeScript module)\n --output <dir> Output directory for generated HTML\n --workers <n|auto> Preferred render worker count for SSG throughput\n --incremental Use incremental generation if a manifest exists\n --changed-key <key> Mark an invalidation key as changed (repeatable)\n --changed-route <path> Mark a concrete route path as changed (repeatable)\n --force-full Force a full rebuild even with incremental flags\n --help Show this help message\n\nExample:\n askr-ssg --config ./ssg.config.ts --output ./dist/static --incremental --changed-key blog/post-123\n\nTypeScript config execution:\n Use tsx to run the CLI with TS config loading:\n tsx node_modules/@askrjs/askr/dist/bin/askr-ssg.js --config ./ssg.config.ts --output ./dist/static\n`;\n\nexport function parseCliArgs(args: string[]): ParsedCliArgs {\n const parsed: ParsedCliArgs = {\n configPath: '',\n outputDir: '',\n workers: 1,\n incremental: false,\n changedKeys: [],\n changedRoutes: [],\n forceFull: false,\n help: false,\n };\n\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--config' && i + 1 < args.length) {\n parsed.configPath = args[i + 1];\n i++;\n } else if (args[i] === '--output' && i + 1 < args.length) {\n parsed.outputDir = args[i + 1];\n i++;\n } else if (args[i] === '--workers' && i + 1 < args.length) {\n parsed.workers = args[i + 1] === 'auto' ? 'auto' : Number(args[i + 1]);\n i++;\n } else if (args[i] === '--changed-key' && i + 1 < args.length) {\n parsed.changedKeys.push(args[i + 1]);\n i++;\n } else if (args[i] === '--changed-route' && i + 1 < args.length) {\n parsed.changedRoutes.push(args[i + 1]);\n i++;\n } else if (args[i] === '--incremental') {\n parsed.incremental = true;\n } else if (args[i] === '--force-full') {\n parsed.forceFull = true;\n } else if (args[i] === '--help' || args[i] === '-h') {\n parsed.help = true;\n }\n }\n\n return parsed;\n}\n\nfunction toGenerateOptions(args: ParsedCliArgs): SSGGenerateOptions {\n return {\n mode: args.incremental ? 'incremental' : 'full',\n changedKeys: args.changedKeys,\n changedRoutes: args.changedRoutes,\n forceFull: args.forceFull,\n };\n}\n\nfunction printSummary(\n io: CliIo,\n outputDir: string,\n durationSeconds: string,\n result: SSGResult\n) {\n io.log('');\n io.log(`Generation complete in ${durationSeconds}s`);\n io.log(` Mode: ${result.mode}`);\n io.log(` Generated: ${result.successful}/${result.totalRoutes} routes`);\n io.log(` Failed: ${result.failed} routes`);\n io.log(` Rebuilt: ${result.rebuilt} routes`);\n io.log(` Skipped: ${result.skipped} routes`);\n io.log(` Removed: ${result.removed} routes`);\n io.log(` CacheHit: ${result.cacheHits} routes`);\n io.log(` Output: ${outputDir}`);\n io.log(` Metadata: ${outputDir}/metadata.json`);\n io.log('');\n}\n\nexport async function runCli(\n args: string[],\n deps: Partial<CliDeps> = {},\n io: CliIo = console\n): Promise<number> {\n const parsed = parseCliArgs(args);\n if (parsed.help) {\n io.log(helpText);\n return 0;\n }\n\n if (!parsed.configPath) {\n io.error('Error: --config argument is required');\n return 1;\n }\n\n if (!parsed.configPath.endsWith('.ts')) {\n io.error('Error: --config must point to a TypeScript file (.ts)');\n return 1;\n }\n\n if (!parsed.outputDir) {\n io.error('Error: --output argument is required');\n return 1;\n }\n\n const resolvedDeps = { ...defaultCliDeps, ...deps };\n const resolvedConfigPath = resolve(resolvedDeps.cwd(), parsed.configPath);\n const resolvedOutputDir = resolve(resolvedDeps.cwd(), parsed.outputDir);\n\n if (!resolvedDeps.existsSync(resolvedConfigPath)) {\n io.error(`Error: Config file not found: ${resolvedConfigPath}`);\n return 1;\n }\n\n try {\n io.log(`Loading config: ${resolvedConfigPath}`);\n\n const configModule = await resolvedDeps.importConfig(resolvedConfigPath);\n const config = (configModule.default || configModule) as Partial<CliConfig>;\n\n if (!Array.isArray(config.routes)) {\n io.error('Error: Config must export routes array');\n return 1;\n }\n\n io.log(`Generating ${config.routes.length} routes...`);\n\n const ssg = resolvedDeps.createStaticGen({\n routes: config.routes,\n outputDir: resolvedOutputDir,\n seed: config.seed,\n dataOverrides: config.dataOverrides,\n concurrency: config.concurrency,\n parallelism: parsed.workers,\n });\n\n const startTime = resolvedDeps.now();\n const result = await ssg.generate(toGenerateOptions(parsed));\n const duration = ((resolvedDeps.now() - startTime) / 1000).toFixed(2);\n\n printSummary(io, resolvedOutputDir, duration, result);\n\n if (result.failed > 0) {\n io.log('Errors encountered:');\n for (const route of result.routes) {\n if (route.status === 'error') {\n io.log(` ${route.path}: ${route.error}`);\n }\n }\n io.log('');\n return 1;\n }\n\n return 0;\n } catch (error) {\n io.error('Generation failed:');\n io.error(error instanceof Error ? error.message : String(error));\n if (error instanceof Error && error.stack) {\n io.error(error.stack);\n }\n return 1;\n }\n}\n\nasync function main() {\n const exitCode = await runCli(process.argv.slice(2));\n process.exit(exitCode);\n}\n\nif (process.argv[1] && import.meta.url === toFileUrl(process.argv[1])) {\n void main();\n}\n"],"mappings":";;;;;;;;;;;AAaA,MAAM,EAAE,YAAY;AACpB,MAAM,EAAE,eAAe;AAEvB,SAAS,UAAU,UAA0B;CAC3C,MAAM,aAAa,QAAQ,QAAQ,CAAC,CAAC,QAAQ,OAAO,GAAG;CAEvD,OAAO,UADc,WAAW,WAAW,GAAG,IAAI,KAAK,MACvB,UAAU,UAAU;AACtD;AAiCA,MAAM,iBAA0B;CAC9B,WAAW,QAAQ,IAAI;CACvB,WAAW,YAAY,IAAI;CAC3B;CACA,cAAc,OAAO,SAClB,MAAM,OAAO,UAAU,IAAI;CAC9B;AACF;AAEA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;AAwBjB,SAAgB,aAAa,MAA+B;CAC1D,MAAM,SAAwB;EAC5B,YAAY;EACZ,WAAW;EACX,SAAS;EACT,aAAa;EACb,aAAa,CAAC;EACd,eAAe,CAAC;EAChB,WAAW;EACX,MAAM;CACR;CAEA,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAC/B,IAAI,KAAK,OAAO,cAAc,IAAI,IAAI,KAAK,QAAQ;EACjD,OAAO,aAAa,KAAK,IAAI;EAC7B;CACF,OAAO,IAAI,KAAK,OAAO,cAAc,IAAI,IAAI,KAAK,QAAQ;EACxD,OAAO,YAAY,KAAK,IAAI;EAC5B;CACF,OAAO,IAAI,KAAK,OAAO,eAAe,IAAI,IAAI,KAAK,QAAQ;EACzD,OAAO,UAAU,KAAK,IAAI,OAAO,SAAS,SAAS,OAAO,KAAK,IAAI,EAAE;EACrE;CACF,OAAO,IAAI,KAAK,OAAO,mBAAmB,IAAI,IAAI,KAAK,QAAQ;EAC7D,OAAO,YAAY,KAAK,KAAK,IAAI,EAAE;EACnC;CACF,OAAO,IAAI,KAAK,OAAO,qBAAqB,IAAI,IAAI,KAAK,QAAQ;EAC/D,OAAO,cAAc,KAAK,KAAK,IAAI,EAAE;EACrC;CACF,OAAO,IAAI,KAAK,OAAO,iBACrB,OAAO,cAAc;MAChB,IAAI,KAAK,OAAO,gBACrB,OAAO,YAAY;MACd,IAAI,KAAK,OAAO,YAAY,KAAK,OAAO,MAC7C,OAAO,OAAO;CAIlB,OAAO;AACT;AAEA,SAAS,kBAAkB,MAAyC;CAClE,OAAO;EACL,MAAM,KAAK,cAAc,gBAAgB;EACzC,aAAa,KAAK;EAClB,eAAe,KAAK;EACpB,WAAW,KAAK;CAClB;AACF;AAEA,SAAS,aACP,IACA,WACA,iBACA,QACA;CACA,GAAG,IAAI,EAAE;CACT,GAAG,IAAI,0BAA0B,gBAAgB,EAAE;CACnD,GAAG,IAAI,iBAAiB,OAAO,MAAM;CACrC,GAAG,IAAI,iBAAiB,OAAO,WAAW,GAAG,OAAO,YAAY,QAAQ;CACxE,GAAG,IAAI,iBAAiB,OAAO,OAAO,QAAQ;CAC9C,GAAG,IAAI,iBAAiB,OAAO,QAAQ,QAAQ;CAC/C,GAAG,IAAI,iBAAiB,OAAO,QAAQ,QAAQ;CAC/C,GAAG,IAAI,iBAAiB,OAAO,QAAQ,QAAQ;CAC/C,GAAG,IAAI,iBAAiB,OAAO,UAAU,QAAQ;CACjD,GAAG,IAAI,iBAAiB,WAAW;CACnC,GAAG,IAAI,iBAAiB,UAAU,eAAe;CACjD,GAAG,IAAI,EAAE;AACX;AAEA,eAAsB,OACpB,MACA,OAAyB,CAAC,GAC1B,KAAY,SACK;CACjB,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,OAAO,MAAM;EACf,GAAG,IAAI,QAAQ;EACf,OAAO;CACT;CAEA,IAAI,CAAC,OAAO,YAAY;EACtB,GAAG,MAAM,sCAAsC;EAC/C,OAAO;CACT;CAEA,IAAI,CAAC,OAAO,WAAW,SAAS,KAAK,GAAG;EACtC,GAAG,MAAM,uDAAuD;EAChE,OAAO;CACT;CAEA,IAAI,CAAC,OAAO,WAAW;EACrB,GAAG,MAAM,sCAAsC;EAC/C,OAAO;CACT;CAEA,MAAM,eAAe;EAAE,GAAG;EAAgB,GAAG;CAAK;CAClD,MAAM,qBAAqB,QAAQ,aAAa,IAAI,GAAG,OAAO,UAAU;CACxE,MAAM,oBAAoB,QAAQ,aAAa,IAAI,GAAG,OAAO,SAAS;CAEtE,IAAI,CAAC,aAAa,WAAW,kBAAkB,GAAG;EAChD,GAAG,MAAM,iCAAiC,oBAAoB;EAC9D,OAAO;CACT;CAEA,IAAI;EACF,GAAG,IAAI,mBAAmB,oBAAoB;EAE9C,MAAM,eAAe,MAAM,aAAa,aAAa,kBAAkB;EACvE,MAAM,SAAU,aAAa,WAAW;EAExC,IAAI,CAAC,MAAM,QAAQ,OAAO,MAAM,GAAG;GACjC,GAAG,MAAM,wCAAwC;GACjD,OAAO;EACT;EAEA,GAAG,IAAI,cAAc,OAAO,OAAO,OAAO,WAAW;EAErD,MAAM,MAAM,aAAa,gBAAgB;GACvC,QAAQ,OAAO;GACf,WAAW;GACX,MAAM,OAAO;GACb,eAAe,OAAO;GACtB,aAAa,OAAO;GACpB,aAAa,OAAO;EACtB,CAAC;EAED,MAAM,YAAY,aAAa,IAAI;EACnC,MAAM,SAAS,MAAM,IAAI,SAAS,kBAAkB,MAAM,CAAC;EAG3D,aAAa,IAAI,qBAFE,aAAa,IAAI,IAAI,aAAa,IAAA,CAAM,QAAQ,CAE/B,GAAU,MAAM;EAEpD,IAAI,OAAO,SAAS,GAAG;GACrB,GAAG,IAAI,qBAAqB;GAC5B,KAAK,MAAM,SAAS,OAAO,QACzB,IAAI,MAAM,WAAW,SACnB,GAAG,IAAI,MAAM,MAAM,KAAK,IAAI,MAAM,OAAO;GAG7C,GAAG,IAAI,EAAE;GACT,OAAO;EACT;EAEA,OAAO;CACT,SAAS,OAAO;EACd,GAAG,MAAM,oBAAoB;EAC7B,GAAG,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;EAC/D,IAAI,iBAAiB,SAAS,MAAM,OAClC,GAAG,MAAM,MAAM,KAAK;EAEtB,OAAO;CACT;AACF;AAEA,eAAe,OAAO;CACpB,MAAM,WAAW,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC;CACnD,QAAQ,KAAK,QAAQ;AACvB;AAEA,IAAI,QAAQ,KAAK,MAAM,OAAO,KAAK,QAAQ,UAAU,QAAQ,KAAK,EAAE,GAClE,AAAK,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"hydration.js","names":[],"sources":["../../src/boot/hydration.ts"],"sourcesContent":["import { isProductionEnvironment } from '../common/env';\nimport { SSR_RENDER_DATA_ATTR, type SSRData } from '../common/ssr';\nimport type { ResolvedRoute } from '../common/router';\nimport type { ComponentFunction } from '../runtime/component';\nimport { setStaticChildSlotsCacheEnabled } from '../renderer/dom';\nimport type { BootAppRouteSource, HydrateSPAConfig } from './types';\n\ntype MountOrUpdateRoot = (\n rootElement: Element,\n componentFn: ComponentFunction,\n options?: { cleanupStrict?: boolean }\n) => void;\n\nexport type HydrationRuntimeHooks = {\n mountOrUpdate: MountOrUpdateRoot;\n registerAppNavigation: (\n rootElement: Element,\n path: string,\n source?: BootAppRouteSource\n ) => Promise<void>;\n registerRootCleanupCallback: (\n rootElement: Element,\n callback: () => void\n ) => () => void;\n flushHydrationActivation: (rootElement: Element) => void;\n};\n\nexport function takeHydrationRenderData(rootElement: Element): SSRData | null {\n for (const child of Array.from(rootElement.children)) {\n if (\n child instanceof HTMLScriptElement &&\n child.getAttribute(SSR_RENDER_DATA_ATTR) === 'true'\n ) {\n const raw = child.textContent ?? '';\n child.remove();\n if (!raw) {\n return {};\n }\n\n try {\n return JSON.parse(raw) as SSRData;\n } catch (err) {\n const error = new Error(\n '[Askr] Failed to parse embedded SSR render data during hydration.'\n );\n (error as Error & { cause?: unknown }).cause = err;\n throw error;\n }\n }\n }\n\n return null;\n}\n\nexport function markSkippedElements(\n root: Element,\n skipSelectors: string[]\n): void {\n if (skipSelectors.length === 0) {\n return;\n }\n\n const uniqueSelectors = Array.from(new Set(skipSelectors));\n const selectorList = uniqueSelectors.join(', ');\n const elements = root.querySelectorAll(selectorList);\n elements.forEach((el) => el.setAttribute('data-skip-hydrate', 'true'));\n}\n\nfunction collectDeferredBelowFoldBoundaries(\n root: Element,\n foldY: number\n): Element[] {\n const boundaries: Element[] = [];\n const stack: Element[] = [];\n\n for (let index = root.children.length - 1; index >= 0; index -= 1) {\n stack.push(root.children[index]);\n }\n\n while (stack.length > 0) {\n const element = stack.pop()!;\n\n if (element.hasAttribute('data-skip-hydrate')) {\n continue;\n }\n\n const rect = element.getBoundingClientRect();\n if (rect.top >= foldY) {\n element.setAttribute('data-skip-hydrate', 'true');\n boundaries.push(element);\n continue;\n }\n\n for (let index = element.children.length - 1; index >= 0; index -= 1) {\n stack.push(element.children[index]);\n }\n }\n\n return boundaries;\n}\n\nfunction activateVisibleDeferredBoundaries(\n boundaries: Element[],\n foldY: number\n): { activated: boolean; remaining: number } {\n let activated = false;\n let remaining = 0;\n\n for (const element of boundaries) {\n if (!element.hasAttribute('data-skip-hydrate')) {\n continue;\n }\n\n const rect = element.getBoundingClientRect();\n if (rect.top < foldY) {\n element.removeAttribute('data-skip-hydrate');\n activated = true;\n } else {\n remaining += 1;\n }\n }\n\n return { activated, remaining };\n}\n\nfunction queueIdleWork(work: () => void): Promise<void> {\n return new Promise((resolve) => {\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(\n () => {\n work();\n resolve();\n },\n { timeout: 2000 }\n );\n return;\n }\n\n setTimeout(() => {\n work();\n resolve();\n }, 0);\n });\n}\n\nexport function shouldVerifyHydrationMarkup(config: HydrateSPAConfig): boolean {\n const explicit = config.hydrate?.verifyMarkup;\n if (typeof explicit === 'boolean') {\n return explicit;\n }\n\n return !isProductionEnvironment();\n}\n\nexport async function applySelectiveHydration(\n rootElement: Element,\n resolved: ResolvedRoute,\n path: string,\n cleanupStrict: boolean | undefined,\n hydrateOptions: NonNullable<HydrateSPAConfig['hydrate']>,\n source: BootAppRouteSource | undefined,\n hooks: HydrationRuntimeHooks\n): Promise<void> {\n const hasPermanentSkips = (hydrateOptions.skipSelectors?.length ?? 0) > 0;\n const hasBelowFoldDeferral = !!hydrateOptions.deferBelowFold;\n const hasSelectiveBoundaries = hasPermanentSkips || hasBelowFoldDeferral;\n let staticChildSlotsCacheSuspended = false;\n let releaseSelectiveHydrationResources = () => {};\n\n const restoreStaticChildSlotsCache = () => {\n if (!staticChildSlotsCacheSuspended) {\n return;\n }\n\n setStaticChildSlotsCacheEnabled(true);\n staticChildSlotsCacheSuspended = false;\n };\n\n if (hydrateOptions.skipSelectors?.length) {\n markSkippedElements(rootElement, hydrateOptions.skipSelectors);\n }\n\n let deferredBoundaries: Element[] = [];\n if (hydrateOptions.deferBelowFold) {\n setStaticChildSlotsCacheEnabled(false);\n staticChildSlotsCacheSuspended = true;\n const foldY = hydrateOptions.foldThreshold ?? window.innerHeight;\n deferredBoundaries = collectDeferredBelowFoldBoundaries(rootElement, foldY);\n\n let selectiveHydrationResourcesReleased = false;\n let unregisterRootCleanupCallback = () => {};\n\n function handleScroll() {\n const { activated, remaining } = activateVisibleDeferredBoundaries(\n deferredBoundaries,\n foldY\n );\n\n if (!activated) {\n return;\n }\n\n hooks.flushHydrationActivation(rootElement);\n\n if (remaining === 0) {\n releaseSelectiveHydrationResources();\n }\n }\n\n releaseSelectiveHydrationResources = () => {\n if (selectiveHydrationResourcesReleased) {\n return;\n }\n\n selectiveHydrationResourcesReleased = true;\n unregisterRootCleanupCallback();\n window.removeEventListener('scroll', handleScroll);\n restoreStaticChildSlotsCache();\n };\n\n unregisterRootCleanupCallback = hooks.registerRootCleanupCallback(\n rootElement,\n releaseSelectiveHydrationResources\n );\n\n window.addEventListener('scroll', handleScroll, { passive: true });\n }\n\n if (hydrateOptions.deferUntilIdle && !hasSelectiveBoundaries) {\n await queueIdleWork(() => {\n hooks.mountOrUpdate(\n rootElement,\n (() => resolved.handler(resolved.params)) as ComponentFunction,\n {\n cleanupStrict,\n }\n );\n });\n await hooks.registerAppNavigation(rootElement, path, source);\n return;\n }\n\n try {\n hooks.mountOrUpdate(\n rootElement,\n (() => resolved.handler(resolved.params)) as ComponentFunction,\n {\n cleanupStrict,\n }\n );\n await hooks.registerAppNavigation(rootElement, path, source);\n } catch (error) {\n releaseSelectiveHydrationResources();\n throw error;\n }\n\n if (hydrateOptions.deferUntilIdle && deferredBoundaries.length > 0) {\n await queueIdleWork(() => {\n try {\n const { activated } = activateVisibleDeferredBoundaries(\n deferredBoundaries,\n Number.POSITIVE_INFINITY\n );\n if (activated) {\n hooks.flushHydrationActivation(rootElement);\n }\n } finally {\n releaseSelectiveHydrationResources();\n }\n });\n }\n\n if (deferredBoundaries.length === 0) {\n releaseSelectiveHydrationResources();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"hydration.js","names":[],"sources":["../../src/boot/hydration.ts"],"sourcesContent":["import { isProductionEnvironment } from '../common/env';\nimport { SSR_RENDER_DATA_ATTR, type SSRData } from '../common/ssr';\nimport type { ResolvedRoute } from '../common/router';\nimport type { ComponentFunction } from '../runtime';\nimport { setStaticChildSlotsCacheEnabled } from '../renderer/dom';\nimport type { BootAppRouteSource, HydrateSPAConfig } from './types';\n\ntype MountOrUpdateRoot = (\n rootElement: Element,\n componentFn: ComponentFunction,\n options?: { cleanupStrict?: boolean }\n) => void;\n\nexport type HydrationRuntimeHooks = {\n mountOrUpdate: MountOrUpdateRoot;\n registerAppNavigation: (\n rootElement: Element,\n path: string,\n source?: BootAppRouteSource\n ) => Promise<void>;\n registerRootCleanupCallback: (\n rootElement: Element,\n callback: () => void\n ) => () => void;\n flushHydrationActivation: (rootElement: Element) => void;\n};\n\nexport function takeHydrationRenderData(rootElement: Element): SSRData | null {\n for (const child of Array.from(rootElement.children)) {\n if (\n child instanceof HTMLScriptElement &&\n child.getAttribute(SSR_RENDER_DATA_ATTR) === 'true'\n ) {\n const raw = child.textContent ?? '';\n child.remove();\n if (!raw) {\n return {};\n }\n\n try {\n return JSON.parse(raw) as SSRData;\n } catch (err) {\n const error = new Error(\n '[Askr] Failed to parse embedded SSR render data during hydration.'\n );\n (error as Error & { cause?: unknown }).cause = err;\n throw error;\n }\n }\n }\n\n return null;\n}\n\nexport function markSkippedElements(\n root: Element,\n skipSelectors: string[]\n): void {\n if (skipSelectors.length === 0) {\n return;\n }\n\n const uniqueSelectors = Array.from(new Set(skipSelectors));\n const selectorList = uniqueSelectors.join(', ');\n const elements = root.querySelectorAll(selectorList);\n elements.forEach((el) => el.setAttribute('data-skip-hydrate', 'true'));\n}\n\nfunction collectDeferredBelowFoldBoundaries(\n root: Element,\n foldY: number\n): Element[] {\n const boundaries: Element[] = [];\n const stack: Element[] = [];\n\n for (let index = root.children.length - 1; index >= 0; index -= 1) {\n stack.push(root.children[index]);\n }\n\n while (stack.length > 0) {\n const element = stack.pop()!;\n\n if (element.hasAttribute('data-skip-hydrate')) {\n continue;\n }\n\n const rect = element.getBoundingClientRect();\n if (rect.top >= foldY) {\n element.setAttribute('data-skip-hydrate', 'true');\n boundaries.push(element);\n continue;\n }\n\n for (let index = element.children.length - 1; index >= 0; index -= 1) {\n stack.push(element.children[index]);\n }\n }\n\n return boundaries;\n}\n\nfunction activateVisibleDeferredBoundaries(\n boundaries: Element[],\n foldY: number\n): { activated: boolean; remaining: number } {\n let activated = false;\n let remaining = 0;\n\n for (const element of boundaries) {\n if (!element.hasAttribute('data-skip-hydrate')) {\n continue;\n }\n\n const rect = element.getBoundingClientRect();\n if (rect.top < foldY) {\n element.removeAttribute('data-skip-hydrate');\n activated = true;\n } else {\n remaining += 1;\n }\n }\n\n return { activated, remaining };\n}\n\nfunction queueIdleWork(work: () => void): Promise<void> {\n return new Promise((resolve) => {\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(\n () => {\n work();\n resolve();\n },\n { timeout: 2000 }\n );\n return;\n }\n\n setTimeout(() => {\n work();\n resolve();\n }, 0);\n });\n}\n\nexport function shouldVerifyHydrationMarkup(config: HydrateSPAConfig): boolean {\n const explicit = config.hydrate?.verifyMarkup;\n if (typeof explicit === 'boolean') {\n return explicit;\n }\n\n return !isProductionEnvironment();\n}\n\nexport async function applySelectiveHydration(\n rootElement: Element,\n resolved: ResolvedRoute,\n path: string,\n cleanupStrict: boolean | undefined,\n hydrateOptions: NonNullable<HydrateSPAConfig['hydrate']>,\n source: BootAppRouteSource | undefined,\n hooks: HydrationRuntimeHooks\n): Promise<void> {\n const hasPermanentSkips = (hydrateOptions.skipSelectors?.length ?? 0) > 0;\n const hasBelowFoldDeferral = !!hydrateOptions.deferBelowFold;\n const hasSelectiveBoundaries = hasPermanentSkips || hasBelowFoldDeferral;\n let staticChildSlotsCacheSuspended = false;\n let releaseSelectiveHydrationResources = () => {};\n\n const restoreStaticChildSlotsCache = () => {\n if (!staticChildSlotsCacheSuspended) {\n return;\n }\n\n setStaticChildSlotsCacheEnabled(true);\n staticChildSlotsCacheSuspended = false;\n };\n\n if (hydrateOptions.skipSelectors?.length) {\n markSkippedElements(rootElement, hydrateOptions.skipSelectors);\n }\n\n let deferredBoundaries: Element[] = [];\n if (hydrateOptions.deferBelowFold) {\n setStaticChildSlotsCacheEnabled(false);\n staticChildSlotsCacheSuspended = true;\n const foldY = hydrateOptions.foldThreshold ?? window.innerHeight;\n deferredBoundaries = collectDeferredBelowFoldBoundaries(rootElement, foldY);\n\n let selectiveHydrationResourcesReleased = false;\n let unregisterRootCleanupCallback = () => {};\n\n function handleScroll() {\n const { activated, remaining } = activateVisibleDeferredBoundaries(\n deferredBoundaries,\n foldY\n );\n\n if (!activated) {\n return;\n }\n\n hooks.flushHydrationActivation(rootElement);\n\n if (remaining === 0) {\n releaseSelectiveHydrationResources();\n }\n }\n\n releaseSelectiveHydrationResources = () => {\n if (selectiveHydrationResourcesReleased) {\n return;\n }\n\n selectiveHydrationResourcesReleased = true;\n unregisterRootCleanupCallback();\n window.removeEventListener('scroll', handleScroll);\n restoreStaticChildSlotsCache();\n };\n\n unregisterRootCleanupCallback = hooks.registerRootCleanupCallback(\n rootElement,\n releaseSelectiveHydrationResources\n );\n\n window.addEventListener('scroll', handleScroll, { passive: true });\n }\n\n if (hydrateOptions.deferUntilIdle && !hasSelectiveBoundaries) {\n await queueIdleWork(() => {\n hooks.mountOrUpdate(\n rootElement,\n (() => resolved.handler(resolved.params)) as ComponentFunction,\n {\n cleanupStrict,\n }\n );\n });\n await hooks.registerAppNavigation(rootElement, path, source);\n return;\n }\n\n try {\n hooks.mountOrUpdate(\n rootElement,\n (() => resolved.handler(resolved.params)) as ComponentFunction,\n {\n cleanupStrict,\n }\n );\n await hooks.registerAppNavigation(rootElement, path, source);\n } catch (error) {\n releaseSelectiveHydrationResources();\n throw error;\n }\n\n if (hydrateOptions.deferUntilIdle && deferredBoundaries.length > 0) {\n await queueIdleWork(() => {\n try {\n const { activated } = activateVisibleDeferredBoundaries(\n deferredBoundaries,\n Number.POSITIVE_INFINITY\n );\n if (activated) {\n hooks.flushHydrationActivation(rootElement);\n }\n } finally {\n releaseSelectiveHydrationResources();\n }\n });\n }\n\n if (deferredBoundaries.length === 0) {\n releaseSelectiveHydrationResources();\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { isProductionEnvironment } from "../common/env.js";
2
- import { configureScrollRestoration } from "../router/navigation-scroll.js";
3
2
  import { assertExecutionModel } from "../runtime/execution-model.js";
4
3
  import { startHydrationRenderPhase, stopHydrationRenderPhase } from "../common/render-context.js";
4
+ import "../runtime/index.js";
5
+ import { configureScrollRestoration } from "../router/navigation-scroll.js";
5
6
  import { _setActiveRouteAuthOptions, hasRegisteredRoutes, lockRouteRegistration } from "../router/store.js";
6
7
  import { route } from "../router/authoring.js";
7
8
  import { setServerLocation } from "../router/activity.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/boot/index.ts"],"sourcesContent":["/**\n * App bootstrap and mount\n */\n\nimport { isProductionEnvironment } from '../common/env';\nimport type { ResolvedRoute } from '../common/router';\nimport { configureScrollRestoration } from '../router/navigate';\nimport {\n _applyManifest,\n _drainLazy,\n _setActiveRouteAuthOptions,\n _snapshotRouteSourceLazy,\n _snapshotLazy,\n clearRoutes,\n hasRegisteredRoutes,\n lockRouteRegistration,\n route as registerRoute,\n setServerLocation,\n} from '../router/route';\nimport { assertExecutionModel } from '../runtime/execution-model';\nimport {\n startHydrationRenderPhase,\n stopHydrationRenderPhase,\n} from '../common/render-context';\nimport {\n applySelectiveHydration,\n markSkippedElements,\n shouldVerifyHydrationMarkup,\n takeHydrationRenderData,\n} from './hydration';\nimport {\n flushHydrationActivation,\n mountOrUpdate,\n registerAppNavigation,\n registerRootCleanupCallback,\n} from './root-lifecycle';\nimport {\n bindDeniedRouteHandler,\n bindDeniedStatus,\n bindResolvedRouteHandler,\n resolveInitialRoute,\n} from './route-startup';\nimport type {\n HydrateSPAConfig,\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n} from './types';\n\nexport { cleanupApp, hasApp } from './root-lifecycle';\nexport type {\n HydrateSPAConfig,\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n} from './types';\n\n/**\n * createIsland: Enhances existing DOM (no router, mounts once)\n */\nexport function createIsland(config: IslandConfig): void {\n assertExecutionModel('islands');\n if (!config || typeof config !== 'object') {\n throw new Error('createIsland requires a config object');\n }\n if (typeof config.component !== 'function') {\n throw new Error('createIsland: component must be a function');\n }\n\n const rootElement =\n typeof config.root === 'string'\n ? document.getElementById(config.root)\n : config.root;\n if (!rootElement) throw new Error(`Root element not found: ${config.root}`);\n\n // Islands must not initialize router or routes\n if ('routes' in config) {\n throw new Error(\n 'createIsland does not accept routes; use createSPA for routed apps'\n );\n }\n\n // Routes are never supported with islands.\n // If routes were registered (even at module load time), fail fast to avoid\n // surprising partial router behavior.\n if (hasRegisteredRoutes()) {\n throw new Error(\n 'Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead.'\n );\n }\n\n mountOrUpdate(rootElement, config.component, {\n cleanupStrict: config.cleanupStrict,\n });\n}\n\n/**\n * createIslands: Enhances one or more existing DOM roots (no router).\n * The only public islands constructor.\n */\nexport function createIslands(config: IslandsConfig): void {\n assertExecutionModel('islands');\n if (!config || typeof config !== 'object') {\n throw new Error('createIslands requires a config object');\n }\n if (!Array.isArray(config.islands) || config.islands.length === 0) {\n throw new Error('createIslands requires a non-empty islands array');\n }\n for (const island of config.islands) {\n createIsland(island);\n }\n}\n\n/**\n * createSPA: Initializes router and mounts the app with the provided route manifest or route table.\n *\n * Preferred usage with manifest:\n * ```ts\n * import { getManifest } from '@askrjs/askr/router';\n * await createSPA({ root: '#app', manifest: getManifest() });\n * ```\n *\n * Legacy usage with plain routes array (still supported):\n * ```ts\n * await createSPA({ root: '#app', routes: getRoutes() });\n * ```\n */\nexport async function createSPA(config: SPAConfig): Promise<void> {\n assertExecutionModel('spa');\n if (!config || typeof config !== 'object') {\n throw new Error('createSPA requires a config object');\n }\n\n const manifest = config.manifest ?? config.registry?.manifest;\n const routeTable = config.routes ?? config.registry?.routes;\n const hasManifest = manifest != null && manifest.records.length > 0;\n const hasRoutes = Array.isArray(routeTable) && routeTable.length > 0;\n\n if (!hasManifest && !hasRoutes) {\n throw new Error(\n 'createSPA requires a route manifest or route table. ' +\n 'Pass `manifest: getManifest()` or `routes: getRoutes()`. ' +\n 'If you are enhancing existing HTML, use createIsland instead.'\n );\n }\n\n const rootElement =\n typeof config.root === 'string'\n ? document.getElementById(config.root)\n : config.root;\n if (!rootElement) throw new Error(`Root element not found: ${config.root}`);\n\n const pendingLazyAtBoot = [\n ..._snapshotLazy(),\n ..._snapshotRouteSourceLazy({ registry: config.registry, manifest }),\n ];\n\n configureScrollRestoration(config.scrollRestoration);\n\n clearRoutes();\n\n if (hasManifest) {\n // Preferred path: apply pre-built manifest records directly\n _applyManifest(manifest!);\n } else {\n // Legacy path: register plain Route objects (no layout metadata)\n for (const r of routeTable!) {\n registerRoute(r.path, r.handler as Parameters<typeof registerRoute>[1]);\n }\n }\n\n const routeAuth = config.auth ?? manifest?.auth;\n const activeManifest = hasManifest ? manifest : undefined;\n const appRouteSource = {\n manifest: activeManifest,\n routes: hasManifest ? undefined : routeTable,\n auth: routeAuth,\n };\n _setActiveRouteAuthOptions(routeAuth);\n\n // Drain any lazy() imports so all split chunks are ready before mounting\n await _drainLazy(pendingLazyAtBoot);\n\n // Lock registration in production to prevent late registration surprises\n if (isProductionEnvironment()) lockRouteRegistration();\n\n // Mount the currently-resolved route handler (if any)\n const { path, resolved } = await resolveInitialRoute(routeAuth);\n\n if (!resolved) {\n mountOrUpdate(rootElement, () => ({ type: 'div', children: [] }), {\n cleanupStrict: config.cleanupStrict,\n });\n\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n return;\n }\n\n if (resolved.kind === 'redirect') {\n mountOrUpdate(rootElement, () => ({ type: 'div', children: [] }), {\n cleanupStrict: config.cleanupStrict,\n });\n\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n return;\n }\n\n mountOrUpdate(\n rootElement,\n resolved.kind === 'deny'\n ? bindDeniedStatus(resolved.status)\n : bindResolvedRouteHandler({\n handler: resolved.handler,\n params: resolved.params,\n }),\n {\n cleanupStrict: config.cleanupStrict,\n }\n );\n\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n}\n\n/**\n * hydrateSPA: Hydrate server-rendered HTML.\n * Accepts either a `manifest` (preferred) or a legacy `routes` array.\n */\nexport async function hydrateSPA(config: HydrateSPAConfig): Promise<void> {\n assertExecutionModel('spa');\n if (!config || typeof config !== 'object') {\n throw new Error('hydrateSPA requires a config object');\n }\n\n const manifest = config.manifest ?? config.registry?.manifest;\n const routeTable = config.routes ?? config.registry?.routes;\n const hasManifest = manifest != null && manifest.records.length > 0;\n const hasRoutes = Array.isArray(routeTable) && routeTable.length > 0;\n\n if (!hasManifest && !hasRoutes) {\n throw new Error(\n 'hydrateSPA requires a route manifest or route table. ' +\n 'Pass `manifest: getManifest()` or `routes: getRoutes()`. ' +\n 'If you are enhancing existing HTML, use createIsland instead.'\n );\n }\n\n const rootElement =\n typeof config.root === 'string'\n ? document.getElementById(config.root)\n : config.root;\n if (!rootElement) throw new Error(`Root element not found: ${config.root}`);\n const hydrationRenderData = takeHydrationRenderData(rootElement);\n\n const pendingLazyAtHydrationBoot = [\n ..._snapshotLazy(),\n ..._snapshotRouteSourceLazy({ registry: config.registry, manifest }),\n ];\n\n configureScrollRestoration(config.scrollRestoration);\n\n clearRoutes();\n\n if (hasManifest) {\n _applyManifest(manifest!);\n } else {\n for (const r of routeTable!) {\n registerRoute(r.path, r.handler as Parameters<typeof registerRoute>[1]);\n }\n }\n\n const routeAuth = config.auth ?? manifest?.auth;\n const activeManifest = hasManifest ? manifest : undefined;\n const appRouteSource = {\n manifest: activeManifest,\n routes: hasManifest ? undefined : routeTable,\n auth: routeAuth,\n };\n _setActiveRouteAuthOptions(routeAuth);\n\n // Drain any lazy() imports so all split chunks are ready before mounting\n await _drainLazy(pendingLazyAtHydrationBoot);\n\n const {\n path,\n href: currentUrl,\n resolved,\n } = await resolveInitialRoute(routeAuth);\n setServerLocation(currentUrl);\n if (isProductionEnvironment()) lockRouteRegistration();\n\n if (!resolved) {\n throw new Error(`hydrateSPA: no route found for current path (${path}).`);\n }\n\n if (resolved.kind === 'redirect') {\n throw new Error(\n `hydrateSPA: unresolved redirect for current path (${path}).`\n );\n }\n\n const hydrationResolved: ResolvedRoute =\n resolved.kind === 'deny'\n ? { handler: bindDeniedRouteHandler(resolved.status), params: {} }\n : { handler: resolved.handler, params: resolved.params };\n\n if (shouldVerifyHydrationMarkup(config)) {\n const legacyRouteTable = hasManifest\n ? manifest!.records.map((r) => ({\n ...r,\n path: r.path,\n handler: r.handler,\n namespace: r.options.namespace,\n }))\n : routeTable!;\n\n const { verifyHydrationSyncForUrl } =\n await import('../ssr/verify-hydration');\n if (\n !verifyHydrationSyncForUrl({\n root: rootElement,\n url: currentUrl,\n routes: legacyRouteTable,\n resolved: hydrationResolved,\n options: {\n data: hydrationRenderData ?? undefined,\n },\n })\n ) {\n throw new Error(\n '[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output.'\n );\n }\n }\n\n const hydrateOptions = config.hydrate;\n if (hydrateOptions) {\n if (hydrateOptions.deferUntilIdle || hydrateOptions.deferBelowFold) {\n if (hydrationRenderData) {\n startHydrationRenderPhase(hydrationRenderData);\n }\n try {\n await applySelectiveHydration(\n rootElement,\n hydrationResolved,\n path,\n config.cleanupStrict,\n hydrateOptions,\n appRouteSource,\n {\n mountOrUpdate,\n registerAppNavigation,\n registerRootCleanupCallback,\n flushHydrationActivation,\n }\n );\n } finally {\n if (hydrationRenderData) {\n stopHydrationRenderPhase();\n }\n }\n return;\n }\n\n if (hydrateOptions.skipSelectors?.length) {\n markSkippedElements(rootElement, hydrateOptions.skipSelectors);\n }\n }\n\n if (hydrationRenderData) {\n startHydrationRenderPhase(hydrationRenderData);\n }\n try {\n mountOrUpdate(\n rootElement,\n resolved.kind === 'deny'\n ? bindDeniedStatus(resolved.status)\n : bindResolvedRouteHandler(hydrationResolved),\n {\n cleanupStrict: config.cleanupStrict,\n }\n );\n } finally {\n if (hydrationRenderData) {\n stopHydrationRenderPhase();\n }\n }\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/boot/index.ts"],"sourcesContent":["/**\n * App bootstrap and mount\n */\n\nimport { isProductionEnvironment } from '../common/env';\nimport type { ResolvedRoute } from '../common/router';\nimport { configureScrollRestoration } from '../router/navigate';\nimport {\n _applyManifest,\n _drainLazy,\n _setActiveRouteAuthOptions,\n _snapshotRouteSourceLazy,\n _snapshotLazy,\n clearRoutes,\n hasRegisteredRoutes,\n lockRouteRegistration,\n route as registerRoute,\n setServerLocation,\n} from '../router/route';\nimport { assertExecutionModel } from '../runtime';\nimport {\n startHydrationRenderPhase,\n stopHydrationRenderPhase,\n} from '../common/render-context';\nimport {\n applySelectiveHydration,\n markSkippedElements,\n shouldVerifyHydrationMarkup,\n takeHydrationRenderData,\n} from './hydration';\nimport {\n flushHydrationActivation,\n mountOrUpdate,\n registerAppNavigation,\n registerRootCleanupCallback,\n} from './root-lifecycle';\nimport {\n bindDeniedRouteHandler,\n bindDeniedStatus,\n bindResolvedRouteHandler,\n resolveInitialRoute,\n} from './route-startup';\nimport type {\n HydrateSPAConfig,\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n} from './types';\n\nexport { cleanupApp, hasApp } from './root-lifecycle';\nexport type {\n HydrateSPAConfig,\n IslandConfig,\n IslandsConfig,\n SPAConfig,\n} from './types';\n\n/**\n * createIsland: Enhances existing DOM (no router, mounts once)\n */\nexport function createIsland(config: IslandConfig): void {\n assertExecutionModel('islands');\n if (!config || typeof config !== 'object') {\n throw new Error('createIsland requires a config object');\n }\n if (typeof config.component !== 'function') {\n throw new Error('createIsland: component must be a function');\n }\n\n const rootElement =\n typeof config.root === 'string'\n ? document.getElementById(config.root)\n : config.root;\n if (!rootElement) throw new Error(`Root element not found: ${config.root}`);\n\n // Islands must not initialize router or routes\n if ('routes' in config) {\n throw new Error(\n 'createIsland does not accept routes; use createSPA for routed apps'\n );\n }\n\n // Routes are never supported with islands.\n // If routes were registered (even at module load time), fail fast to avoid\n // surprising partial router behavior.\n if (hasRegisteredRoutes()) {\n throw new Error(\n 'Routes are not supported with islands. Use createSPA (client) or createSSR (server) instead.'\n );\n }\n\n mountOrUpdate(rootElement, config.component, {\n cleanupStrict: config.cleanupStrict,\n });\n}\n\n/**\n * createIslands: Enhances one or more existing DOM roots (no router).\n * The only public islands constructor.\n */\nexport function createIslands(config: IslandsConfig): void {\n assertExecutionModel('islands');\n if (!config || typeof config !== 'object') {\n throw new Error('createIslands requires a config object');\n }\n if (!Array.isArray(config.islands) || config.islands.length === 0) {\n throw new Error('createIslands requires a non-empty islands array');\n }\n for (const island of config.islands) {\n createIsland(island);\n }\n}\n\n/**\n * createSPA: Initializes router and mounts the app with the provided route manifest or route table.\n *\n * Preferred usage with manifest:\n * ```ts\n * import { getManifest } from '@askrjs/askr/router';\n * await createSPA({ root: '#app', manifest: getManifest() });\n * ```\n *\n * Legacy usage with plain routes array (still supported):\n * ```ts\n * await createSPA({ root: '#app', routes: getRoutes() });\n * ```\n */\nexport async function createSPA(config: SPAConfig): Promise<void> {\n assertExecutionModel('spa');\n if (!config || typeof config !== 'object') {\n throw new Error('createSPA requires a config object');\n }\n\n const manifest = config.manifest ?? config.registry?.manifest;\n const routeTable = config.routes ?? config.registry?.routes;\n const hasManifest = manifest != null && manifest.records.length > 0;\n const hasRoutes = Array.isArray(routeTable) && routeTable.length > 0;\n\n if (!hasManifest && !hasRoutes) {\n throw new Error(\n 'createSPA requires a route manifest or route table. ' +\n 'Pass `manifest: getManifest()` or `routes: getRoutes()`. ' +\n 'If you are enhancing existing HTML, use createIsland instead.'\n );\n }\n\n const rootElement =\n typeof config.root === 'string'\n ? document.getElementById(config.root)\n : config.root;\n if (!rootElement) throw new Error(`Root element not found: ${config.root}`);\n\n const pendingLazyAtBoot = [\n ..._snapshotLazy(),\n ..._snapshotRouteSourceLazy({ registry: config.registry, manifest }),\n ];\n\n configureScrollRestoration(config.scrollRestoration);\n\n clearRoutes();\n\n if (hasManifest) {\n // Preferred path: apply pre-built manifest records directly\n _applyManifest(manifest!);\n } else {\n // Legacy path: register plain Route objects (no layout metadata)\n for (const r of routeTable!) {\n registerRoute(r.path, r.handler as Parameters<typeof registerRoute>[1]);\n }\n }\n\n const routeAuth = config.auth ?? manifest?.auth;\n const activeManifest = hasManifest ? manifest : undefined;\n const appRouteSource = {\n manifest: activeManifest,\n routes: hasManifest ? undefined : routeTable,\n auth: routeAuth,\n };\n _setActiveRouteAuthOptions(routeAuth);\n\n // Drain any lazy() imports so all split chunks are ready before mounting\n await _drainLazy(pendingLazyAtBoot);\n\n // Lock registration in production to prevent late registration surprises\n if (isProductionEnvironment()) lockRouteRegistration();\n\n // Mount the currently-resolved route handler (if any)\n const { path, resolved } = await resolveInitialRoute(routeAuth);\n\n if (!resolved) {\n mountOrUpdate(rootElement, () => ({ type: 'div', children: [] }), {\n cleanupStrict: config.cleanupStrict,\n });\n\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n return;\n }\n\n if (resolved.kind === 'redirect') {\n mountOrUpdate(rootElement, () => ({ type: 'div', children: [] }), {\n cleanupStrict: config.cleanupStrict,\n });\n\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n return;\n }\n\n mountOrUpdate(\n rootElement,\n resolved.kind === 'deny'\n ? bindDeniedStatus(resolved.status)\n : bindResolvedRouteHandler({\n handler: resolved.handler,\n params: resolved.params,\n }),\n {\n cleanupStrict: config.cleanupStrict,\n }\n );\n\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n}\n\n/**\n * hydrateSPA: Hydrate server-rendered HTML.\n * Accepts either a `manifest` (preferred) or a legacy `routes` array.\n */\nexport async function hydrateSPA(config: HydrateSPAConfig): Promise<void> {\n assertExecutionModel('spa');\n if (!config || typeof config !== 'object') {\n throw new Error('hydrateSPA requires a config object');\n }\n\n const manifest = config.manifest ?? config.registry?.manifest;\n const routeTable = config.routes ?? config.registry?.routes;\n const hasManifest = manifest != null && manifest.records.length > 0;\n const hasRoutes = Array.isArray(routeTable) && routeTable.length > 0;\n\n if (!hasManifest && !hasRoutes) {\n throw new Error(\n 'hydrateSPA requires a route manifest or route table. ' +\n 'Pass `manifest: getManifest()` or `routes: getRoutes()`. ' +\n 'If you are enhancing existing HTML, use createIsland instead.'\n );\n }\n\n const rootElement =\n typeof config.root === 'string'\n ? document.getElementById(config.root)\n : config.root;\n if (!rootElement) throw new Error(`Root element not found: ${config.root}`);\n const hydrationRenderData = takeHydrationRenderData(rootElement);\n\n const pendingLazyAtHydrationBoot = [\n ..._snapshotLazy(),\n ..._snapshotRouteSourceLazy({ registry: config.registry, manifest }),\n ];\n\n configureScrollRestoration(config.scrollRestoration);\n\n clearRoutes();\n\n if (hasManifest) {\n _applyManifest(manifest!);\n } else {\n for (const r of routeTable!) {\n registerRoute(r.path, r.handler as Parameters<typeof registerRoute>[1]);\n }\n }\n\n const routeAuth = config.auth ?? manifest?.auth;\n const activeManifest = hasManifest ? manifest : undefined;\n const appRouteSource = {\n manifest: activeManifest,\n routes: hasManifest ? undefined : routeTable,\n auth: routeAuth,\n };\n _setActiveRouteAuthOptions(routeAuth);\n\n // Drain any lazy() imports so all split chunks are ready before mounting\n await _drainLazy(pendingLazyAtHydrationBoot);\n\n const {\n path,\n href: currentUrl,\n resolved,\n } = await resolveInitialRoute(routeAuth);\n setServerLocation(currentUrl);\n if (isProductionEnvironment()) lockRouteRegistration();\n\n if (!resolved) {\n throw new Error(`hydrateSPA: no route found for current path (${path}).`);\n }\n\n if (resolved.kind === 'redirect') {\n throw new Error(\n `hydrateSPA: unresolved redirect for current path (${path}).`\n );\n }\n\n const hydrationResolved: ResolvedRoute =\n resolved.kind === 'deny'\n ? { handler: bindDeniedRouteHandler(resolved.status), params: {} }\n : { handler: resolved.handler, params: resolved.params };\n\n if (shouldVerifyHydrationMarkup(config)) {\n const legacyRouteTable = hasManifest\n ? manifest!.records.map((r) => ({\n ...r,\n path: r.path,\n handler: r.handler,\n namespace: r.options.namespace,\n }))\n : routeTable!;\n\n const { verifyHydrationSyncForUrl } =\n await import('../ssr/verify-hydration');\n if (\n !verifyHydrationSyncForUrl({\n root: rootElement,\n url: currentUrl,\n routes: legacyRouteTable,\n resolved: hydrationResolved,\n options: {\n data: hydrationRenderData ?? undefined,\n },\n })\n ) {\n throw new Error(\n '[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output.'\n );\n }\n }\n\n const hydrateOptions = config.hydrate;\n if (hydrateOptions) {\n if (hydrateOptions.deferUntilIdle || hydrateOptions.deferBelowFold) {\n if (hydrationRenderData) {\n startHydrationRenderPhase(hydrationRenderData);\n }\n try {\n await applySelectiveHydration(\n rootElement,\n hydrationResolved,\n path,\n config.cleanupStrict,\n hydrateOptions,\n appRouteSource,\n {\n mountOrUpdate,\n registerAppNavigation,\n registerRootCleanupCallback,\n flushHydrationActivation,\n }\n );\n } finally {\n if (hydrationRenderData) {\n stopHydrationRenderPhase();\n }\n }\n return;\n }\n\n if (hydrateOptions.skipSelectors?.length) {\n markSkippedElements(rootElement, hydrateOptions.skipSelectors);\n }\n }\n\n if (hydrationRenderData) {\n startHydrationRenderPhase(hydrationRenderData);\n }\n try {\n mountOrUpdate(\n rootElement,\n resolved.kind === 'deny'\n ? bindDeniedStatus(resolved.status)\n : bindResolvedRouteHandler(hydrationResolved),\n {\n cleanupStrict: config.cleanupStrict,\n }\n );\n } finally {\n if (hydrationRenderData) {\n stopHydrationRenderPhase();\n }\n }\n await registerAppNavigation(rootElement, path, {\n ...appRouteSource,\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"root-lifecycle.d.ts","names":[],"sources":["../../src/boot/root-lifecycle.ts"],"mappings":";;;;iBA0DgB,2BAAA,CACd,WAAA,EAAa,OAAO,EACpB,QAAA;AAAA,iBAsHc,aAAA,CACd,WAAA,EAAa,OAAA,EACb,WAAA,EAAa,iBAAiB,EAC9B,OAAA;EAAY,aAAA;AAAA;AAAA,iBAoGE,wBAAA,CAAyB,WAAoB,EAAP,OAAO;AAAA,iBAOvC,qBAAA,CACpB,WAAA,EAAa,OAAA,EACb,IAAA,UACA,MAAA,GAAS,kBAAA,GAAkB,OAAA;AAAA,iBASb,UAAA,CAAW,IAAsB,EAAhB,OAAO;AAAA,iBA0BxB,MAAA,CAAO,IAAsB,EAAhB,OAAO"}
1
+ {"version":3,"file":"root-lifecycle.d.ts","names":[],"sources":["../../src/boot/root-lifecycle.ts"],"mappings":";;;;iBAuDgB,2BAAA,CACd,WAAA,EAAa,OAAO,EACpB,QAAA;AAAA,iBAsHc,aAAA,CACd,WAAA,EAAa,OAAA,EACb,WAAA,EAAa,iBAAiB,EAC9B,OAAA;EAAY,aAAA;AAAA;AAAA,iBAoGE,wBAAA,CAAyB,WAAoB,EAAP,OAAO;AAAA,iBAOvC,qBAAA,CACpB,WAAA,EAAa,OAAA,EACb,IAAA,UACA,MAAA,GAAS,kBAAA,GAAkB,OAAA;AAAA,iBASb,UAAA,CAAW,IAAsB,EAAhB,OAAO;AAAA,iBA0BxB,MAAA,CAAO,IAAsB,EAAhB,OAAO"}
@@ -1,17 +1,17 @@
1
1
  import { isDevelopmentEnvironment } from "../common/env.js";
2
- import { logger } from "../dev/logger.js";
2
+ import { logger } from "../common/logger.js";
3
3
  import { flushRuntimeScheduler } from "../runtime/access.js";
4
4
  import { ELEMENT_TYPE, Fragment } from "../common/jsx.js";
5
5
  import { cleanupComponent } from "../runtime/component-cleanup.js";
6
6
  import { isPromiseLike } from "../common/promise.js";
7
7
  import { createComponentInstance, mountComponent } from "../runtime/component-internal.js";
8
- import "../runtime/component.js";
8
+ import { DefaultPortal, disposeDefaultPortalScope } from "../runtime/portal.js";
9
+ import "../runtime/index.js";
9
10
  import { removeAllListeners, teardownNodeSubtree } from "../renderer/cleanup.js";
10
11
  import { installRendererBridge } from "../renderer/index.js";
11
12
  import { clearRoutes } from "../router/manifest.js";
12
13
  import "../router/route.js";
13
14
  import { registerAppInstance, unregisterAppInstance } from "../router/navigation-registry.js";
14
- import { DefaultPortal, disposeDefaultPortalScope } from "../foundations/structures/portal.js";
15
15
  import "../jsx/index.js";
16
16
  import { initializeNavigation } from "../router/navigate.js";
17
17
  //#region src/boot/root-lifecycle.ts
@@ -102,7 +102,7 @@ function mountOrUpdate(rootElement, componentFn, options) {
102
102
  const portalVNode = {
103
103
  $$typeof: ELEMENT_TYPE,
104
104
  type: DefaultPortal,
105
- props: {},
105
+ props: { __askrAutoDefaultPortal: true },
106
106
  key: "__default_portal"
107
107
  };
108
108
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"root-lifecycle.js","names":[],"sources":["../../src/boot/root-lifecycle.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { isPromiseLike } from '../common/promise';\nimport { logger } from '../dev/logger';\nimport {\n DefaultPortal,\n disposeDefaultPortalScope,\n} from '../foundations/structures/portal';\nimport { ELEMENT_TYPE, Fragment } from '../jsx';\nimport {\n initializeNavigation,\n registerAppInstance,\n unregisterAppInstance,\n} from '../router/navigate';\nimport { clearRoutes } from '../router/route';\nimport { flushRuntimeScheduler } from '../runtime/access';\nimport {\n cleanupComponent,\n createComponentInstance,\n mountComponent,\n type ComponentFunction,\n type ComponentInstance,\n} from '../runtime/component';\nimport {\n installRendererBridge,\n removeAllListeners,\n teardownNodeSubtree,\n} from '../renderer';\nimport type { BootAppRouteSource } from './types';\n\ninstallRendererBridge();\n\nlet componentIdCounter = 0;\n\nconst instancesByRoot = new WeakMap<Element, ComponentInstance>();\nconst routedRoots = new Set<Element>();\n\nconst CLEANUP_SYMBOL = Symbol.for('__askrCleanup__');\nconst ROOT_CLEANUP_CALLBACKS_SYMBOL = Symbol.for(\n '__askrRootCleanupCallbacks__'\n);\n\ntype RootCleanupOptions = {\n preserveInstance?: boolean;\n};\n\ninterface ElementWithCleanup extends Element {\n [CLEANUP_SYMBOL]?: (options?: RootCleanupOptions) => void;\n [ROOT_CLEANUP_CALLBACKS_SYMBOL]?: Set<() => void>;\n}\n\nfunction clearRootCleanupCallbacks(rootElement: Element): void {\n try {\n delete (rootElement as ElementWithCleanup)[ROOT_CLEANUP_CALLBACKS_SYMBOL];\n } catch {\n (rootElement as ElementWithCleanup)[ROOT_CLEANUP_CALLBACKS_SYMBOL]?.clear();\n }\n}\n\nexport function registerRootCleanupCallback(\n rootElement: Element,\n callback: () => void\n): () => void {\n const elementWithCleanup = rootElement as ElementWithCleanup;\n const callbacks =\n elementWithCleanup[ROOT_CLEANUP_CALLBACKS_SYMBOL] ?? new Set();\n callbacks.add(callback);\n elementWithCleanup[ROOT_CLEANUP_CALLBACKS_SYMBOL] = callbacks;\n\n return () => {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n clearRootCleanupCallbacks(rootElement);\n }\n };\n}\n\nfunction runRootCleanupCallbacks(\n rootElement: Element,\n errors: unknown[]\n): void {\n const callbacks = (rootElement as ElementWithCleanup)[\n ROOT_CLEANUP_CALLBACKS_SYMBOL\n ];\n if (!callbacks || callbacks.size === 0) {\n clearRootCleanupCallbacks(rootElement);\n return;\n }\n\n clearRootCleanupCallbacks(rootElement);\n for (const callback of callbacks) {\n try {\n callback();\n } catch (e) {\n errors.push(e);\n }\n }\n}\n\nfunction cleanupRootInstance(\n rootElement: Element,\n instance: ComponentInstance,\n options?: RootCleanupOptions\n) {\n const errors: unknown[] = [];\n try {\n teardownNodeSubtree(rootElement);\n } catch (e) {\n errors.push(e);\n }\n\n try {\n cleanupComponent(instance);\n } catch (e) {\n errors.push(e);\n }\n\n runRootCleanupCallbacks(rootElement, errors);\n\n if (!options?.preserveInstance) {\n unregisterAppInstance(instance);\n instancesByRoot.delete(rootElement);\n clearRootCleanupCallbacks(rootElement);\n try {\n delete (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n } catch {\n // Ignore cleanup marker removal failures.\n }\n }\n\n if (errors.length > 0) {\n if (instance.cleanupStrict) {\n throw new AggregateError(errors, `cleanup failed for app root`);\n } else if (isDevelopmentEnvironment()) {\n for (const err of errors) logger.warn('[Askr] cleanup error:', err);\n }\n }\n}\n\nfunction attachCleanupForRoot(\n rootElement: Element,\n instance: ComponentInstance\n) {\n (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL] = (options) => {\n cleanupRootInstance(rootElement, instance, options);\n };\n\n try {\n const descriptor =\n Object.getOwnPropertyDescriptor(rootElement, 'innerHTML') ||\n Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(rootElement),\n 'innerHTML'\n ) ||\n Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');\n\n if (descriptor && (descriptor.get || descriptor.set)) {\n Object.defineProperty(rootElement, 'innerHTML', {\n get: descriptor.get\n ? function (this: Element) {\n return descriptor.get!.call(this);\n }\n : undefined,\n set: function (this: Element, value: string) {\n if (value === '' && instancesByRoot.get(this) === instance) {\n cleanupRootInstance(rootElement, instance);\n }\n if (descriptor.set) {\n return descriptor.set.call(this, value);\n }\n },\n configurable: true,\n });\n }\n } catch {\n // If Object.defineProperty fails, ignore\n }\n}\n\nexport function mountOrUpdate(\n rootElement: Element,\n componentFn: ComponentFunction,\n options?: { cleanupStrict?: boolean }\n) {\n const wrappedFn: ComponentFunction = (props, ctx) => {\n const out = componentFn(props, ctx);\n if (isPromiseLike(out)) {\n throw new Error(\n 'Async components are not supported. Components must return synchronously.'\n );\n }\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: {},\n key: '__default_portal',\n } as unknown;\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: {\n children:\n out === undefined || out === null\n ? [portalVNode]\n : [out, portalVNode],\n },\n } as unknown as ReturnType<ComponentFunction>;\n };\n Object.defineProperty(wrappedFn, 'name', {\n value: componentFn.name || 'Component',\n });\n\n const existingCleanup = (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n const reusedExistingInstance = typeof existingCleanup === 'function';\n if (reusedExistingInstance) {\n existingCleanup({ preserveInstance: true });\n }\n\n let instance = instancesByRoot.get(rootElement);\n\n if (instance) {\n const shouldResetHookState = instance.fn.name !== wrappedFn.name;\n\n if (!reusedExistingInstance) {\n removeAllListeners(rootElement);\n try {\n cleanupComponent(instance);\n } catch (e) {\n if (isDevelopmentEnvironment()) {\n logger.warn('[Askr] prior cleanup threw:', e);\n }\n }\n }\n\n instance.fn = wrappedFn;\n instance.evaluationGeneration++;\n instance.mounted = false;\n instance.expectedStateIndices = [];\n instance.firstRenderComplete = false;\n instance.isRoot = true;\n instance.portalScope = instance;\n\n if (shouldResetHookState) {\n instance.stateValues = [];\n instance.hasPendingUpdate = false;\n instance.notifyUpdate = null;\n instance.stateIndexCheck = -1;\n instance.mountOperations = [];\n instance.commitOperations = [];\n instance.lifecycleSlots = [];\n instance.cleanupFns = [];\n instance._currentRenderToken = undefined;\n instance.lastRenderToken = 0;\n instance._pendingReadSources = undefined;\n instance._lastReadSources = undefined;\n instance._placeholder = undefined;\n instance.errorBoundaryState = undefined;\n instance.devWarningsEmitted = undefined;\n }\n\n if (options && typeof options.cleanupStrict === 'boolean') {\n instance.cleanupStrict = options.cleanupStrict;\n }\n } else {\n const componentId = String(++componentIdCounter);\n instance = createComponentInstance(componentId, wrappedFn, {}, rootElement);\n instancesByRoot.set(rootElement, instance);\n instance.isRoot = true;\n instance.portalScope = instance;\n if (options && typeof options.cleanupStrict === 'boolean') {\n instance.cleanupStrict = options.cleanupStrict;\n }\n }\n\n attachCleanupForRoot(rootElement, instance);\n registerRootCleanupCallback(rootElement, () => {\n disposeDefaultPortalScope(instance.portalScope ?? instance);\n });\n mountComponent(instance);\n flushRuntimeScheduler();\n}\n\nexport function flushHydrationActivation(rootElement: Element): void {\n const instance = instancesByRoot.get(rootElement);\n if (!instance) return;\n instance._enqueueRun?.();\n flushRuntimeScheduler();\n}\n\nexport async function registerAppNavigation(\n rootElement: Element,\n path: string,\n source?: BootAppRouteSource\n) {\n const instance = instancesByRoot.get(rootElement);\n if (!instance) throw new Error('Internal error: app instance missing');\n routedRoots.add(rootElement);\n registerAppInstance(instance, path, source);\n initializeNavigation();\n}\n\nexport function cleanupApp(root: Element | string): void {\n const rootElement =\n typeof root === 'string' ? document.getElementById(root) : root;\n\n if (!rootElement) return;\n\n const cleanupFn = (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n try {\n if (typeof cleanupFn === 'function') {\n cleanupFn();\n }\n } finally {\n const wasRoutedRoot = routedRoots.delete(rootElement);\n instancesByRoot.delete(rootElement);\n clearRootCleanupCallbacks(rootElement);\n if (wasRoutedRoot && routedRoots.size === 0) {\n clearRoutes();\n }\n try {\n delete (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n } catch {\n // Ignore cleanup marker removal failures.\n }\n }\n}\n\nexport function hasApp(root: Element | string): boolean {\n const rootElement =\n typeof root === 'string' ? document.getElementById(root) : root;\n\n if (!rootElement) return false;\n return instancesByRoot.has(rootElement);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"root-lifecycle.js","names":[],"sources":["../../src/boot/root-lifecycle.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { isPromiseLike } from '../common/promise';\nimport { logger } from '../common/logger';\nimport { DefaultPortal, disposeDefaultPortalScope } from '../runtime';\nimport { ELEMENT_TYPE, Fragment } from '../jsx';\nimport {\n initializeNavigation,\n registerAppInstance,\n unregisterAppInstance,\n} from '../router/navigate';\nimport { clearRoutes } from '../router/route';\nimport {\n cleanupComponent,\n createComponentInstance,\n flushRuntimeScheduler,\n mountComponent,\n type ComponentFunction,\n type ComponentInstance,\n} from '../runtime';\nimport {\n installRendererBridge,\n removeAllListeners,\n teardownNodeSubtree,\n} from '../renderer';\nimport type { BootAppRouteSource } from './types';\n\ninstallRendererBridge();\n\nlet componentIdCounter = 0;\n\nconst instancesByRoot = new WeakMap<Element, ComponentInstance>();\nconst routedRoots = new Set<Element>();\n\nconst CLEANUP_SYMBOL = Symbol.for('__askrCleanup__');\nconst ROOT_CLEANUP_CALLBACKS_SYMBOL = Symbol.for(\n '__askrRootCleanupCallbacks__'\n);\n\ntype RootCleanupOptions = {\n preserveInstance?: boolean;\n};\n\ninterface ElementWithCleanup extends Element {\n [CLEANUP_SYMBOL]?: (options?: RootCleanupOptions) => void;\n [ROOT_CLEANUP_CALLBACKS_SYMBOL]?: Set<() => void>;\n}\n\nfunction clearRootCleanupCallbacks(rootElement: Element): void {\n try {\n delete (rootElement as ElementWithCleanup)[ROOT_CLEANUP_CALLBACKS_SYMBOL];\n } catch {\n (rootElement as ElementWithCleanup)[ROOT_CLEANUP_CALLBACKS_SYMBOL]?.clear();\n }\n}\n\nexport function registerRootCleanupCallback(\n rootElement: Element,\n callback: () => void\n): () => void {\n const elementWithCleanup = rootElement as ElementWithCleanup;\n const callbacks =\n elementWithCleanup[ROOT_CLEANUP_CALLBACKS_SYMBOL] ?? new Set();\n callbacks.add(callback);\n elementWithCleanup[ROOT_CLEANUP_CALLBACKS_SYMBOL] = callbacks;\n\n return () => {\n callbacks.delete(callback);\n if (callbacks.size === 0) {\n clearRootCleanupCallbacks(rootElement);\n }\n };\n}\n\nfunction runRootCleanupCallbacks(\n rootElement: Element,\n errors: unknown[]\n): void {\n const callbacks = (rootElement as ElementWithCleanup)[\n ROOT_CLEANUP_CALLBACKS_SYMBOL\n ];\n if (!callbacks || callbacks.size === 0) {\n clearRootCleanupCallbacks(rootElement);\n return;\n }\n\n clearRootCleanupCallbacks(rootElement);\n for (const callback of callbacks) {\n try {\n callback();\n } catch (e) {\n errors.push(e);\n }\n }\n}\n\nfunction cleanupRootInstance(\n rootElement: Element,\n instance: ComponentInstance,\n options?: RootCleanupOptions\n) {\n const errors: unknown[] = [];\n try {\n teardownNodeSubtree(rootElement);\n } catch (e) {\n errors.push(e);\n }\n\n try {\n cleanupComponent(instance);\n } catch (e) {\n errors.push(e);\n }\n\n runRootCleanupCallbacks(rootElement, errors);\n\n if (!options?.preserveInstance) {\n unregisterAppInstance(instance);\n instancesByRoot.delete(rootElement);\n clearRootCleanupCallbacks(rootElement);\n try {\n delete (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n } catch {\n // Ignore cleanup marker removal failures.\n }\n }\n\n if (errors.length > 0) {\n if (instance.cleanupStrict) {\n throw new AggregateError(errors, `cleanup failed for app root`);\n } else if (isDevelopmentEnvironment()) {\n for (const err of errors) logger.warn('[Askr] cleanup error:', err);\n }\n }\n}\n\nfunction attachCleanupForRoot(\n rootElement: Element,\n instance: ComponentInstance\n) {\n (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL] = (options) => {\n cleanupRootInstance(rootElement, instance, options);\n };\n\n try {\n const descriptor =\n Object.getOwnPropertyDescriptor(rootElement, 'innerHTML') ||\n Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(rootElement),\n 'innerHTML'\n ) ||\n Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');\n\n if (descriptor && (descriptor.get || descriptor.set)) {\n Object.defineProperty(rootElement, 'innerHTML', {\n get: descriptor.get\n ? function (this: Element) {\n return descriptor.get!.call(this);\n }\n : undefined,\n set: function (this: Element, value: string) {\n if (value === '' && instancesByRoot.get(this) === instance) {\n cleanupRootInstance(rootElement, instance);\n }\n if (descriptor.set) {\n return descriptor.set.call(this, value);\n }\n },\n configurable: true,\n });\n }\n } catch {\n // If Object.defineProperty fails, ignore\n }\n}\n\nexport function mountOrUpdate(\n rootElement: Element,\n componentFn: ComponentFunction,\n options?: { cleanupStrict?: boolean }\n) {\n const wrappedFn: ComponentFunction = (props, ctx) => {\n const out = componentFn(props, ctx);\n if (isPromiseLike(out)) {\n throw new Error(\n 'Async components are not supported. Components must return synchronously.'\n );\n }\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: { __askrAutoDefaultPortal: true },\n key: '__default_portal',\n } as unknown;\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: {\n children:\n out === undefined || out === null\n ? [portalVNode]\n : [out, portalVNode],\n },\n } as unknown as ReturnType<ComponentFunction>;\n };\n Object.defineProperty(wrappedFn, 'name', {\n value: componentFn.name || 'Component',\n });\n\n const existingCleanup = (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n const reusedExistingInstance = typeof existingCleanup === 'function';\n if (reusedExistingInstance) {\n existingCleanup({ preserveInstance: true });\n }\n\n let instance = instancesByRoot.get(rootElement);\n\n if (instance) {\n const shouldResetHookState = instance.fn.name !== wrappedFn.name;\n\n if (!reusedExistingInstance) {\n removeAllListeners(rootElement);\n try {\n cleanupComponent(instance);\n } catch (e) {\n if (isDevelopmentEnvironment()) {\n logger.warn('[Askr] prior cleanup threw:', e);\n }\n }\n }\n\n instance.fn = wrappedFn;\n instance.evaluationGeneration++;\n instance.mounted = false;\n instance.expectedStateIndices = [];\n instance.firstRenderComplete = false;\n instance.isRoot = true;\n instance.portalScope = instance;\n\n if (shouldResetHookState) {\n instance.stateValues = [];\n instance.hasPendingUpdate = false;\n instance.notifyUpdate = null;\n instance.stateIndexCheck = -1;\n instance.mountOperations = [];\n instance.commitOperations = [];\n instance.lifecycleSlots = [];\n instance.cleanupFns = [];\n instance._currentRenderToken = undefined;\n instance.lastRenderToken = 0;\n instance._pendingReadSources = undefined;\n instance._lastReadSources = undefined;\n instance._placeholder = undefined;\n instance.errorBoundaryState = undefined;\n instance.devWarningsEmitted = undefined;\n }\n\n if (options && typeof options.cleanupStrict === 'boolean') {\n instance.cleanupStrict = options.cleanupStrict;\n }\n } else {\n const componentId = String(++componentIdCounter);\n instance = createComponentInstance(componentId, wrappedFn, {}, rootElement);\n instancesByRoot.set(rootElement, instance);\n instance.isRoot = true;\n instance.portalScope = instance;\n if (options && typeof options.cleanupStrict === 'boolean') {\n instance.cleanupStrict = options.cleanupStrict;\n }\n }\n\n attachCleanupForRoot(rootElement, instance);\n registerRootCleanupCallback(rootElement, () => {\n disposeDefaultPortalScope(instance.portalScope ?? instance);\n });\n mountComponent(instance);\n flushRuntimeScheduler();\n}\n\nexport function flushHydrationActivation(rootElement: Element): void {\n const instance = instancesByRoot.get(rootElement);\n if (!instance) return;\n instance._enqueueRun?.();\n flushRuntimeScheduler();\n}\n\nexport async function registerAppNavigation(\n rootElement: Element,\n path: string,\n source?: BootAppRouteSource\n) {\n const instance = instancesByRoot.get(rootElement);\n if (!instance) throw new Error('Internal error: app instance missing');\n routedRoots.add(rootElement);\n registerAppInstance(instance, path, source);\n initializeNavigation();\n}\n\nexport function cleanupApp(root: Element | string): void {\n const rootElement =\n typeof root === 'string' ? document.getElementById(root) : root;\n\n if (!rootElement) return;\n\n const cleanupFn = (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n try {\n if (typeof cleanupFn === 'function') {\n cleanupFn();\n }\n } finally {\n const wasRoutedRoot = routedRoots.delete(rootElement);\n instancesByRoot.delete(rootElement);\n clearRootCleanupCallbacks(rootElement);\n if (wasRoutedRoot && routedRoots.size === 0) {\n clearRoutes();\n }\n try {\n delete (rootElement as ElementWithCleanup)[CLEANUP_SYMBOL];\n } catch {\n // Ignore cleanup marker removal failures.\n }\n }\n}\n\nexport function hasApp(root: Element | string): boolean {\n const rootElement =\n typeof root === 'string' ? document.getElementById(root) : root;\n\n if (!rootElement) return false;\n return instancesByRoot.has(rootElement);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"route-startup.js","names":[],"sources":["../../src/boot/route-startup.ts"],"sourcesContent":["import type {\n ResolvedRoute,\n RouteAuthOptions,\n RouteHandler,\n RouteRequestResult,\n} from '../common/router';\nimport { resolveRouteRequest } from '../router/route';\nimport type { ComponentFunction } from '../runtime/component';\n\nconst MAX_INITIAL_ROUTE_REDIRECTS = 20;\n\nexport function bindResolvedRouteHandler(\n resolved: ResolvedRoute\n): ComponentFunction {\n return () =>\n resolved.handler(resolved.params) as ReturnType<ComponentFunction>;\n}\n\nfunction createDeniedStatusNode(status: number) {\n return {\n type: 'div',\n props: {\n 'data-route-denied': String(status),\n },\n children: [String(status)],\n };\n}\n\nexport function bindDeniedStatus(status: number): ComponentFunction {\n return () => createDeniedStatusNode(status);\n}\n\nexport function bindDeniedRouteHandler(status: number): RouteHandler {\n return () => createDeniedStatusNode(status);\n}\n\nexport async function resolveInitialRoute(\n auth?: RouteAuthOptions\n): Promise<{ path: string; href: string; resolved: RouteRequestResult }> {\n let path = typeof window !== 'undefined' ? window.location.pathname : '/';\n let href =\n typeof window !== 'undefined'\n ? `${window.location.pathname}${window.location.search}${window.location.hash}`\n : path;\n const visited = new Set<string>();\n\n for (\n let redirects = 0;\n redirects <= MAX_INITIAL_ROUTE_REDIRECTS;\n redirects++\n ) {\n if (visited.has(href)) {\n throw new Error(`[Askr] Route redirect cycle detected at ${href}.`);\n }\n visited.add(href);\n\n const resolved = await resolveRouteRequest(href, { auth });\n if (\n typeof window === 'undefined' ||\n !resolved ||\n resolved.kind !== 'redirect'\n ) {\n return { path, href, resolved };\n }\n\n const redirectTarget = new URL(resolved.to, window.location.href);\n const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;\n window.history.replaceState({ path: redirectHref }, '', redirectHref);\n path = redirectTarget.pathname;\n href = redirectHref;\n }\n\n throw new Error(\n `[Askr] Route redirect limit exceeded (${MAX_INITIAL_ROUTE_REDIRECTS}).`\n );\n}\n"],"mappings":";;;AASA,MAAM,8BAA8B;AAEpC,SAAgB,yBACd,UACmB;CACnB,aACE,SAAS,QAAQ,SAAS,MAAM;AACpC;AAEA,SAAS,uBAAuB,QAAgB;CAC9C,OAAO;EACL,MAAM;EACN,OAAO,EACL,qBAAqB,OAAO,MAAM,EACpC;EACA,UAAU,CAAC,OAAO,MAAM,CAAC;CAC3B;AACF;AAEA,SAAgB,iBAAiB,QAAmC;CAClE,aAAa,uBAAuB,MAAM;AAC5C;AAEA,SAAgB,uBAAuB,QAA8B;CACnE,aAAa,uBAAuB,MAAM;AAC5C;AAEA,eAAsB,oBACpB,MACuE;CACvE,IAAI,OAAO,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW;CACtE,IAAI,OACF,OAAO,WAAW,cACd,GAAG,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS,SACvE;CACN,MAAM,0BAAU,IAAI,IAAY;CAEhC,KACE,IAAI,YAAY,GAChB,aAAa,6BACb,aACA;EACA,IAAI,QAAQ,IAAI,IAAI,GAClB,MAAM,IAAI,MAAM,2CAA2C,KAAK,EAAE;EAEpE,QAAQ,IAAI,IAAI;EAEhB,MAAM,WAAW,MAAM,oBAAoB,MAAM,EAAE,KAAK,CAAC;EACzD,IACE,OAAO,WAAW,eAClB,CAAC,YACD,SAAS,SAAS,YAElB,OAAO;GAAE;GAAM;GAAM;EAAS;EAGhC,MAAM,iBAAiB,IAAI,IAAI,SAAS,IAAI,OAAO,SAAS,IAAI;EAChE,MAAM,eAAe,GAAG,eAAe,WAAW,eAAe,SAAS,eAAe;EACzF,OAAO,QAAQ,aAAa,EAAE,MAAM,aAAa,GAAG,IAAI,YAAY;EACpE,OAAO,eAAe;EACtB,OAAO;CACT;CAEA,MAAM,IAAI,MACR,yCAAyC,4BAA4B,GACvE;AACF"}
1
+ {"version":3,"file":"route-startup.js","names":[],"sources":["../../src/boot/route-startup.ts"],"sourcesContent":["import type {\n ResolvedRoute,\n RouteAuthOptions,\n RouteHandler,\n RouteRequestResult,\n} from '../common/router';\nimport { resolveRouteRequest } from '../router/route';\nimport type { ComponentFunction } from '../runtime';\n\nconst MAX_INITIAL_ROUTE_REDIRECTS = 20;\n\nexport function bindResolvedRouteHandler(\n resolved: ResolvedRoute\n): ComponentFunction {\n return () =>\n resolved.handler(resolved.params) as ReturnType<ComponentFunction>;\n}\n\nfunction createDeniedStatusNode(status: number) {\n return {\n type: 'div',\n props: {\n 'data-route-denied': String(status),\n },\n children: [String(status)],\n };\n}\n\nexport function bindDeniedStatus(status: number): ComponentFunction {\n return () => createDeniedStatusNode(status);\n}\n\nexport function bindDeniedRouteHandler(status: number): RouteHandler {\n return () => createDeniedStatusNode(status);\n}\n\nexport async function resolveInitialRoute(\n auth?: RouteAuthOptions\n): Promise<{ path: string; href: string; resolved: RouteRequestResult }> {\n let path = typeof window !== 'undefined' ? window.location.pathname : '/';\n let href =\n typeof window !== 'undefined'\n ? `${window.location.pathname}${window.location.search}${window.location.hash}`\n : path;\n const visited = new Set<string>();\n\n for (\n let redirects = 0;\n redirects <= MAX_INITIAL_ROUTE_REDIRECTS;\n redirects++\n ) {\n if (visited.has(href)) {\n throw new Error(`[Askr] Route redirect cycle detected at ${href}.`);\n }\n visited.add(href);\n\n const resolved = await resolveRouteRequest(href, { auth });\n if (\n typeof window === 'undefined' ||\n !resolved ||\n resolved.kind !== 'redirect'\n ) {\n return { path, href, resolved };\n }\n\n const redirectTarget = new URL(resolved.to, window.location.href);\n const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;\n window.history.replaceState({ path: redirectHref }, '', redirectHref);\n path = redirectTarget.pathname;\n href = redirectHref;\n }\n\n throw new Error(\n `[Askr] Route redirect limit exceeded (${MAX_INITIAL_ROUTE_REDIRECTS}).`\n );\n}\n"],"mappings":";;;AASA,MAAM,8BAA8B;AAEpC,SAAgB,yBACd,UACmB;CACnB,aACE,SAAS,QAAQ,SAAS,MAAM;AACpC;AAEA,SAAS,uBAAuB,QAAgB;CAC9C,OAAO;EACL,MAAM;EACN,OAAO,EACL,qBAAqB,OAAO,MAAM,EACpC;EACA,UAAU,CAAC,OAAO,MAAM,CAAC;CAC3B;AACF;AAEA,SAAgB,iBAAiB,QAAmC;CAClE,aAAa,uBAAuB,MAAM;AAC5C;AAEA,SAAgB,uBAAuB,QAA8B;CACnE,aAAa,uBAAuB,MAAM;AAC5C;AAEA,eAAsB,oBACpB,MACuE;CACvE,IAAI,OAAO,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW;CACtE,IAAI,OACF,OAAO,WAAW,cACd,GAAG,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS,SACvE;CACN,MAAM,0BAAU,IAAI,IAAY;CAEhC,KACE,IAAI,YAAY,GAChB,aAAa,6BACb,aACA;EACA,IAAI,QAAQ,IAAI,IAAI,GAClB,MAAM,IAAI,MAAM,2CAA2C,KAAK,EAAE;EAEpE,QAAQ,IAAI,IAAI;EAEhB,MAAM,WAAW,MAAM,oBAAoB,MAAM,EAAE,KAAK,CAAC;EACzD,IACE,OAAO,WAAW,eAClB,CAAC,YACD,SAAS,SAAS,YAElB,OAAO;GAAE;GAAM;GAAM;EAAS;EAGhC,MAAM,iBAAiB,IAAI,IAAI,SAAS,IAAI,OAAO,SAAS,IAAI;EAChE,MAAM,eAAe,GAAG,eAAe,WAAW,eAAe,SAAS,eAAe;EACzF,OAAO,QAAQ,aAAa,EAAE,MAAM,aAAa,GAAG,IAAI,YAAY;EACpE,OAAO,eAAe;EACtB,OAAO;CACT;CAEA,MAAM,IAAI,MACR,yCAAyC,4BAA4B,GACvE;AACF"}
@@ -0,0 +1,16 @@
1
+ import { Props } from "./props.js";
2
+ import { VNode } from "./vnode.js";
3
+
4
+ //#region src/common/error-boundary.d.ts
5
+ type ErrorBoundaryContent = VNode | readonly VNode[];
6
+ type ErrorBoundaryFallbackValue = ErrorBoundaryContent | Node;
7
+ type ErrorBoundaryFallbackRender = (error: unknown, reset: () => void) => ErrorBoundaryFallbackValue;
8
+ interface ErrorBoundaryProps extends Props {
9
+ children?: ErrorBoundaryContent;
10
+ fallback?: ErrorBoundaryFallbackValue | ErrorBoundaryFallbackRender;
11
+ onError?: (error: unknown) => void;
12
+ resetKey?: unknown;
13
+ }
14
+ //#endregion
15
+ export { ErrorBoundaryContent, ErrorBoundaryFallbackRender, ErrorBoundaryFallbackValue, ErrorBoundaryProps };
16
+ //# sourceMappingURL=error-boundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-boundary.d.ts","names":[],"sources":["../../src/common/error-boundary.ts"],"mappings":";;;;KAGY,oBAAA,GAAuB,KAAA,YAAiB,KAAK;AAAA,KAC7C,0BAAA,GAA6B,oBAAA,GAAuB,IAAI;AAAA,KAExD,2BAAA,IACV,KAAA,WACA,KAAA,iBACG,0BAA0B;AAAA,UAEd,kBAAA,SAA2B,KAAA;EAC1C,QAAA,GAAW,oBAAA;EACX,QAAA,GAAW,0BAAA,GAA6B,2BAAA;EACxC,OAAA,IAAW,KAAA;EACX,QAAA;AAAA"}
@@ -0,0 +1,17 @@
1
+ //#region src/common/invariant.ts
2
+ /**
3
+ * Invariant assertions shared by production runtime code.
4
+ */
5
+ function invariant(condition, message, context) {
6
+ if (!condition) {
7
+ const contextStr = context ? "\n" + JSON.stringify(context, null, 2) : "";
8
+ throw new Error(`[Askr Invariant] ${message}${contextStr}`);
9
+ }
10
+ }
11
+ function assertSchedulingPrecondition(condition, violationMessage) {
12
+ invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
13
+ }
14
+ //#endregion
15
+ export { assertSchedulingPrecondition, invariant };
16
+
17
+ //# sourceMappingURL=invariant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invariant.js","names":[],"sources":["../../src/common/invariant.ts"],"sourcesContent":["/**\n * Invariant assertions shared by production runtime code.\n */\n\nexport function invariant(\n condition: boolean,\n message: string,\n context?: Record<string, unknown>\n): asserts condition {\n if (!condition) {\n const contextStr = context ? '\\n' + JSON.stringify(context, null, 2) : '';\n throw new Error(`[Askr Invariant] ${message}${contextStr}`);\n }\n}\n\nexport function assertSchedulingPrecondition(\n condition: boolean,\n violationMessage: string\n): asserts condition {\n invariant(condition, `[Scheduler Precondition] ${violationMessage}`);\n}\n"],"mappings":";;;;AAIA,SAAgB,UACd,WACA,SACA,SACmB;CACnB,IAAI,CAAC,WAAW;EACd,MAAM,aAAa,UAAU,OAAO,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI;EACvE,MAAM,IAAI,MAAM,oBAAoB,UAAU,YAAY;CAC5D;AACF;AAEA,SAAgB,6BACd,WACA,kBACmB;CACnB,UAAU,WAAW,4BAA4B,kBAAkB;AACrE"}
@@ -1,10 +1,9 @@
1
- import { isProductionEnvironment } from "../common/env.js";
2
- //#region src/dev/logger.ts
1
+ import { isProductionEnvironment } from "./env.js";
2
+ //#region src/common/logger.ts
3
3
  /**
4
- * Centralized logger interface
5
- * - Keeps production builds silent for debug/warn/info messages
6
- * - Ensures consistent behavior across the codebase
7
- * - Protects against missing `console` in some environments
4
+ * Shared logger interface for runtime and tooling code.
5
+ *
6
+ * Debug, info, and warn stay silent in production. Errors always log.
8
7
  */
9
8
  function callConsole(method, args) {
10
9
  const c = typeof console !== "undefined" ? console : void 0;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","names":[],"sources":["../../src/common/logger.ts"],"sourcesContent":["/**\n * Shared logger interface for runtime and tooling code.\n *\n * Debug, info, and warn stay silent in production. Errors always log.\n */\n\nimport { isProductionEnvironment } from './env';\n\nfunction callConsole(method: string, args: unknown[]): void {\n const c = typeof console !== 'undefined' ? (console as unknown) : undefined;\n if (!c) return;\n const fn = (c as Record<string, unknown>)[method];\n if (typeof fn === 'function') {\n try {\n (fn as (...a: unknown[]) => unknown).apply(console, args as unknown[]);\n } catch {\n // Ignore logging failures.\n }\n }\n}\n\nexport const logger = {\n debug: (...args: unknown[]) => {\n if (isProductionEnvironment()) return;\n callConsole('debug', args);\n },\n\n info: (...args: unknown[]) => {\n if (isProductionEnvironment()) return;\n callConsole('info', args);\n },\n\n warn: (...args: unknown[]) => {\n if (isProductionEnvironment()) return;\n callConsole('warn', args);\n },\n\n error: (...args: unknown[]) => {\n callConsole('error', args);\n },\n};\n"],"mappings":";;;;;;;AAQA,SAAS,YAAY,QAAgB,MAAuB;CAC1D,MAAM,IAAI,OAAO,YAAY,cAAe,UAAsB;CAClE,IAAI,CAAC,GAAG;CACR,MAAM,KAAM,EAA8B;CAC1C,IAAI,OAAO,OAAO,YAChB,IAAI;EACF,GAAqC,MAAM,SAAS,IAAiB;CACvE,QAAQ,CAER;AAEJ;AAEA,MAAa,SAAS;CACpB,QAAQ,GAAG,SAAoB;EAC7B,IAAI,wBAAwB,GAAG;EAC/B,YAAY,SAAS,IAAI;CAC3B;CAEA,OAAO,GAAG,SAAoB;EAC5B,IAAI,wBAAwB,GAAG;EAC/B,YAAY,QAAQ,IAAI;CAC1B;CAEA,OAAO,GAAG,SAAoB;EAC5B,IAAI,wBAAwB,GAAG;EAC/B,YAAY,QAAQ,IAAI;CAC1B;CAEA,QAAQ,GAAG,SAAoB;EAC7B,YAAY,SAAS,IAAI;CAC3B;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"vnode.js","names":[],"sources":["../../src/common/vnode.ts"],"sourcesContent":["/**\n * Common call contracts: VNode / virtual DOM shapes\n */\n\nimport type { Props } from './props';\nimport type { JSXElement, JSXElementType } from './jsx';\nimport type { ControlBoundaryState } from '../runtime/control';\nimport type { ForState } from '../runtime/for';\nexport { __CONTROL_BOUNDARY__ } from './control';\nimport { __CONTROL_BOUNDARY__ } from './control';\n\nexport const __ERROR_BOUNDARY__ = Symbol.for('askr.error-boundary');\n\nexport interface DOMElement {\n // Element `type` can be an intrinsic tag name, a component function, or\n // a special symbol (e.g. `Fragment`). Include `symbol` in the type union\n // so runtime comparisons against `Fragment` are type-safe.\n type: JSXElementType;\n props?: Props;\n children?: VNode[];\n key?: string | number | null;\n [Symbol.iterator]?: never;\n _controlState?: ControlBoundaryState; // Internal: control boundary state\n _forState?: ForState<unknown>; // Deprecated internal alias during migration\n}\n\n// Type for virtual DOM nodes\nexport type VNode = DOMElement | string | number | boolean | null | undefined;\nexport type RenderableChild = VNode | JSXElement | readonly RenderableChild[];\n\n// Backward-compatible internal alias while renderer/runtime migrates away from\n// the old For-only boundary naming.\nexport const __FOR_BOUNDARY__ = __CONTROL_BOUNDARY__;\n\nexport function _isDOMElement(node: unknown): node is DOMElement {\n return typeof node === 'object' && node !== null && 'type' in node;\n}\n"],"mappings":";;AAWA,MAAa,qBAAqB,OAAO,IAAI,qBAAqB;AAqBlE,MAAa,mBAAmB;AAEhC,SAAgB,cAAc,MAAmC;CAC/D,OAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU;AAChE"}
1
+ {"version":3,"file":"vnode.js","names":[],"sources":["../../src/common/vnode.ts"],"sourcesContent":["/**\n * Common call contracts: VNode / virtual DOM shapes\n */\n\nimport type { Props } from './props';\nimport type { JSXElement, JSXElementType } from './jsx';\nimport type { ControlBoundaryState } from '../runtime';\nimport type { ForState } from '../runtime';\nexport { __CONTROL_BOUNDARY__ } from './control';\nimport { __CONTROL_BOUNDARY__ } from './control';\n\nexport const __ERROR_BOUNDARY__ = Symbol.for('askr.error-boundary');\n\nexport interface DOMElement {\n // Element `type` can be an intrinsic tag name, a component function, or\n // a special symbol (e.g. `Fragment`). Include `symbol` in the type union\n // so runtime comparisons against `Fragment` are type-safe.\n type: JSXElementType;\n props?: Props;\n children?: VNode[];\n key?: string | number | null;\n [Symbol.iterator]?: never;\n _controlState?: ControlBoundaryState; // Internal: control boundary state\n _forState?: ForState<unknown>; // Deprecated internal alias during migration\n}\n\n// Type for virtual DOM nodes\nexport type VNode = DOMElement | string | number | boolean | null | undefined;\nexport type RenderableChild = VNode | JSXElement | readonly RenderableChild[];\n\n// Backward-compatible internal alias while renderer/runtime migrates away from\n// the old For-only boundary naming.\nexport const __FOR_BOUNDARY__ = __CONTROL_BOUNDARY__;\n\nexport function _isDOMElement(node: unknown): node is DOMElement {\n return typeof node === 'object' && node !== null && 'type' in node;\n}\n"],"mappings":";;AAWA,MAAa,qBAAqB,OAAO,IAAI,qBAAqB;AAqBlE,MAAa,mBAAmB;AAEhC,SAAgB,cAAc,MAAmC;CAC/D,OAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,UAAU;AAChE"}
@@ -1,18 +1,8 @@
1
- import { Props } from "../common/props.js";
2
1
  import { JSXElement } from "../common/jsx.js";
3
2
  import { ComponentInstance } from "../runtime/component-internal.js";
4
- import { VNode } from "../common/vnode.js";
3
+ import { ErrorBoundaryFallbackRender, ErrorBoundaryProps } from "../common/error-boundary.js";
5
4
 
6
5
  //#region src/components/error-boundary.d.ts
7
- type ErrorBoundaryContent = VNode | readonly VNode[];
8
- type ErrorBoundaryFallbackValue = ErrorBoundaryContent | Node;
9
- type ErrorBoundaryFallbackRender = (error: unknown, reset: () => void) => ErrorBoundaryFallbackValue;
10
- interface ErrorBoundaryProps extends Props {
11
- children?: ErrorBoundaryContent;
12
- fallback?: ErrorBoundaryFallbackValue | ErrorBoundaryFallbackRender;
13
- onError?: (error: unknown) => void;
14
- resetKey?: unknown;
15
- }
16
6
  type ErrorBoundaryState = NonNullable<ComponentInstance['errorBoundaryState']>;
17
7
  type ErrorBoundaryVNode = JSXElement & {
18
8
  __instance?: ComponentInstance;
@@ -20,9 +10,6 @@ type ErrorBoundaryVNode = JSXElement & {
20
10
  declare function ErrorBoundary(props: ErrorBoundaryProps): JSXElement;
21
11
  declare function isErrorBoundaryVNode(value: unknown): value is ErrorBoundaryVNode;
22
12
  declare function resolveErrorBoundaryState(vnode: ErrorBoundaryVNode): ErrorBoundaryState | null;
23
- declare function resolveErrorBoundaryFallback(fallback: ErrorBoundaryProps['fallback'], error: unknown, reset: () => void): ErrorBoundaryFallbackValue;
24
- declare function createBoundaryReset(instance: ComponentInstance): () => void;
25
- declare function reportBoundaryError(instance: ComponentInstance, error: unknown, onError?: (error: unknown) => void): void;
26
13
  //#endregion
27
- export { ErrorBoundary, ErrorBoundaryFallbackRender, ErrorBoundaryProps };
14
+ export { ErrorBoundary, type ErrorBoundaryFallbackRender, type ErrorBoundaryProps };
28
15
  //# sourceMappingURL=error-boundary.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-boundary.d.ts","names":[],"sources":["../../src/components/error-boundary.tsx"],"mappings":";;;;;;KAWK,oBAAA,GAAuB,KAAA,YAAiB,KAAK;AAAA,KAC7C,0BAAA,GAA6B,oBAAA,GAAuB,IAAI;AAAA,KAEjD,2BAAA,IACV,KAAA,WACA,KAAA,iBACG,0BAA0B;AAAA,UAEd,kBAAA,SAA2B,KAAA;EAC1C,QAAA,GAAW,oBAAA;EACX,QAAA,GAAW,0BAAA,GAA6B,2BAAA;EACxC,OAAA,IAAW,KAAA;EACX,QAAA;AAAA;AAAA,KAGG,kBAAA,GAAqB,WAAW,CAAC,iBAAA;AAAA,KAEjC,kBAAA,GAAqB,UAAA;EACxB,UAAA,GAAa,iBAAiB;AAAA;AAAA,iBA+DhB,aAAA,CAAc,KAAA,EAAO,kBAAA,GAAqB,UAAU;AAAA,iBAYpD,oBAAA,CACd,KAAA,YACC,KAAA,IAAS,kBAAkB;AAAA,iBAQd,yBAAA,CACd,KAAA,EAAO,kBAAA,GACN,kBAAkB;AAAA,iBAIL,4BAAA,CACd,QAAA,EAAU,kBAAA,cACV,KAAA,WACA,KAAA,eACC,0BAA0B;AAAA,iBAmDb,mBAAA,CAAoB,QAA2B,EAAjB,iBAAiB;AAAA,iBAc/C,mBAAA,CACd,QAAA,EAAU,iBAAiB,EAC3B,KAAA,WACA,OAAA,IAAW,KAAA"}
1
+ {"version":3,"file":"error-boundary.d.ts","names":[],"sources":["../../src/components/error-boundary.tsx"],"mappings":";;;;;KAaK,kBAAA,GAAqB,WAAW,CAAC,iBAAA;AAAA,KAEjC,kBAAA,GAAqB,UAAA;EACxB,UAAA,GAAa,iBAAiB;AAAA;AAAA,iBA+ChB,aAAA,CAAc,KAAA,EAAO,kBAAA,GAAqB,UAAU;AAAA,iBAYpD,oBAAA,CACd,KAAA,YACC,KAAA,IAAS,kBAAkB;AAAA,iBAQd,yBAAA,CACd,KAAA,EAAO,kBAAA,GACN,kBAAkB"}
@@ -1,19 +1,8 @@
1
1
  import { __ERROR_BOUNDARY__ } from "../common/vnode.js";
2
- import { isDevelopmentEnvironment } from "../common/env.js";
3
- import { logger } from "../dev/logger.js";
4
2
  import { ELEMENT_TYPE } from "../common/jsx.js";
5
3
  import { getCurrentComponentInstance } from "../runtime/component-scope.js";
6
- import "../runtime/component.js";
4
+ import "../runtime/index.js";
7
5
  //#region src/components/error-boundary.tsx
8
- function getBoundaryMessage(error) {
9
- if (error instanceof Error) return error.message || error.name || "Unknown error";
10
- if (typeof error === "string") return error;
11
- try {
12
- return JSON.stringify(error);
13
- } catch {
14
- return String(error);
15
- }
16
- }
17
6
  function ensureBoundaryState(instance, resetKey) {
18
7
  const boundaryState = instance.errorBoundaryState ?? (instance.errorBoundaryState = {
19
8
  error: null,
@@ -48,68 +37,7 @@ function ErrorBoundary(props) {
48
37
  ensureBoundaryState(instance, props.resetKey);
49
38
  return createBoundaryVNode(instance, props);
50
39
  }
51
- function resolveErrorBoundaryFallback(fallback, error, reset) {
52
- if (typeof fallback === "function") return fallback(error, reset);
53
- if (fallback !== void 0) return fallback;
54
- const message = getBoundaryMessage(error);
55
- const wrapper = document.createElement("div");
56
- wrapper.setAttribute("role", "alert");
57
- wrapper.setAttribute("data-askr-error-boundary", "true");
58
- wrapper.style.boxSizing = "border-box";
59
- wrapper.style.padding = "1rem";
60
- wrapper.style.border = "1px solid currentColor";
61
- wrapper.style.borderRadius = "0.75rem";
62
- wrapper.style.display = "grid";
63
- wrapper.style.gap = "0.75rem";
64
- wrapper.style.maxWidth = "100%";
65
- const title = document.createElement("strong");
66
- title.textContent = "Something went wrong while rendering this view.";
67
- const summary = document.createElement("p");
68
- summary.textContent = "The app recovered into a visible fallback so the error is not hidden in the console.";
69
- summary.style.margin = "0";
70
- const details = document.createElement("details");
71
- details.open = isDevelopmentEnvironment();
72
- const detailsSummary = document.createElement("summary");
73
- detailsSummary.textContent = "Error details";
74
- const pre = document.createElement("pre");
75
- pre.textContent = message;
76
- pre.style.margin = "0";
77
- pre.style.whiteSpace = "pre-wrap";
78
- pre.style.wordBreak = "break-word";
79
- const button = document.createElement("button");
80
- button.type = "button";
81
- button.textContent = "Try again";
82
- button.addEventListener("click", () => reset());
83
- details.append(detailsSummary, pre);
84
- wrapper.append(title, summary, details, button);
85
- return wrapper;
86
- }
87
- function createBoundaryReset(instance) {
88
- return () => {
89
- const boundaryState = instance.errorBoundaryState;
90
- if (!boundaryState) return;
91
- boundaryState.error = null;
92
- boundaryState.notified = false;
93
- queueMicrotask(() => {
94
- instance._enqueueRun?.();
95
- });
96
- };
97
- }
98
- function reportBoundaryError(instance, error, onError) {
99
- const boundaryState = instance.errorBoundaryState;
100
- if (boundaryState && Object.is(boundaryState.error, error) && boundaryState.notified) return;
101
- if (boundaryState) {
102
- boundaryState.error = error;
103
- boundaryState.notified = true;
104
- }
105
- try {
106
- onError?.(error);
107
- } catch (hookError) {
108
- logger.error("[Askr] ErrorBoundary onError handler threw:", hookError);
109
- }
110
- logger.error("[Askr] ErrorBoundary caught render error:", error);
111
- }
112
40
  //#endregion
113
- export { ErrorBoundary, createBoundaryReset, reportBoundaryError, resolveErrorBoundaryFallback };
41
+ export { ErrorBoundary };
114
42
 
115
43
  //# sourceMappingURL=error-boundary.js.map