@askrjs/askr 0.0.39 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/dist/bench/components/benchmark-row.d.ts.map +1 -1
  2. package/dist/bench/components/benchmark-row.js.map +1 -1
  3. package/dist/bench/components/benchmark-table.js.map +1 -1
  4. package/dist/benchmark.d.ts.map +1 -1
  5. package/dist/benchmark.js +2 -2
  6. package/dist/benchmark.js.map +1 -1
  7. package/dist/bin/askr-ssg.d.ts.map +1 -1
  8. package/dist/bin/askr-ssg.js.map +1 -1
  9. package/dist/boot/index.d.ts +9 -6
  10. package/dist/boot/index.d.ts.map +1 -1
  11. package/dist/boot/index.js +210 -75
  12. package/dist/boot/index.js.map +1 -1
  13. package/dist/common/attr-names.js +17 -0
  14. package/dist/common/attr-names.js.map +1 -0
  15. package/dist/common/component.d.ts.map +1 -1
  16. package/dist/common/control.d.ts.map +1 -1
  17. package/dist/common/control.js.map +1 -1
  18. package/dist/common/env.js.map +1 -1
  19. package/dist/common/jsx.d.ts.map +1 -1
  20. package/dist/common/jsx.js.map +1 -1
  21. package/dist/common/promise.js +8 -0
  22. package/dist/common/promise.js.map +1 -0
  23. package/dist/common/props.d.ts +286 -1
  24. package/dist/common/props.d.ts.map +1 -1
  25. package/dist/common/router-internal.js +6 -0
  26. package/dist/common/router-internal.js.map +1 -0
  27. package/dist/common/router.d.ts +45 -36
  28. package/dist/common/router.d.ts.map +1 -1
  29. package/dist/common/ssr-errors.d.ts.map +1 -1
  30. package/dist/common/ssr-errors.js.map +1 -1
  31. package/dist/common/ssr.d.ts +1 -0
  32. package/dist/common/ssr.d.ts.map +1 -1
  33. package/dist/common/ssr.js +6 -0
  34. package/dist/common/ssr.js.map +1 -0
  35. package/dist/common/vnode.d.ts +2 -1
  36. package/dist/common/vnode.d.ts.map +1 -1
  37. package/dist/common/vnode.js.map +1 -1
  38. package/dist/components/error-boundary.d.ts +7 -4
  39. package/dist/components/error-boundary.d.ts.map +1 -1
  40. package/dist/components/error-boundary.js.map +1 -1
  41. package/dist/components/link.d.ts +2 -1
  42. package/dist/components/link.d.ts.map +1 -1
  43. package/dist/components/link.js +10 -1
  44. package/dist/components/link.js.map +1 -1
  45. package/dist/control/case.d.ts +4 -2
  46. package/dist/control/case.d.ts.map +1 -1
  47. package/dist/control/case.js.map +1 -1
  48. package/dist/control/for.d.ts +2 -1
  49. package/dist/control/for.d.ts.map +1 -1
  50. package/dist/control/for.js.map +1 -1
  51. package/dist/control/shared.d.ts +9 -0
  52. package/dist/control/shared.d.ts.map +1 -0
  53. package/dist/control/shared.js.map +1 -1
  54. package/dist/control/show.d.ts +4 -3
  55. package/dist/control/show.d.ts.map +1 -1
  56. package/dist/control/show.js.map +1 -1
  57. package/dist/data/index.d.ts +94 -14
  58. package/dist/data/index.d.ts.map +1 -1
  59. package/dist/data/index.js +65 -14
  60. package/dist/data/index.js.map +1 -1
  61. package/dist/dev/invariant.js.map +1 -1
  62. package/dist/dev/logger.js.map +1 -1
  63. package/dist/foundations/icon/icon.d.ts.map +1 -1
  64. package/dist/foundations/icon/icon.js.map +1 -1
  65. package/dist/foundations/icon/icon.types.d.ts.map +1 -1
  66. package/dist/foundations/interactions/dismissable.d.ts +9 -3
  67. package/dist/foundations/interactions/dismissable.d.ts.map +1 -1
  68. package/dist/foundations/interactions/dismissable.js.map +1 -1
  69. package/dist/foundations/interactions/focusable.d.ts.map +1 -1
  70. package/dist/foundations/interactions/focusable.js.map +1 -1
  71. package/dist/foundations/interactions/hoverable.d.ts.map +1 -1
  72. package/dist/foundations/interactions/hoverable.js.map +1 -1
  73. package/dist/foundations/interactions/interaction-policy.d.ts +1 -1
  74. package/dist/foundations/interactions/interaction-policy.d.ts.map +1 -1
  75. package/dist/foundations/interactions/interaction-policy.js +3 -3
  76. package/dist/foundations/interactions/interaction-policy.js.map +1 -1
  77. package/dist/foundations/interactions/pressable.d.ts.map +1 -1
  78. package/dist/foundations/interactions/pressable.js.map +1 -1
  79. package/dist/foundations/interactions/roving-focus.d.ts.map +1 -1
  80. package/dist/foundations/interactions/roving-focus.js +8 -8
  81. package/dist/foundations/interactions/roving-focus.js.map +1 -1
  82. package/dist/foundations/state/controllable.d.ts.map +1 -1
  83. package/dist/foundations/state/controllable.js.map +1 -1
  84. package/dist/foundations/structures/collection.d.ts.map +1 -1
  85. package/dist/foundations/structures/collection.js.map +1 -1
  86. package/dist/foundations/structures/layer.d.ts.map +1 -1
  87. package/dist/foundations/structures/layer.js.map +1 -1
  88. package/dist/foundations/structures/layout.d.ts +4 -2
  89. package/dist/foundations/structures/layout.d.ts.map +1 -1
  90. package/dist/foundations/structures/layout.js.map +1 -1
  91. package/dist/foundations/structures/portal.d.ts +9 -25
  92. package/dist/foundations/structures/portal.d.ts.map +1 -1
  93. package/dist/foundations/structures/portal.js +98 -17
  94. package/dist/foundations/structures/portal.js.map +1 -1
  95. package/dist/foundations/structures/presence.d.ts +4 -3
  96. package/dist/foundations/structures/presence.d.ts.map +1 -1
  97. package/dist/foundations/structures/presence.js +2 -2
  98. package/dist/foundations/structures/presence.js.map +1 -1
  99. package/dist/foundations/structures/slot.d.ts +2 -1
  100. package/dist/foundations/structures/slot.d.ts.map +1 -1
  101. package/dist/foundations/structures/slot.js.map +1 -1
  102. package/dist/foundations/utilities/aria.d.ts.map +1 -1
  103. package/dist/foundations/utilities/aria.js.map +1 -1
  104. package/dist/foundations/utilities/compose-handlers.d.ts.map +1 -1
  105. package/dist/foundations/utilities/compose-handlers.js.map +1 -1
  106. package/dist/foundations/utilities/compose-ref.d.ts.map +1 -1
  107. package/dist/foundations/utilities/compose-ref.js.map +1 -1
  108. package/dist/foundations/utilities/event-types.d.ts.map +1 -1
  109. package/dist/foundations/utilities/merge-props.js.map +1 -1
  110. package/dist/foundations/utilities/use-id.d.ts.map +1 -1
  111. package/dist/foundations/utilities/use-id.js.map +1 -1
  112. package/dist/fx/fx.d.ts.map +1 -1
  113. package/dist/fx/fx.js.map +1 -1
  114. package/dist/fx/noop.js.map +1 -1
  115. package/dist/fx/timing.d.ts +5 -4
  116. package/dist/fx/timing.d.ts.map +1 -1
  117. package/dist/fx/timing.js +7 -4
  118. package/dist/fx/timing.js.map +1 -1
  119. package/dist/index.js.map +1 -1
  120. package/dist/jsx/types.d.ts +3 -3
  121. package/dist/jsx/types.d.ts.map +1 -1
  122. package/dist/jsx/utils.d.ts.map +1 -1
  123. package/dist/jsx/utils.js.map +1 -1
  124. package/dist/jsx-dev-runtime.d.ts +6 -2
  125. package/dist/jsx-dev-runtime.d.ts.map +1 -1
  126. package/dist/jsx-dev-runtime.js.map +1 -1
  127. package/dist/jsx-runtime.d.ts +16 -6
  128. package/dist/jsx-runtime.d.ts.map +1 -1
  129. package/dist/jsx-runtime.js.map +1 -1
  130. package/dist/renderer/children.js.map +1 -1
  131. package/dist/renderer/cleanup.js +40 -13
  132. package/dist/renderer/cleanup.js.map +1 -1
  133. package/dist/renderer/dom.js +163 -63
  134. package/dist/renderer/dom.js.map +1 -1
  135. package/dist/renderer/evaluate.js +9 -6
  136. package/dist/renderer/evaluate.js.map +1 -1
  137. package/dist/renderer/fastpath.js.map +1 -1
  138. package/dist/renderer/for-commit.js +1 -0
  139. package/dist/renderer/for-commit.js.map +1 -1
  140. package/dist/renderer/index.js.map +1 -1
  141. package/dist/renderer/keyed.js.map +1 -1
  142. package/dist/renderer/reconcile.js +34 -0
  143. package/dist/renderer/reconcile.js.map +1 -1
  144. package/dist/renderer/utils.js +34 -3
  145. package/dist/renderer/utils.js.map +1 -1
  146. package/dist/router/index.d.ts +2 -2
  147. package/dist/router/match.js +16 -2
  148. package/dist/router/match.js.map +1 -1
  149. package/dist/router/navigate.d.ts +9 -1
  150. package/dist/router/navigate.d.ts.map +1 -1
  151. package/dist/router/navigate.js +235 -81
  152. package/dist/router/navigate.js.map +1 -1
  153. package/dist/router/policy.d.ts +7 -7
  154. package/dist/router/policy.d.ts.map +1 -1
  155. package/dist/router/policy.js +5 -7
  156. package/dist/router/policy.js.map +1 -1
  157. package/dist/router/route-context.js.map +1 -1
  158. package/dist/router/route.d.ts +20 -9
  159. package/dist/router/route.d.ts.map +1 -1
  160. package/dist/router/route.js +95 -29
  161. package/dist/router/route.js.map +1 -1
  162. package/dist/runtime/child-scope.d.ts.map +1 -1
  163. package/dist/runtime/child-scope.js +5 -1
  164. package/dist/runtime/child-scope.js.map +1 -1
  165. package/dist/runtime/component.d.ts +5 -2
  166. package/dist/runtime/component.d.ts.map +1 -1
  167. package/dist/runtime/component.js +85 -25
  168. package/dist/runtime/component.js.map +1 -1
  169. package/dist/runtime/context.d.ts +5 -2
  170. package/dist/runtime/context.d.ts.map +1 -1
  171. package/dist/runtime/context.js +5 -2
  172. package/dist/runtime/context.js.map +1 -1
  173. package/dist/runtime/control.d.ts.map +1 -1
  174. package/dist/runtime/control.js.map +1 -1
  175. package/dist/runtime/derive.d.ts.map +1 -1
  176. package/dist/runtime/derive.js +3 -1
  177. package/dist/runtime/derive.js.map +1 -1
  178. package/dist/runtime/dev-namespace.js.map +1 -1
  179. package/dist/runtime/effect.d.ts.map +1 -1
  180. package/dist/runtime/effect.js +17 -11
  181. package/dist/runtime/effect.js.map +1 -1
  182. package/dist/runtime/events.js +43 -1
  183. package/dist/runtime/events.js.map +1 -1
  184. package/dist/runtime/execution-model.js.map +1 -1
  185. package/dist/runtime/fastlane.js +2 -23
  186. package/dist/runtime/fastlane.js.map +1 -1
  187. package/dist/runtime/for-bench.d.ts.map +1 -1
  188. package/dist/runtime/for-bench.js.map +1 -1
  189. package/dist/runtime/for.d.ts +1 -1
  190. package/dist/runtime/for.d.ts.map +1 -1
  191. package/dist/runtime/for.js +36 -12
  192. package/dist/runtime/for.js.map +1 -1
  193. package/dist/runtime/operations.d.ts +3 -13
  194. package/dist/runtime/operations.d.ts.map +1 -1
  195. package/dist/runtime/operations.js +47 -39
  196. package/dist/runtime/operations.js.map +1 -1
  197. package/dist/runtime/perf-metrics.js.map +1 -1
  198. package/dist/runtime/readable.d.ts +1 -0
  199. package/dist/runtime/readable.d.ts.map +1 -1
  200. package/dist/runtime/readable.js +6 -1
  201. package/dist/runtime/readable.js.map +1 -1
  202. package/dist/runtime/resource-cell.js +13 -2
  203. package/dist/runtime/resource-cell.js.map +1 -1
  204. package/dist/runtime/scheduler.d.ts.map +1 -1
  205. package/dist/runtime/scheduler.js +8 -4
  206. package/dist/runtime/scheduler.js.map +1 -1
  207. package/dist/runtime/selector.d.ts.map +1 -1
  208. package/dist/runtime/selector.js +8 -2
  209. package/dist/runtime/selector.js.map +1 -1
  210. package/dist/runtime/snapshot-source.d.ts.map +1 -1
  211. package/dist/runtime/snapshot-source.js.map +1 -1
  212. package/dist/runtime/ssr-bridge.js.map +1 -1
  213. package/dist/runtime/state.d.ts +4 -3
  214. package/dist/runtime/state.d.ts.map +1 -1
  215. package/dist/runtime/state.js.map +1 -1
  216. package/dist/ssg/batch-render.js +4 -8
  217. package/dist/ssg/batch-render.js.map +1 -1
  218. package/dist/ssg/create-static-gen.d.ts +10 -2
  219. package/dist/ssg/create-static-gen.d.ts.map +1 -1
  220. package/dist/ssg/create-static-gen.js +5 -4
  221. package/dist/ssg/create-static-gen.js.map +1 -1
  222. package/dist/ssg/generate-metadata.js.map +1 -1
  223. package/dist/ssg/incremental-manifest.js.map +1 -1
  224. package/dist/ssg/resolve-ssg-data.js +54 -12
  225. package/dist/ssg/resolve-ssg-data.js.map +1 -1
  226. package/dist/ssg/route-utils.js.map +1 -1
  227. package/dist/ssg/types.d.ts +8 -7
  228. package/dist/ssg/types.d.ts.map +1 -1
  229. package/dist/ssg/write-static-files.js.map +1 -1
  230. package/dist/ssr/attrs.js +3 -2
  231. package/dist/ssr/attrs.js.map +1 -1
  232. package/dist/ssr/context.d.ts +1 -0
  233. package/dist/ssr/context.d.ts.map +1 -1
  234. package/dist/ssr/context.js +1 -0
  235. package/dist/ssr/context.js.map +1 -1
  236. package/dist/ssr/errors.d.ts.map +1 -1
  237. package/dist/ssr/escape.js.map +1 -1
  238. package/dist/ssr/index.d.ts +8 -12
  239. package/dist/ssr/index.d.ts.map +1 -1
  240. package/dist/ssr/index.js +55 -30
  241. package/dist/ssr/index.js.map +1 -1
  242. package/dist/ssr/render-keys.js +15 -4
  243. package/dist/ssr/render-keys.js.map +1 -1
  244. package/dist/ssr/render-resolved.js +33 -0
  245. package/dist/ssr/render-resolved.js.map +1 -0
  246. package/dist/ssr/sink.js.map +1 -1
  247. package/dist/ssr/types.d.ts.map +1 -1
  248. package/dist/ssr/verify-hydration.js +5 -6
  249. package/dist/ssr/verify-hydration.js.map +1 -1
  250. package/package.json +12 -4
