@askrjs/askr 0.0.39 → 0.0.41
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.
- package/dist/bench/components/benchmark-row.d.ts.map +1 -1
- package/dist/bench/components/benchmark-row.js.map +1 -1
- package/dist/bench/components/benchmark-table.js.map +1 -1
- package/dist/benchmark.d.ts.map +1 -1
- package/dist/benchmark.js +2 -2
- package/dist/benchmark.js.map +1 -1
- package/dist/bin/askr-ssg.d.ts.map +1 -1
- package/dist/bin/askr-ssg.js.map +1 -1
- package/dist/boot/index.d.ts +9 -6
- package/dist/boot/index.d.ts.map +1 -1
- package/dist/boot/index.js +210 -75
- package/dist/boot/index.js.map +1 -1
- package/dist/common/attr-names.js +17 -0
- package/dist/common/attr-names.js.map +1 -0
- package/dist/common/component.d.ts.map +1 -1
- package/dist/common/control.d.ts.map +1 -1
- package/dist/common/control.js.map +1 -1
- package/dist/common/env.js.map +1 -1
- package/dist/common/jsx.d.ts.map +1 -1
- package/dist/common/jsx.js.map +1 -1
- package/dist/common/promise.js +8 -0
- package/dist/common/promise.js.map +1 -0
- package/dist/common/props.d.ts +286 -1
- package/dist/common/props.d.ts.map +1 -1
- package/dist/common/router-internal.js +6 -0
- package/dist/common/router-internal.js.map +1 -0
- package/dist/common/router.d.ts +45 -36
- package/dist/common/router.d.ts.map +1 -1
- package/dist/common/ssr-errors.d.ts.map +1 -1
- package/dist/common/ssr-errors.js.map +1 -1
- package/dist/common/ssr.d.ts +1 -0
- package/dist/common/ssr.d.ts.map +1 -1
- package/dist/common/ssr.js +6 -0
- package/dist/common/ssr.js.map +1 -0
- package/dist/common/vnode.d.ts +2 -1
- package/dist/common/vnode.d.ts.map +1 -1
- package/dist/common/vnode.js.map +1 -1
- package/dist/components/error-boundary.d.ts +7 -4
- package/dist/components/error-boundary.d.ts.map +1 -1
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/link.d.ts +2 -1
- package/dist/components/link.d.ts.map +1 -1
- package/dist/components/link.js +10 -1
- package/dist/components/link.js.map +1 -1
- package/dist/control/case.d.ts +4 -2
- package/dist/control/case.d.ts.map +1 -1
- package/dist/control/case.js.map +1 -1
- package/dist/control/for.d.ts +2 -1
- package/dist/control/for.d.ts.map +1 -1
- package/dist/control/for.js.map +1 -1
- package/dist/control/shared.d.ts +9 -0
- package/dist/control/shared.d.ts.map +1 -0
- package/dist/control/shared.js.map +1 -1
- package/dist/control/show.d.ts +4 -3
- package/dist/control/show.d.ts.map +1 -1
- package/dist/control/show.js.map +1 -1
- package/dist/data/index.d.ts +94 -14
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +65 -14
- package/dist/data/index.js.map +1 -1
- package/dist/dev/invariant.js.map +1 -1
- package/dist/dev/logger.js.map +1 -1
- package/dist/foundations/icon/icon.d.ts.map +1 -1
- package/dist/foundations/icon/icon.js.map +1 -1
- package/dist/foundations/icon/icon.types.d.ts.map +1 -1
- package/dist/foundations/interactions/dismissable.d.ts +9 -3
- package/dist/foundations/interactions/dismissable.d.ts.map +1 -1
- package/dist/foundations/interactions/dismissable.js.map +1 -1
- package/dist/foundations/interactions/focusable.d.ts.map +1 -1
- package/dist/foundations/interactions/focusable.js.map +1 -1
- package/dist/foundations/interactions/hoverable.d.ts.map +1 -1
- package/dist/foundations/interactions/hoverable.js.map +1 -1
- package/dist/foundations/interactions/interaction-policy.d.ts +1 -1
- package/dist/foundations/interactions/interaction-policy.d.ts.map +1 -1
- package/dist/foundations/interactions/interaction-policy.js +3 -3
- package/dist/foundations/interactions/interaction-policy.js.map +1 -1
- package/dist/foundations/interactions/pressable.d.ts.map +1 -1
- package/dist/foundations/interactions/pressable.js.map +1 -1
- package/dist/foundations/interactions/roving-focus.d.ts.map +1 -1
- package/dist/foundations/interactions/roving-focus.js +8 -8
- package/dist/foundations/interactions/roving-focus.js.map +1 -1
- package/dist/foundations/state/controllable.d.ts.map +1 -1
- package/dist/foundations/state/controllable.js.map +1 -1
- package/dist/foundations/structures/collection.d.ts.map +1 -1
- package/dist/foundations/structures/collection.js.map +1 -1
- package/dist/foundations/structures/layer.d.ts.map +1 -1
- package/dist/foundations/structures/layer.js.map +1 -1
- package/dist/foundations/structures/layout.d.ts +4 -2
- package/dist/foundations/structures/layout.d.ts.map +1 -1
- package/dist/foundations/structures/layout.js.map +1 -1
- package/dist/foundations/structures/portal.d.ts +9 -25
- package/dist/foundations/structures/portal.d.ts.map +1 -1
- package/dist/foundations/structures/portal.js +98 -17
- package/dist/foundations/structures/portal.js.map +1 -1
- package/dist/foundations/structures/presence.d.ts +4 -3
- package/dist/foundations/structures/presence.d.ts.map +1 -1
- package/dist/foundations/structures/presence.js +2 -2
- package/dist/foundations/structures/presence.js.map +1 -1
- package/dist/foundations/structures/slot.d.ts +2 -1
- package/dist/foundations/structures/slot.d.ts.map +1 -1
- package/dist/foundations/structures/slot.js.map +1 -1
- package/dist/foundations/utilities/aria.d.ts.map +1 -1
- package/dist/foundations/utilities/aria.js.map +1 -1
- package/dist/foundations/utilities/compose-handlers.d.ts.map +1 -1
- package/dist/foundations/utilities/compose-handlers.js.map +1 -1
- package/dist/foundations/utilities/compose-ref.d.ts.map +1 -1
- package/dist/foundations/utilities/compose-ref.js.map +1 -1
- package/dist/foundations/utilities/event-types.d.ts.map +1 -1
- package/dist/foundations/utilities/merge-props.d.ts.map +1 -1
- package/dist/foundations/utilities/merge-props.js.map +1 -1
- package/dist/foundations/utilities/use-id.d.ts.map +1 -1
- package/dist/foundations/utilities/use-id.js.map +1 -1
- package/dist/fx/fx.d.ts.map +1 -1
- package/dist/fx/fx.js.map +1 -1
- package/dist/fx/noop.js.map +1 -1
- package/dist/fx/timing.d.ts +5 -4
- package/dist/fx/timing.d.ts.map +1 -1
- package/dist/fx/timing.js +7 -4
- package/dist/fx/timing.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/jsx/types.d.ts +3 -3
- package/dist/jsx/types.d.ts.map +1 -1
- package/dist/jsx/utils.d.ts.map +1 -1
- package/dist/jsx/utils.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +6 -2
- package/dist/jsx-dev-runtime.d.ts.map +1 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +16 -6
- package/dist/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/renderer/children.js.map +1 -1
- package/dist/renderer/cleanup.js +40 -13
- package/dist/renderer/cleanup.js.map +1 -1
- package/dist/renderer/dom.js +163 -63
- package/dist/renderer/dom.js.map +1 -1
- package/dist/renderer/evaluate.js +9 -6
- package/dist/renderer/evaluate.js.map +1 -1
- package/dist/renderer/fastpath.js.map +1 -1
- package/dist/renderer/for-commit.js +1 -0
- package/dist/renderer/for-commit.js.map +1 -1
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/keyed.js.map +1 -1
- package/dist/renderer/reconcile.js +34 -0
- package/dist/renderer/reconcile.js.map +1 -1
- package/dist/renderer/utils.js +34 -3
- package/dist/renderer/utils.js.map +1 -1
- package/dist/router/index.d.ts +2 -2
- package/dist/router/match.js +16 -2
- package/dist/router/match.js.map +1 -1
- package/dist/router/navigate.d.ts +9 -1
- package/dist/router/navigate.d.ts.map +1 -1
- package/dist/router/navigate.js +235 -81
- package/dist/router/navigate.js.map +1 -1
- package/dist/router/policy.d.ts +7 -7
- package/dist/router/policy.d.ts.map +1 -1
- package/dist/router/policy.js +5 -7
- package/dist/router/policy.js.map +1 -1
- package/dist/router/route-context.js.map +1 -1
- package/dist/router/route.d.ts +20 -9
- package/dist/router/route.d.ts.map +1 -1
- package/dist/router/route.js +95 -29
- package/dist/router/route.js.map +1 -1
- package/dist/runtime/child-scope.d.ts.map +1 -1
- package/dist/runtime/child-scope.js +5 -1
- package/dist/runtime/child-scope.js.map +1 -1
- package/dist/runtime/component.d.ts +5 -2
- package/dist/runtime/component.d.ts.map +1 -1
- package/dist/runtime/component.js +85 -25
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/context.d.ts +5 -2
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/context.js +5 -2
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/control.d.ts.map +1 -1
- package/dist/runtime/control.js.map +1 -1
- package/dist/runtime/derive.d.ts.map +1 -1
- package/dist/runtime/derive.js +3 -1
- package/dist/runtime/derive.js.map +1 -1
- package/dist/runtime/dev-namespace.js.map +1 -1
- package/dist/runtime/effect.d.ts.map +1 -1
- package/dist/runtime/effect.js +17 -11
- package/dist/runtime/effect.js.map +1 -1
- package/dist/runtime/events.js +43 -1
- package/dist/runtime/events.js.map +1 -1
- package/dist/runtime/execution-model.js.map +1 -1
- package/dist/runtime/fastlane.js +2 -23
- package/dist/runtime/fastlane.js.map +1 -1
- package/dist/runtime/for-bench.d.ts.map +1 -1
- package/dist/runtime/for-bench.js.map +1 -1
- package/dist/runtime/for.d.ts +1 -1
- package/dist/runtime/for.d.ts.map +1 -1
- package/dist/runtime/for.js +36 -12
- package/dist/runtime/for.js.map +1 -1
- package/dist/runtime/operations.d.ts +3 -13
- package/dist/runtime/operations.d.ts.map +1 -1
- package/dist/runtime/operations.js +47 -39
- package/dist/runtime/operations.js.map +1 -1
- package/dist/runtime/perf-metrics.js.map +1 -1
- package/dist/runtime/readable.d.ts +1 -0
- package/dist/runtime/readable.d.ts.map +1 -1
- package/dist/runtime/readable.js +6 -1
- package/dist/runtime/readable.js.map +1 -1
- package/dist/runtime/resource-cell.js +13 -2
- package/dist/runtime/resource-cell.js.map +1 -1
- package/dist/runtime/scheduler.d.ts.map +1 -1
- package/dist/runtime/scheduler.js +8 -4
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/selector.d.ts.map +1 -1
- package/dist/runtime/selector.js +8 -2
- package/dist/runtime/selector.js.map +1 -1
- package/dist/runtime/snapshot-source.d.ts.map +1 -1
- package/dist/runtime/snapshot-source.js.map +1 -1
- package/dist/runtime/ssr-bridge.js.map +1 -1
- package/dist/runtime/state.d.ts +4 -3
- package/dist/runtime/state.d.ts.map +1 -1
- package/dist/runtime/state.js.map +1 -1
- package/dist/ssg/batch-render.js +4 -8
- package/dist/ssg/batch-render.js.map +1 -1
- package/dist/ssg/create-static-gen.d.ts +10 -2
- package/dist/ssg/create-static-gen.d.ts.map +1 -1
- package/dist/ssg/create-static-gen.js +5 -4
- package/dist/ssg/create-static-gen.js.map +1 -1
- package/dist/ssg/generate-metadata.js.map +1 -1
- package/dist/ssg/incremental-manifest.js.map +1 -1
- package/dist/ssg/resolve-ssg-data.js +54 -12
- package/dist/ssg/resolve-ssg-data.js.map +1 -1
- package/dist/ssg/route-utils.js.map +1 -1
- package/dist/ssg/types.d.ts +8 -7
- package/dist/ssg/types.d.ts.map +1 -1
- package/dist/ssg/write-static-files.js.map +1 -1
- package/dist/ssr/attrs.js +3 -2
- package/dist/ssr/attrs.js.map +1 -1
- package/dist/ssr/context.d.ts +1 -0
- package/dist/ssr/context.d.ts.map +1 -1
- package/dist/ssr/context.js +1 -0
- package/dist/ssr/context.js.map +1 -1
- package/dist/ssr/errors.d.ts.map +1 -1
- package/dist/ssr/escape.js.map +1 -1
- package/dist/ssr/index.d.ts +8 -11
- package/dist/ssr/index.d.ts.map +1 -1
- package/dist/ssr/index.js +55 -29
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/render-keys.js +15 -4
- package/dist/ssr/render-keys.js.map +1 -1
- package/dist/ssr/render-resolved.d.ts +20 -0
- package/dist/ssr/render-resolved.d.ts.map +1 -0
- package/dist/ssr/render-resolved.js +33 -0
- package/dist/ssr/render-resolved.js.map +1 -0
- package/dist/ssr/sink.js.map +1 -1
- package/dist/ssr/types.d.ts.map +1 -1
- package/dist/ssr/verify-hydration.js +5 -6
- package/dist/ssr/verify-hydration.js.map +1 -1
- package/package.json +13 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"benchmark-row.d.ts","names":[],"sources":["../../../src/bench/components/benchmark-row.tsx"],"mappings":";UAAiB,gBAAA;EACf,EAAA;EACA,
|
|
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;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,
|
|
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,
|
|
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"}
|
package/dist/benchmark.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"benchmark.d.ts","names":[],"sources":["../src/bench/benchmark-entry.tsx"],"mappings":";;;KAWK,OAAA,GAAU,
|
|
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,IAAwB,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.
|
|
14
|
-
buildLabel: "0.0.
|
|
13
|
+
packageVersion: "0.0.41",
|
|
14
|
+
buildLabel: "0.0.41-local"
|
|
15
15
|
};
|
|
16
16
|
function getBenchmarkMetadata() {
|
|
17
17
|
return { ...benchmarkMetadata };
|
package/dist/benchmark.js.map
CHANGED
|
@@ -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,
|
|
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,
|
|
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"}
|
package/dist/bin/askr-ssg.js.map
CHANGED
|
@@ -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":"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"}
|
package/dist/boot/index.d.ts
CHANGED
|
@@ -12,7 +12,14 @@ type IslandConfig = {
|
|
|
12
12
|
type IslandsConfig = {
|
|
13
13
|
islands: IslandConfig[];
|
|
14
14
|
};
|
|
15
|
-
type
|
|
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;
|
package/dist/boot/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/boot/index.ts"],"mappings":";;;;;
|
|
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"}
|
package/dist/boot/index.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
27
|
-
} catch (
|
|
28
|
-
|
|
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
|
-
|
|
32
|
-
} catch
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
131
|
+
const reusedExistingInstance = typeof existingCleanup === "function";
|
|
132
|
+
if (reusedExistingInstance) existingCleanup({ preserveInstance: true });
|
|
85
133
|
let instance = instancesByRoot.get(rootElement);
|
|
86
134
|
if (instance) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
307
|
-
|
|
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
|
-
|
|
320
|
-
|
|
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
|
-
|
|
434
|
+
releaseSelectiveHydrationResources();
|
|
327
435
|
}
|
|
328
436
|
});
|
|
329
|
-
if (deferredBoundaries.length === 0)
|
|
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
|
|
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
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
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
|
-
|
|
381
|
-
|
|
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
|
-
|
|
392
|
-
|
|
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
|