@@ -1 +1 @@
1
- {"version":3,"file":"benchmark-row.d.ts","names":[],"sources":["../../../src/bench/components/benchmark-row.tsx"],"mappings":";UAAiB,gBAAA;EACf,EAAA;EACA,KAAA;AAAA;AAAA,UAGQ,iBAAA;EACR,IAAA,EAAM,gBAAA;EACN,UAAA,GAAa,EAAA;EACb,QAAA,GAAW,EAAA;EACX,QAAA,GAAW,EAAA;AAAA;AAAA,iBAGG,YAAA,CAAA;EACd,IAAA;EACA,UAAA;EACA,QAAA;EACA;AAAA,GACC,iBAAA,GAAiB,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"benchmark-row.d.ts","names":[],"sources":["../../../src/bench/components/benchmark-row.tsx"],"mappings":";UAAiB,gBAAA;EACf,EAAA;EACA,KAAK;AAAA;AAAA,UAGG,iBAAA;EACR,IAAA,EAAM,gBAAgB;EACtB,UAAA,GAAa,EAAA;EACb,QAAA,GAAW,EAAA;EACX,QAAA,GAAW,EAAA;AAAA;AAAA,iBAGG,YAAA,CAAA;EACd,IAAA;EACA,UAAA;EACA,QAAA;EACA;AAAA,GACC,iBAAA,GAAiB,GAAA,CAAA,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"benchmark-row.js","names":[],"sources":["../../../src/bench/components/benchmark-row.tsx"],"sourcesContent":["export interface BenchmarkRowData {\n id: number;\n label: string;\n}\n\ninterface BenchmarkRowProps {\n item: BenchmarkRowData;\n isSelected: (id: number) => boolean;\n onSelect: (id: number) => void;\n onRemove: (id: number) => void;\n}\n\nexport function BenchmarkRow({\n item,\n isSelected,\n onSelect,\n onRemove,\n}: BenchmarkRowProps) {\n return (\n <tr class={() => (isSelected(item.id) ? 'danger' : '')}>\n <td key=\"id\" class=\"col-md-1\">\n {() => item.id}\n </td>\n <td key=\"label\" class=\"col-md-4\">\n <a\n onClick={(event: MouseEvent) => {\n event.preventDefault();\n onSelect(item.id);\n }}\n >\n {() => item.label}\n </a>\n </td>\n <td key=\"remove\" class=\"col-md-1\">\n <a\n onClick={(event: MouseEvent) => {\n event.preventDefault();\n onRemove(item.id);\n }}\n >\n <span class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\" />\n </a>\n </td>\n <td key=\"spacer\" class=\"col-md-6\" />\n </tr>\n );\n}\n"],"mappings":";;;AAYA,SAAgB,aAAa,EAC3B,MACA,YACA,UACA,YACoB;CACpB,OACE,qBAAC,MAAD;EAAI,aAAc,WAAW,KAAK,GAAG,GAAG,WAAW;YAAnD;GACE,oBAAC,MAAD;IAAa,OAAM;oBACV,KAAK;IACT,EAFG,KAEH;GACL,oBAAC,MAAD;IAAgB,OAAM;cACpB,oBAAC,KAAD;KACE,UAAU,UAAsB;MAC9B,MAAM,gBAAgB;MACtB,SAAS,KAAK,GAAG;;qBAGZ,KAAK;KACV,CAAA;IACD,EATG,QASH;GACL,oBAAC,MAAD;IAAiB,OAAM;cACrB,oBAAC,KAAD;KACE,UAAU,UAAsB;MAC9B,MAAM,gBAAgB;MACtB,SAAS,KAAK,GAAG;;eAGnB,oBAAC,QAAD;MAAM,OAAM;MAA6B,eAAY;MAAS,CAAA;KAC5D,CAAA;IACD,EATG,SASH;GACL,oBAAC,MAAD,EAAiB,OAAM,YAAa,EAA5B,SAA4B;GACjC"}
1
+ {"version":3,"file":"benchmark-row.js","names":[],"sources":["../../../src/bench/components/benchmark-row.tsx"],"sourcesContent":["export interface BenchmarkRowData {\n id: number;\n label: string;\n}\n\ninterface BenchmarkRowProps {\n item: BenchmarkRowData;\n isSelected: (id: number) => boolean;\n onSelect: (id: number) => void;\n onRemove: (id: number) => void;\n}\n\nexport function BenchmarkRow({\n item,\n isSelected,\n onSelect,\n onRemove,\n}: BenchmarkRowProps) {\n return (\n <tr class={() => (isSelected(item.id) ? 'danger' : '')}>\n <td key=\"id\" class=\"col-md-1\">\n {() => item.id}\n </td>\n <td key=\"label\" class=\"col-md-4\">\n <a\n onClick={(event: MouseEvent) => {\n event.preventDefault();\n onSelect(item.id);\n }}\n >\n {() => item.label}\n </a>\n </td>\n <td key=\"remove\" class=\"col-md-1\">\n <a\n onClick={(event: MouseEvent) => {\n event.preventDefault();\n onRemove(item.id);\n }}\n >\n <span class=\"glyphicon glyphicon-remove\" aria-hidden=\"true\" />\n </a>\n </td>\n <td key=\"spacer\" class=\"col-md-6\" />\n </tr>\n );\n}\n"],"mappings":";;;AAYA,SAAgB,aAAa,EAC3B,MACA,YACA,UACA,YACoB;CACpB,OACE,qBAAC,MAAD;EAAI,aAAc,WAAW,KAAK,EAAE,IAAI,WAAW;YAAnD;GACE,oBAAC,MAAD;IAAa,OAAM;oBACV,KAAK;GACV,GAFI,IAEJ;GACJ,oBAAC,MAAD;IAAgB,OAAM;cACpB,oBAAC,KAAD;KACE,UAAU,UAAsB;MAC9B,MAAM,eAAe;MACrB,SAAS,KAAK,EAAE;KAClB;qBAEO,KAAK;IACX,CAAA;GACD,GATI,OASJ;GACJ,oBAAC,MAAD;IAAiB,OAAM;cACrB,oBAAC,KAAD;KACE,UAAU,UAAsB;MAC9B,MAAM,eAAe;MACrB,SAAS,KAAK,EAAE;KAClB;eAEA,oBAAC,QAAD;MAAM,OAAM;MAA6B,eAAY;KAAQ,CAAA;IAC5D,CAAA;GACD,GATI,QASJ;GACJ,oBAAC,MAAD,EAAiB,OAAM,WAAY,GAA3B,QAA2B;EACjC;;AAER"}
@@ -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,MAAM;GAAE,KAAK,SAAS,KAAK;cACxC,SACA,oBAAC,cAAD;IACQ;IACM;IACF;IACA;IACV,CAAA;GAEA,CAAA,EAEF,CAAA;EACF,CAAA"}
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 +1 @@
1
- {"version":3,"file":"benchmark.d.ts","names":[],"sources":["../src/bench/benchmark-entry.tsx"],"mappings":";;;KAWK,OAAA,GAAU,gBAAA;AAAA,UAEE,iBAAA;EACf,WAAA;EACA,cAAA;EACA,UAAA;AAAA;AAAA,cAYW,iBAAA,EAAmB,iBAAA;AAAA,iBAOhB,oBAAA,CAAA,GAAwB,iBAAA;AAAA,iBAIxB,cAAA,CAAe,IAAA,EAAM,OAAA,EAAS,WAAA,GAAc,OAAA;gBAmC1C,OAAA;;;;cAcjB,QAAA"}
1
+ {"version":3,"file":"benchmark.d.ts","names":[],"sources":["../src/bench/benchmark-entry.tsx"],"mappings":";;;KAWK,OAAA,GAAU,gBAAgB;AAAA,UAEd,iBAAA;EACf,WAAA;EACA,cAAA;EACA,UAAA;AAAA;AAAA,cAYW,iBAAA,EAAmB,iBAK/B;AAAA,iBAEe,oBAAA,CAAA,GAAwB,iBAAiB;AAAA,iBAIzC,cAAA,CAAe,IAAA,EAAM,OAAA,EAAS,WAAA,GAAc,OAAA;gBAmC1C,OAAA;;;;cAcjB,QAAA"}
package/dist/benchmark.js CHANGED
@@ -10,8 +10,8 @@ import { BenchmarkTable } from "./bench/components/benchmark-table.js";
10
10
  installRendererBridge();
11
11
  const benchmarkMetadata = {
12
12
  packageName: "@askrjs/askr",
13
- packageVersion: "0.0.39",
14
- buildLabel: "0.0.39-local"
13
+ packageVersion: "0.0.40",
14
+ buildLabel: "0.0.40-local"
15
15
  };
16
16
  function getBenchmarkMetadata() {
17
17
  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 { selector } from '../runtime/selector';\nimport { state, State } from '../runtime/state';\nimport { globalScheduler } from '../runtime/scheduler';\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 globalScheduler.flush();\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 globalScheduler.flush();\n },\n setSelected(id: number | null) {\n selectedState.set(id);\n globalScheduler.flush();\n },\n cleanup() {\n // nothing to do; outer test may clean the container\n },\n };\n}\n\nexport default { mountBenchmark };\n"],"mappings":";;;;;;;;;AASA,uBAAuB;AAmBvB,MAAa,oBAAuC;CAClD;CACA;CACA,YAAA;CAED;AAED,SAAgB,uBAA0C;CACxD,OAAO,EAAE,GAAG,mBAAmB;;AAGjC,SAAgB,eAAe,MAAe,aAAyB;CACrE,MAAM,mBAA8B,MAAM,QAAQ,YAAY,GAC1D,cACA,EAAE;CACN,IAAI;CACJ,IAAI;CAEJ,MAAM,YAAY;EAChB,YAAY,MAAiB,iBAAiB;EAC9C,gBAAgB,MAAqB,KAAK;EAC1C,UAAU,eAAe;EACzB,MAAM,aAAa,SAAS,cAAc;EAE1C,MAAM,UAAU,OAAe,cAAc,IAAI,GAAG;EACpD,MAAM,UAAU,OAAe;GAC7B,UAAU,KAAK,SAAS,KAAK,QAAQ,SAAS,KAAK,OAAO,GAAG,CAAC;GAC9D,cAAc,KAAK,aAAc,aAAa,KAAK,OAAO,SAAU;;EAGtE,OACE,oBAAC,OAAD;GAAK,OAAM;aACT,oBAAC,gBAAD;IACE,MAAM;IACM;IACZ,UAAU;IACV,UAAU;IACV,CAAA;GACE,CAAA;;CAIV,aAAa;EAAE;EAAM,WAAW;EAAY,CAAC;CAC7C,gBAAgB,OAAO;CAEvB,OAAO;EACL,QAAQ,MAAiB;GACvB,UAAU,IAAI,KAAK;GAGnB,gBAAgB,OAAO;;EAEzB,YAAY,IAAmB;GAC7B,cAAc,IAAI,GAAG;GACrB,gBAAgB,OAAO;;EAEzB,UAAU;EAGX;;AAGH,IAAA,0BAAe,EAAE,gBAAgB"}
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 { selector } from '../runtime/selector';\nimport { state, State } from '../runtime/state';\nimport { globalScheduler } from '../runtime/scheduler';\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 globalScheduler.flush();\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 globalScheduler.flush();\n },\n setSelected(id: number | null) {\n selectedState.set(id);\n globalScheduler.flush();\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,gBAAgB,MAAM;CAEtB,OAAO;EACL,QAAQ,MAAiB;GACvB,UAAU,IAAI,IAAI;GAGlB,gBAAgB,MAAM;EACxB;EACA,YAAY,IAAmB;GAC7B,cAAc,IAAI,EAAE;GACpB,gBAAgB,MAAM;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,iBAqExB,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":";;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 +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 } 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":";;;;;;;;;;;AAcA,MAAM,EAAE,YAAY;AACpB,MAAM,EAAE,eAAe;AAEvB,SAAS,UAAU,UAA0B;CAC3C,MAAM,aAAa,QAAQ,QAAQ,EAAE,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,KAAM,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"}
@@ -12,7 +12,14 @@ type IslandConfig = {
12
12
  type IslandsConfig = {
13
13
  islands: IslandConfig[];
14
14
  };
15
- type SPAConfig = {
15
+ type BootRouteSource = {
16
+ manifest: RouteManifest;
17
+ routes?: Route[];
18
+ } | {
19
+ manifest?: RouteManifest;
20
+ routes: Route[];
21
+ };
22
+ type SPAConfig = BootRouteSource & {
16
23
  root: Element | string;
17
24
  /**
18
25
  * Preferred: pass the route manifest built via `registerRoutes(() => { ... })`.
@@ -21,17 +28,13 @@ type SPAConfig = {
21
28
  * await createSPA({ root: '#app', manifest: getManifest() });
22
29
  * ```
23
30
  */
24
- manifest?: RouteManifest; /** Legacy: flat route array — kept for backward compatibility and test fixtures. */
25
- routes?: Route[];
26
31
  auth?: RouteAuthOptions;
27
32
  scrollRestoration?: boolean | ScrollRestorationOptions;
28
33
  cleanupStrict?: boolean;
29
34
  component?: never;
30
35
  };
31
- type HydrateSPAConfig = {
36
+ type HydrateSPAConfig = BootRouteSource & {
32
37
  root: Element | string; /** Preferred manifest input — see `SPAConfig.manifest`. */
33
- manifest?: RouteManifest; /** Legacy flat route array. */
34
- routes?: Route[];
35
38
  auth?: RouteAuthOptions;
36
39
  scrollRestoration?: boolean | ScrollRestorationOptions;
37
40
  cleanupStrict?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/boot/index.ts"],"mappings":";;;;;KAwOY,YAAA;EACV,IAAA,EAAM,OAAA;EACN,SAAA,EAAW,iBAAA;EAEX,aAAA;EAEA,MAAA;AAAA;AAAA,KAGU,aAAA;EACV,OAAA,EAAS,YAAA;AAAA;AAAA,KAGC,SAAA;EACV,IAAA,EAAM,OAAA;EARA;AAGR;;;;;AAIA;EASE,QAAA,GAAW,aAAA;EAEX,MAAA,GAAS,KAAA;EACT,IAAA,GAAO,gBAAA;EACP,iBAAA,aAA8B,wBAAA;EAC9B,aAAA;EACA,SAAA;AAAA;AAAA,KAGU,gBAAA;EACV,IAAA,EAAM,OAAA,WAlBA;EAoBN,QAAA,GAAW,aAAA,EAZA;EAcX,MAAA,GAAS,KAAA;EACT,IAAA,GAAO,gBAAA;EACP,iBAAA,aAA8B,wBAAA;EAC9B,aAAA;EACA,OAAA;IACE,YAAA;IACA,cAAA;IACA,cAAA;IACA,aAAA;IACA,aAAA;EAAA;AAAA;;;;iBAOY,YAAA,CAAa,MAAA,EAAQ,YAAA;;;;;iBA6CrB,aAAA,CAAc,MAAA,EAAQ,aAAA;;;;;;;;;;;;;;;iBA2BhB,SAAA,CAAU,MAAA,EAAQ,SAAA,GAAY,OAAA;;;;AAxEpD;iBA0YsB,UAAA,CAAW,MAAA,EAAQ,gBAAA,GAAmB,OAAA;;;;AA7V5D;iBA4cgB,UAAA,CAAW,IAAA,EAAM,OAAA;;;;iBAiBjB,MAAA,CAAO,IAAA,EAAM,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/boot/index.ts"],"mappings":";;;;;KAgXY,YAAA;EACV,IAAA,EAAM,OAAA;EACN,SAAA,EAAW,iBAAiB;EAE5B,aAAA;EAEA,MAAA;AAAA;AAAA,KAGU,aAAA;EACV,OAAA,EAAS,YAAY;AAAA;AAAA,KAGlB,eAAA;EAEC,QAAA,EAAU,aAAA;EACV,MAAA,GAAS,KAAA;AAAA;EAGT,QAAA,GAAW,aAAA;EACX,MAAA,EAAQ,KAAA;AAAA;AAAA,KAGF,SAAA,GAAY,eAAA;EACtB,IAAA,EAAM,OAAA;EAXY;;;;;;;EAmBlB,IAAA,GAAO,gBAAA;EACP,iBAAA,aAA8B,wBAAA;EAC9B,aAAA;EACA,SAAA;AAAA;AAAA,KAGU,gBAAA,GAAmB,eAAA;EAC7B,IAAA,EAAM,OAAA,WAnBF;EAqBJ,IAAA,GAAO,gBAAA;EACP,iBAAA,aAA8B,wBAAA;EAC9B,aAAA;EACA,OAAA;IACE,YAAA;IACA,cAAA;IACA,cAAA;IACA,aAAA;IACA,aAAA;EAAA;AAAA;;;;iBAkDY,YAAA,CAAa,MAAoB,EAAZ,YAAY;;;;;iBA6CjC,aAAA,CAAc,MAAqB,EAAb,aAAa;;;AA7GxC;AAGX;;;;;;;;;;;iBAqIsB,SAAA,CAAU,MAAA,EAAQ,SAAA,GAAY,OAAO;;;;;iBA4VrC,UAAA,CAAW,MAAA,EAAQ,gBAAA,GAAmB,OAAO;;;;;iBAuJnD,UAAA,CAAW,IAAsB,EAAhB,OAAO;;;AA7mBvB;iBAsoBD,MAAA,CAAO,IAAsB,EAAhB,OAAO"}
@@ -2,15 +2,18 @@ import { isDevelopmentEnvironment, isProductionEnvironment } from "../common/env
2
2
  import { logger } from "../dev/logger.js";
3
3
  import { globalScheduler } from "../runtime/scheduler.js";
4
4
  import { ELEMENT_TYPE, Fragment } from "../common/jsx.js";
5
+ import { isPromiseLike } from "../common/promise.js";
5
6
  import { cleanupComponent, createComponentInstance, mountComponent } from "../runtime/component.js";
6
- import { removeAllListeners } from "../renderer/cleanup.js";
7
+ import { removeAllListeners, teardownNodeSubtree } from "../renderer/cleanup.js";
7
8
  import { setStaticChildSlotsCacheEnabled } from "../renderer/dom.js";
8
9
  import { installRendererBridge } from "../renderer/index.js";
9
10
  import { assertExecutionModel } from "../runtime/execution-model.js";
10
- import { _applyManifest, _drainLazy, _setActiveRouteAuthOptions, _snapshotLazy, clearRoutes, lockRouteRegistration, resolveRoute, resolveRouteRequest, route, setServerLocation } from "../router/route.js";
11
+ import { _applyManifest, _drainLazy, _setActiveRouteAuthOptions, _snapshotLazy, clearRoutes, lockRouteRegistration, resolveRouteRequest, route, setServerLocation } from "../router/route.js";
11
12
  import "../jsx/index.js";
12
- import { DefaultPortal } from "../foundations/structures/portal.js";
13
- import { configureScrollRestoration, initializeNavigation, registerAppInstance } from "../router/navigate.js";
13
+ import { DefaultPortal, disposeDefaultPortalScope } from "../foundations/structures/portal.js";
14
+ import { configureScrollRestoration, initializeNavigation, registerAppInstance, unregisterAppInstance } from "../router/navigate.js";
15
+ import "../common/ssr.js";
16
+ import { startHydrationRenderPhase, stopHydrationRenderPhase } from "../ssr/render-keys.js";
14
17
  //#region src/boot/index.ts
15
18
  /**
16
19
  * App bootstrap and mount
@@ -19,23 +22,79 @@ const HAS_ROUTES_KEY = Symbol.for("__ASKR_HAS_ROUTES__");
19
22
  let componentIdCounter = 0;
20
23
  const instancesByRoot = /* @__PURE__ */ new WeakMap();
21
24
  const CLEANUP_SYMBOL = Symbol.for("__askrCleanup__");
22
- function attachCleanupForRoot(rootElement, instance) {
23
- rootElement[CLEANUP_SYMBOL] = () => {
24
- const errors = [];
25
+ const ROOT_CLEANUP_CALLBACKS_SYMBOL = Symbol.for("__askrRootCleanupCallbacks__");
26
+ function takeHydrationRenderData(rootElement) {
27
+ for (const child of Array.from(rootElement.children)) if (child instanceof HTMLScriptElement && child.getAttribute("data-askr-render-data") === "true") {
28
+ const raw = child.textContent ?? "";
29
+ child.remove();
30
+ if (!raw) return {};
25
31
  try {
26
- removeAllListeners(rootElement);
27
- } catch (e) {
28
- errors.push(e);
32
+ return JSON.parse(raw);
33
+ } catch (err) {
34
+ throw new Error("[Askr] Failed to parse embedded SSR render data during hydration.", { cause: err });
29
35
  }
36
+ }
37
+ return null;
38
+ }
39
+ function clearRootCleanupCallbacks(rootElement) {
40
+ try {
41
+ delete rootElement[ROOT_CLEANUP_CALLBACKS_SYMBOL];
42
+ } catch {
43
+ rootElement[ROOT_CLEANUP_CALLBACKS_SYMBOL]?.clear();
44
+ }
45
+ }
46
+ function registerRootCleanupCallback(rootElement, callback) {
47
+ const elementWithCleanup = rootElement;
48
+ const callbacks = elementWithCleanup[ROOT_CLEANUP_CALLBACKS_SYMBOL] ?? /* @__PURE__ */ new Set();
49
+ callbacks.add(callback);
50
+ elementWithCleanup[ROOT_CLEANUP_CALLBACKS_SYMBOL] = callbacks;
51
+ return () => {
52
+ callbacks.delete(callback);
53
+ if (callbacks.size === 0) clearRootCleanupCallbacks(rootElement);
54
+ };
55
+ }
56
+ function runRootCleanupCallbacks(rootElement, errors) {
57
+ const callbacks = rootElement[ROOT_CLEANUP_CALLBACKS_SYMBOL];
58
+ if (!callbacks || callbacks.size === 0) {
59
+ clearRootCleanupCallbacks(rootElement);
60
+ return;
61
+ }
62
+ clearRootCleanupCallbacks(rootElement);
63
+ for (const callback of callbacks) try {
64
+ callback();
65
+ } catch (e) {
66
+ errors.push(e);
67
+ }
68
+ }
69
+ function cleanupRootInstance(rootElement, instance, options) {
70
+ const errors = [];
71
+ try {
72
+ teardownNodeSubtree(rootElement);
73
+ } catch (e) {
74
+ errors.push(e);
75
+ }
76
+ try {
77
+ cleanupComponent(instance);
78
+ } catch (e) {
79
+ errors.push(e);
80
+ }
81
+ runRootCleanupCallbacks(rootElement, errors);
82
+ if (!options?.preserveInstance) {
83
+ unregisterAppInstance(instance);
84
+ instancesByRoot.delete(rootElement);
85
+ clearRootCleanupCallbacks(rootElement);
30
86
  try {
31
- cleanupComponent(instance);
32
- } catch (e) {
33
- errors.push(e);
34
- }
35
- if (errors.length > 0) {
36
- if (instance.cleanupStrict) throw new AggregateError(errors, `cleanup failed for app root`);
37
- else if (isDevelopmentEnvironment()) for (const err of errors) logger.warn("[Askr] cleanup error:", err);
38
- }
87
+ delete rootElement[CLEANUP_SYMBOL];
88
+ } catch {}
89
+ }
90
+ if (errors.length > 0) {
91
+ if (instance.cleanupStrict) throw new AggregateError(errors, `cleanup failed for app root`);
92
+ else if (isDevelopmentEnvironment()) for (const err of errors) logger.warn("[Askr] cleanup error:", err);
93
+ }
94
+ }
95
+ function attachCleanupForRoot(rootElement, instance) {
96
+ rootElement[CLEANUP_SYMBOL] = (options) => {
97
+ cleanupRootInstance(rootElement, instance, options);
39
98
  };
40
99
  try {
41
100
  const descriptor = Object.getOwnPropertyDescriptor(rootElement, "innerHTML") || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(rootElement), "innerHTML") || Object.getOwnPropertyDescriptor(Element.prototype, "innerHTML");
@@ -44,20 +103,7 @@ function attachCleanupForRoot(rootElement, instance) {
44
103
  return descriptor.get.call(this);
45
104
  } : void 0,
46
105
  set: function(value) {
47
- if (value === "" && instancesByRoot.get(this) === instance) {
48
- try {
49
- removeAllListeners(rootElement);
50
- } catch (e) {
51
- if (instance.cleanupStrict) throw e;
52
- if (isDevelopmentEnvironment()) logger.warn("[Askr] cleanup error:", e);
53
- }
54
- try {
55
- cleanupComponent(instance);
56
- } catch (e) {
57
- if (instance.cleanupStrict) throw e;
58
- if (isDevelopmentEnvironment()) logger.warn("[Askr] cleanup error:", e);
59
- }
60
- }
106
+ if (value === "" && instancesByRoot.get(this) === instance) cleanupRootInstance(rootElement, instance);
61
107
  if (descriptor.set) return descriptor.set.call(this, value);
62
108
  },
63
109
  configurable: true
@@ -67,6 +113,7 @@ function attachCleanupForRoot(rootElement, instance) {
67
113
  function mountOrUpdate(rootElement, componentFn, options) {
68
114
  const wrappedFn = (props, ctx) => {
69
115
  const out = componentFn(props, ctx);
116
+ if (isPromiseLike(out)) throw new Error("Async components are not supported. Components must return synchronously.");
70
117
  const portalVNode = {
71
118
  $$typeof: ELEMENT_TYPE,
72
119
  type: DefaultPortal,
@@ -81,14 +128,18 @@ function mountOrUpdate(rootElement, componentFn, options) {
81
128
  };
82
129
  Object.defineProperty(wrappedFn, "name", { value: componentFn.name || "Component" });
83
130
  const existingCleanup = rootElement[CLEANUP_SYMBOL];
84
- if (existingCleanup) existingCleanup();
131
+ const reusedExistingInstance = typeof existingCleanup === "function";
132
+ if (reusedExistingInstance) existingCleanup({ preserveInstance: true });
85
133
  let instance = instancesByRoot.get(rootElement);
86
134
  if (instance) {
87
- removeAllListeners(rootElement);
88
- try {
89
- cleanupComponent(instance);
90
- } catch (e) {
91
- if (isDevelopmentEnvironment()) logger.warn("[Askr] prior cleanup threw:", e);
135
+ const shouldResetHookState = instance.fn.name !== wrappedFn.name;
136
+ if (!reusedExistingInstance) {
137
+ removeAllListeners(rootElement);
138
+ try {
139
+ cleanupComponent(instance);
140
+ } catch (e) {
141
+ if (isDevelopmentEnvironment()) logger.warn("[Askr] prior cleanup threw:", e);
142
+ }
92
143
  }
93
144
  instance.fn = wrappedFn;
94
145
  instance.evaluationGeneration++;
@@ -96,14 +147,34 @@ function mountOrUpdate(rootElement, componentFn, options) {
96
147
  instance.expectedStateIndices = [];
97
148
  instance.firstRenderComplete = false;
98
149
  instance.isRoot = true;
150
+ instance.portalScope = instance;
151
+ if (shouldResetHookState) {
152
+ instance.stateValues = [];
153
+ instance.hasPendingUpdate = false;
154
+ instance.notifyUpdate = null;
155
+ instance.stateIndexCheck = -1;
156
+ instance.mountOperations = [];
157
+ instance.cleanupFns = [];
158
+ instance._currentRenderToken = void 0;
159
+ instance.lastRenderToken = 0;
160
+ instance._pendingReadSources = void 0;
161
+ instance._lastReadSources = void 0;
162
+ instance._placeholder = void 0;
163
+ instance.errorBoundaryState = void 0;
164
+ instance.devWarningsEmitted = void 0;
165
+ }
99
166
  if (options && typeof options.cleanupStrict === "boolean") instance.cleanupStrict = options.cleanupStrict;
100
167
  } else {
101
168
  instance = createComponentInstance(String(++componentIdCounter), wrappedFn, {}, rootElement);
102
169
  instancesByRoot.set(rootElement, instance);
103
170
  instance.isRoot = true;
171
+ instance.portalScope = instance;
104
172
  if (options && typeof options.cleanupStrict === "boolean") instance.cleanupStrict = options.cleanupStrict;
105
173
  }
106
174
  attachCleanupForRoot(rootElement, instance);
175
+ registerRootCleanupCallback(rootElement, () => {
176
+ disposeDefaultPortalScope(instance.portalScope ?? instance);
177
+ });
107
178
  mountComponent(instance);
108
179
  globalScheduler.flush();
109
180
  }
@@ -118,6 +189,28 @@ function bindDeniedStatus(status) {
118
189
  });
119
190
  }
120
191
  installRendererBridge();
192
+ const MAX_INITIAL_ROUTE_REDIRECTS = 20;
193
+ async function resolveInitialRoute(auth) {
194
+ let path = typeof window !== "undefined" ? window.location.pathname : "/";
195
+ let href = typeof window !== "undefined" ? `${window.location.pathname}${window.location.search}${window.location.hash}` : path;
196
+ const visited = /* @__PURE__ */ new Set();
197
+ for (let redirects = 0; redirects <= MAX_INITIAL_ROUTE_REDIRECTS; redirects++) {
198
+ if (visited.has(href)) throw new Error(`[Askr] Route redirect cycle detected at ${href}.`);
199
+ visited.add(href);
200
+ const resolved = await resolveRouteRequest(href, { auth });
201
+ if (typeof window === "undefined" || !resolved || resolved.kind !== "redirect") return {
202
+ path,
203
+ href,
204
+ resolved
205
+ };
206
+ const redirectTarget = new URL(resolved.to, window.location.href);
207
+ const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;
208
+ window.history.replaceState({ path: redirectHref }, "", redirectHref);
209
+ path = redirectTarget.pathname;
210
+ href = redirectHref;
211
+ }
212
+ throw new Error(`[Askr] Route redirect limit exceeded (${MAX_INITIAL_ROUTE_REDIRECTS}).`);
213
+ }
121
214
  /**
122
215
  * createIsland: Enhances existing DOM (no router, mounts once)
123
216
  */
@@ -174,23 +267,17 @@ async function createSPA(config) {
174
267
  _setActiveRouteAuthOptions(routeAuth);
175
268
  await _drainLazy(pendingLazyAtBoot);
176
269
  if (isProductionEnvironment()) lockRouteRegistration();
177
- let path = typeof window !== "undefined" ? window.location.pathname : "/";
178
- let href = typeof window !== "undefined" ? `${window.location.pathname}${window.location.search}${window.location.hash}` : path;
179
- let resolved = await resolveRouteRequest(href, { auth: routeAuth });
180
- while (typeof window !== "undefined" && resolved && resolved.kind === "redirect") {
181
- const redirectTarget = new URL(resolved.to, window.location.href);
182
- const redirectHref = `${redirectTarget.pathname}${redirectTarget.search}${redirectTarget.hash}`;
183
- window.history.replaceState({ path: redirectHref }, "", redirectHref);
184
- path = redirectTarget.pathname;
185
- href = redirectHref;
186
- resolved = await resolveRouteRequest(href, { auth: routeAuth });
187
- }
270
+ const { path, resolved } = await resolveInitialRoute(routeAuth);
188
271
  if (!resolved) {
189
272
  mountOrUpdate(rootElement, () => ({
190
273
  type: "div",
191
274
  children: []
192
275
  }), { cleanupStrict: config.cleanupStrict });
193
- await registerAppNavigation(rootElement, path);
276
+ await registerAppNavigation(rootElement, path, {
277
+ manifest: config.manifest,
278
+ routes: config.routes,
279
+ auth: routeAuth
280
+ });
194
281
  return;
195
282
  }
196
283
  if (resolved.kind === "redirect") {
@@ -198,14 +285,22 @@ async function createSPA(config) {
198
285
  type: "div",
199
286
  children: []
200
287
  }), { cleanupStrict: config.cleanupStrict });
201
- await registerAppNavigation(rootElement, path);
288
+ await registerAppNavigation(rootElement, path, {
289
+ manifest: config.manifest,
290
+ routes: config.routes,
291
+ auth: routeAuth
292
+ });
202
293
  return;
203
294
  }
204
295
  mountOrUpdate(rootElement, resolved.kind === "deny" ? bindDeniedStatus(resolved.status) : bindResolvedRouteHandler({
205
296
  handler: resolved.handler,
206
297
  params: resolved.params
207
298
  }), { cleanupStrict: config.cleanupStrict });
208
- await registerAppNavigation(rootElement, path);
299
+ await registerAppNavigation(rootElement, path, {
300
+ manifest: config.manifest,
301
+ routes: config.routes,
302
+ auth: routeAuth
303
+ });
209
304
  }
210
305
  /**
211
306
  * Mark elements that should be skipped during hydration
@@ -272,10 +367,10 @@ function shouldVerifyHydrationMarkup(config) {
272
367
  if (typeof explicit === "boolean") return explicit;
273
368
  return !isProductionEnvironment();
274
369
  }
275
- async function registerAppNavigation(rootElement, path) {
370
+ async function registerAppNavigation(rootElement, path, source) {
276
371
  const instance = instancesByRoot.get(rootElement);
277
372
  if (!instance) throw new Error("Internal error: app instance missing");
278
- registerAppInstance(instance, path);
373
+ registerAppInstance(instance, path, source);
279
374
  initializeNavigation();
280
375
  }
281
376
  /**
@@ -286,6 +381,7 @@ async function applySelectiveHydration(rootElement, resolved, path, cleanupStric
286
381
  const hasBelowFoldDeferral = !!hydrateOptions.deferBelowFold;
287
382
  const hasSelectiveBoundaries = hasPermanentSkips || hasBelowFoldDeferral;
288
383
  let staticChildSlotsCacheSuspended = false;
384
+ let releaseSelectiveHydrationResources = () => {};
289
385
  const restoreStaticChildSlotsCache = () => {
290
386
  if (!staticChildSlotsCacheSuspended) return;
291
387
  setStaticChildSlotsCacheEnabled(true);
@@ -298,15 +394,22 @@ async function applySelectiveHydration(rootElement, resolved, path, cleanupStric
298
394
  staticChildSlotsCacheSuspended = true;
299
395
  const foldY = hydrateOptions.foldThreshold ?? window.innerHeight;
300
396
  deferredBoundaries = collectDeferredBelowFoldBoundaries(rootElement, foldY);
301
- const handleScroll = () => {
397
+ let selectiveHydrationResourcesReleased = false;
398
+ let unregisterRootCleanupCallback = () => {};
399
+ function handleScroll() {
302
400
  const { activated, remaining } = activateVisibleDeferredBoundaries(deferredBoundaries, foldY);
303
401
  if (!activated) return;
304
402
  flushHydrationActivation(rootElement);
305
- if (remaining === 0) {
306
- restoreStaticChildSlotsCache();
307
- window.removeEventListener("scroll", handleScroll);
308
- }
403
+ if (remaining === 0) releaseSelectiveHydrationResources();
404
+ }
405
+ releaseSelectiveHydrationResources = () => {
406
+ if (selectiveHydrationResourcesReleased) return;
407
+ selectiveHydrationResourcesReleased = true;
408
+ unregisterRootCleanupCallback();
409
+ window.removeEventListener("scroll", handleScroll);
410
+ restoreStaticChildSlotsCache();
309
411
  };
412
+ unregisterRootCleanupCallback = registerRootCleanupCallback(rootElement, releaseSelectiveHydrationResources);
310
413
  window.addEventListener("scroll", handleScroll, { passive: true });
311
414
  }
312
415
  if (hydrateOptions.deferUntilIdle && !hasSelectiveBoundaries) {
@@ -316,17 +419,22 @@ async function applySelectiveHydration(rootElement, resolved, path, cleanupStric
316
419
  await registerAppNavigation(rootElement, path);
317
420
  return;
318
421
  }
319
- mountOrUpdate(rootElement, (() => resolved.handler(resolved.params)), { cleanupStrict });
320
- await registerAppNavigation(rootElement, path);
422
+ try {
423
+ mountOrUpdate(rootElement, (() => resolved.handler(resolved.params)), { cleanupStrict });
424
+ await registerAppNavigation(rootElement, path);
425
+ } catch (error) {
426
+ releaseSelectiveHydrationResources();
427
+ throw error;
428
+ }
321
429
  if (hydrateOptions.deferUntilIdle && deferredBoundaries.length > 0) await queueIdleWork(() => {
322
430
  try {
323
431
  const { activated } = activateVisibleDeferredBoundaries(deferredBoundaries, Number.POSITIVE_INFINITY);
324
432
  if (activated) flushHydrationActivation(rootElement);
325
433
  } finally {
326
- restoreStaticChildSlotsCache();
434
+ releaseSelectiveHydrationResources();
327
435
  }
328
436
  });
329
- if (deferredBoundaries.length === 0) restoreStaticChildSlotsCache();
437
+ if (deferredBoundaries.length === 0) releaseSelectiveHydrationResources();
330
438
  }
331
439
  /**
332
440
  * hydrateSPA: Hydrate server-rendered HTML.
@@ -340,6 +448,7 @@ async function hydrateSPA(config) {
340
448
  if (!hasManifest && !hasRoutes) throw new Error("hydrateSPA requires a route manifest or route table. Pass `manifest: getManifest()` or `routes: getRoutes()`. If you are enhancing existing HTML, use createIsland instead.");
341
449
  const rootElement = typeof config.root === "string" ? document.getElementById(config.root) : config.root;
342
450
  if (!rootElement) throw new Error(`Root element not found: ${config.root}`);
451
+ const hydrationRenderData = takeHydrationRenderData(rootElement);
343
452
  const pendingLazyAtHydrationBoot = _snapshotLazy();
344
453
  configureScrollRestoration(config.scrollRestoration);
345
454
  clearRoutes();
@@ -347,12 +456,18 @@ async function hydrateSPA(config) {
347
456
  else for (const r of config.routes) route(r.path, r.handler);
348
457
  _setActiveRouteAuthOptions(config.auth ?? config.manifest?.auth);
349
458
  await _drainLazy(pendingLazyAtHydrationBoot);
350
- const path = typeof window !== "undefined" ? window.location.pathname : "/";
351
- const currentUrl = typeof window !== "undefined" ? `${window.location.pathname}${window.location.search}${window.location.hash}` : path;
459
+ const { path, href: currentUrl, resolved } = await resolveInitialRoute(config.auth ?? config.manifest?.auth);
352
460
  setServerLocation(currentUrl);
353
461
  if (isProductionEnvironment()) lockRouteRegistration();
354
- const resolved = resolveRoute(path);
355
462
  if (!resolved) throw new Error(`hydrateSPA: no route found for current path (${path}).`);
463
+ if (resolved.kind === "redirect") throw new Error(`hydrateSPA: unresolved redirect for current path (${path}).`);
464
+ const hydrationResolved = resolved.kind === "deny" ? {
465
+ handler: bindDeniedStatus(resolved.status),
466
+ params: {}
467
+ } : {
468
+ handler: resolved.handler,
469
+ params: resolved.params
470
+ };
356
471
  if (shouldVerifyHydrationMarkup(config)) {
357
472
  const legacyRouteTable = hasManifest ? config.manifest.records.map((r) => ({
358
473
  path: r.path,
@@ -363,22 +478,35 @@ async function hydrateSPA(config) {
363
478
  if (!verifyHydrationSyncForUrl({
364
479
  root: rootElement,
365
480
  url: currentUrl,
366
- routes: legacyRouteTable
481
+ routes: legacyRouteTable,
482
+ resolved: hydrationResolved,
483
+ options: { data: hydrationRenderData ?? void 0 }
367
484
  })) throw new Error("[Askr] Hydration mismatch detected. Server HTML does not match expected server-render output.");
368
485
  }
369
486
  const hydrateOptions = config.hydrate;
370
487
  if (hydrateOptions) {
371
488
  if (hydrateOptions.deferUntilIdle || hydrateOptions.deferBelowFold) {
372
- await applySelectiveHydration(rootElement, {
373
- handler: resolved.handler,
374
- params: resolved.params
375
- }, path, config.cleanupStrict, hydrateOptions);
489
+ if (hydrationRenderData) startHydrationRenderPhase(hydrationRenderData);
490
+ try {
491
+ await applySelectiveHydration(rootElement, hydrationResolved, path, config.cleanupStrict, hydrateOptions);
492
+ } finally {
493
+ if (hydrationRenderData) stopHydrationRenderPhase();
494
+ }
376
495
  return;
377
496
  }
378
497
  if (hydrateOptions.skipSelectors?.length) markSkippedElements(rootElement, hydrateOptions.skipSelectors);
379
498
  }
380
- mountOrUpdate(rootElement, bindResolvedRouteHandler(resolved), { cleanupStrict: config.cleanupStrict });
381
- await registerAppNavigation(rootElement, path);
499
+ if (hydrationRenderData) startHydrationRenderPhase(hydrationRenderData);
500
+ try {
501
+ mountOrUpdate(rootElement, resolved.kind === "deny" ? bindDeniedStatus(resolved.status) : bindResolvedRouteHandler(hydrationResolved), { cleanupStrict: config.cleanupStrict });
502
+ } finally {
503
+ if (hydrationRenderData) stopHydrationRenderPhase();
504
+ }
505
+ await registerAppNavigation(rootElement, path, {
506
+ manifest: config.manifest,
507
+ routes: config.routes,
508
+ auth: config.auth ?? config.manifest?.auth
509
+ });
382
510
  }
383
511
  /**
384
512
  * Cleanup an app mounted on a root element (element or id).
@@ -388,8 +516,15 @@ function cleanupApp(root) {
388
516
  const rootElement = typeof root === "string" ? document.getElementById(root) : root;
389
517
  if (!rootElement) return;
390
518
  const cleanupFn = rootElement[CLEANUP_SYMBOL];
391
- if (typeof cleanupFn === "function") cleanupFn();
392
- instancesByRoot.delete(rootElement);
519
+ try {
520
+ if (typeof cleanupFn === "function") cleanupFn();
521
+ } finally {
522
+ instancesByRoot.delete(rootElement);
523
+ clearRootCleanupCallbacks(rootElement);
524
+ try {
525
+ delete rootElement[CLEANUP_SYMBOL];
526
+ } catch {}
527
+ }
393
528
  }
394
529
  /**
395
530
  * Check whether an app is mounted on the given root