@askrjs/askr 0.0.48 → 0.0.49
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/benchmark.js +6 -6
- package/dist/benchmark.js.map +1 -1
- package/dist/boot/hydration.js +140 -0
- package/dist/boot/hydration.js.map +1 -0
- package/dist/boot/index.d.ts +3 -56
- package/dist/boot/index.d.ts.map +1 -1
- package/dist/boot/index.js +62 -410
- package/dist/boot/index.js.map +1 -1
- package/dist/boot/root-lifecycle.d.ts +15 -0
- package/dist/boot/root-lifecycle.d.ts.map +1 -0
- package/dist/boot/root-lifecycle.js +205 -0
- package/dist/boot/root-lifecycle.js.map +1 -0
- package/dist/boot/route-startup.js +45 -0
- package/dist/boot/route-startup.js.map +1 -0
- package/dist/boot/types.d.ts +62 -0
- package/dist/boot/types.d.ts.map +1 -0
- package/dist/common/component.d.ts +3 -1
- package/dist/common/component.d.ts.map +1 -1
- package/dist/common/jsx.d.ts +1 -1
- package/dist/common/jsx.d.ts.map +1 -1
- package/dist/common/jsx.js.map +1 -1
- package/dist/common/props.d.ts +1 -1
- package/dist/common/render-context.js +55 -0
- package/dist/common/render-context.js.map +1 -0
- package/dist/common/router.d.ts +5 -1
- package/dist/common/router.d.ts.map +1 -1
- package/dist/common/ssr.d.ts +1 -1
- package/dist/common/ssr.js.map +1 -1
- package/dist/common/vnode.d.ts +5 -4
- package/dist/common/vnode.d.ts.map +1 -1
- package/dist/common/vnode.js.map +1 -1
- package/dist/components/error-boundary.d.ts +1 -1
- package/dist/components/error-boundary.js +2 -1
- package/dist/components/error-boundary.js.map +1 -1
- package/dist/components/link.js.map +1 -1
- package/dist/control/for.js +2 -1
- package/dist/control/for.js.map +1 -1
- package/dist/data/data-runtime.d.ts +28 -0
- package/dist/data/data-runtime.d.ts.map +1 -0
- package/dist/data/data-runtime.js +114 -0
- package/dist/data/data-runtime.js.map +1 -0
- package/dist/data/index.d.ts +6 -142
- package/dist/data/index.js +5 -539
- package/dist/data/invalidation.d.ts +9 -0
- package/dist/data/invalidation.d.ts.map +1 -0
- package/dist/data/invalidation.js +27 -0
- package/dist/data/invalidation.js.map +1 -0
- package/dist/data/mutation-cell.d.ts +28 -0
- package/dist/data/mutation-cell.d.ts.map +1 -0
- package/dist/data/mutation-cell.js +132 -0
- package/dist/data/mutation-cell.js.map +1 -0
- package/dist/data/query-cell.d.ts +46 -0
- package/dist/data/query-cell.d.ts.map +1 -0
- package/dist/data/query-cell.js +290 -0
- package/dist/data/query-cell.js.map +1 -0
- package/dist/data/query-key.js +42 -0
- package/dist/data/query-key.js.map +1 -0
- package/dist/data/shared.js +20 -0
- package/dist/data/shared.js.map +1 -0
- package/dist/data/types.d.ts +161 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/foundations/icon/icon.d.ts.map +1 -1
- package/dist/foundations/icon/icon.js.map +1 -1
- package/dist/foundations/structures/portal.d.ts +1 -1
- package/dist/foundations/structures/portal.d.ts.map +1 -1
- package/dist/foundations/structures/portal.js +2 -1
- package/dist/foundations/structures/portal.js.map +1 -1
- package/dist/fx/fx.d.ts +1 -1
- package/dist/fx/fx.js +5 -4
- package/dist/fx/fx.js.map +1 -1
- package/dist/fx/timing.d.ts.map +1 -1
- package/dist/fx/timing.js +10 -6
- package/dist/fx/timing.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/jsx/index.d.ts +2 -1
- package/dist/jsx/index.js +3 -2
- package/dist/jsx/types.d.ts +2 -0
- package/dist/jsx/types.js +2 -1
- package/dist/jsx-runtime2.d.ts +2 -1
- package/dist/jsx-runtime2.js +3 -2
- package/dist/renderer/attributes.js +231 -0
- package/dist/renderer/attributes.js.map +1 -0
- package/dist/renderer/boundaries.js +266 -0
- package/dist/renderer/boundaries.js.map +1 -0
- package/dist/renderer/child-shape.js +85 -0
- package/dist/renderer/child-shape.js.map +1 -0
- package/dist/renderer/children.js +3 -2
- package/dist/renderer/children.js.map +1 -1
- package/dist/renderer/cleanup.js +2 -1
- package/dist/renderer/cleanup.js.map +1 -1
- package/dist/renderer/component-host-cleanup.js +68 -0
- package/dist/renderer/component-host-cleanup.js.map +1 -0
- package/dist/renderer/component-host-instances.js +65 -0
- package/dist/renderer/component-host-instances.js.map +1 -0
- package/dist/renderer/component-host.js +247 -0
- package/dist/renderer/component-host.js.map +1 -0
- package/dist/renderer/dom-host.js +13 -0
- package/dist/renderer/dom-host.js.map +1 -0
- package/dist/renderer/dom-internal.js +185 -0
- package/dist/renderer/dom-internal.js.map +1 -0
- package/dist/renderer/dom.js +9 -2356
- package/dist/renderer/element-children.js +279 -0
- package/dist/renderer/element-children.js.map +1 -0
- package/dist/renderer/env.js +2 -1
- package/dist/renderer/error-boundary-dom.js +29 -0
- package/dist/renderer/error-boundary-dom.js.map +1 -0
- package/dist/renderer/evaluate-dom-range.js +85 -0
- package/dist/renderer/evaluate-dom-range.js.map +1 -0
- package/dist/renderer/evaluate-reconcile.js +281 -0
- package/dist/renderer/evaluate-reconcile.js.map +1 -0
- package/dist/renderer/evaluate.js +13 -399
- package/dist/renderer/evaluate.js.map +1 -1
- package/dist/renderer/fastpath.js +6 -5
- package/dist/renderer/fastpath.js.map +1 -1
- package/dist/renderer/for-commit-dom-map.js +83 -0
- package/dist/renderer/for-commit-dom-map.js.map +1 -0
- package/dist/renderer/for-commit-removal.js +36 -0
- package/dist/renderer/for-commit-removal.js.map +1 -0
- package/dist/renderer/for-commit-reorder.js +89 -0
- package/dist/renderer/for-commit-reorder.js.map +1 -0
- package/dist/renderer/for-commit.js +6 -188
- package/dist/renderer/for-commit.js.map +1 -1
- package/dist/renderer/index.js +28 -16
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/keyed-children.js +32 -0
- package/dist/renderer/keyed-children.js.map +1 -0
- package/dist/renderer/keyed.js +2 -15
- package/dist/renderer/keyed.js.map +1 -1
- package/dist/renderer/namespaces.js +23 -0
- package/dist/renderer/namespaces.js.map +1 -0
- package/dist/renderer/prop-bindings.js +280 -0
- package/dist/renderer/prop-bindings.js.map +1 -0
- package/dist/renderer/reactive-child-dom.js +133 -0
- package/dist/renderer/reactive-child-dom.js.map +1 -0
- package/dist/renderer/reactive-child-sources.js +184 -0
- package/dist/renderer/reactive-child-sources.js.map +1 -0
- package/dist/renderer/reactive-children.js +294 -0
- package/dist/renderer/reactive-children.js.map +1 -0
- package/dist/renderer/reconcile-commit.js +38 -0
- package/dist/renderer/reconcile-commit.js.map +1 -0
- package/dist/renderer/reconcile-fastpaths.js +106 -0
- package/dist/renderer/reconcile-fastpaths.js.map +1 -0
- package/dist/renderer/reconcile-resolution.js +187 -0
- package/dist/renderer/reconcile-resolution.js.map +1 -0
- package/dist/renderer/reconcile.js +9 -371
- package/dist/renderer/reconcile.js.map +1 -1
- package/dist/renderer/retained-element-rollback.js +276 -0
- package/dist/renderer/retained-element-rollback.js.map +1 -0
- package/dist/renderer/stable-patch.js +82 -0
- package/dist/renderer/stable-patch.js.map +1 -0
- package/dist/renderer/static-reuse.js +96 -0
- package/dist/renderer/static-reuse.js.map +1 -0
- package/dist/renderer/types.js +2 -1
- package/dist/renderer/utils.js +4 -4
- package/dist/renderer/utils.js.map +1 -1
- package/dist/resources/index.d.ts +3 -2
- package/dist/resources/index.js +5 -2
- package/dist/router/access.js +36 -0
- package/dist/router/access.js.map +1 -0
- package/dist/router/activity.d.ts +10 -0
- package/dist/router/activity.d.ts.map +1 -0
- package/dist/router/activity.js +89 -0
- package/dist/router/activity.js.map +1 -0
- package/dist/router/authoring.d.ts +22 -0
- package/dist/router/authoring.d.ts.map +1 -0
- package/dist/router/authoring.js +198 -0
- package/dist/router/authoring.js.map +1 -0
- package/dist/router/index.d.ts +12 -4
- package/dist/router/index.js +10 -3
- package/dist/router/internal-types.d.ts +31 -0
- package/dist/router/internal-types.d.ts.map +1 -0
- package/dist/router/lazy.d.ts +19 -0
- package/dist/router/lazy.d.ts.map +1 -0
- package/dist/router/lazy.js +52 -0
- package/dist/router/lazy.js.map +1 -0
- package/dist/router/manifest.d.ts +10 -0
- package/dist/router/manifest.d.ts.map +1 -0
- package/dist/router/manifest.js +49 -0
- package/dist/router/manifest.js.map +1 -0
- package/dist/router/navigate.d.ts +4 -51
- package/dist/router/navigate.d.ts.map +1 -1
- package/dist/router/navigate.js +16 -459
- package/dist/router/navigate.js.map +1 -1
- package/dist/router/navigation-registry.d.ts +32 -0
- package/dist/router/navigation-registry.d.ts.map +1 -0
- package/dist/router/navigation-registry.js +105 -0
- package/dist/router/navigation-registry.js.map +1 -0
- package/dist/router/navigation-scroll.d.ts +14 -0
- package/dist/router/navigation-scroll.d.ts.map +1 -0
- package/dist/router/navigation-scroll.js +93 -0
- package/dist/router/navigation-scroll.js.map +1 -0
- package/dist/router/navigation-targets.d.ts +31 -0
- package/dist/router/navigation-targets.d.ts.map +1 -0
- package/dist/router/navigation-targets.js +253 -0
- package/dist/router/navigation-targets.js.map +1 -0
- package/dist/router/policy.d.ts +7 -1
- package/dist/router/policy.d.ts.map +1 -1
- package/dist/router/policy.js +27 -9
- package/dist/router/policy.js.map +1 -1
- package/dist/router/rendering.d.ts +10 -0
- package/dist/router/rendering.d.ts.map +1 -0
- package/dist/router/rendering.js +45 -0
- package/dist/router/rendering.js.map +1 -0
- package/dist/router/resolution.d.ts +17 -0
- package/dist/router/resolution.d.ts.map +1 -0
- package/dist/router/resolution.js +253 -0
- package/dist/router/resolution.js.map +1 -0
- package/dist/router/route-query.d.ts +17 -0
- package/dist/router/route-query.d.ts.map +1 -0
- package/dist/router/route-query.js +47 -0
- package/dist/router/route-query.js.map +1 -0
- package/dist/router/route.d.ts +8 -149
- package/dist/router/route.js +8 -854
- package/dist/router/store.d.ts +50 -0
- package/dist/router/store.d.ts.map +1 -0
- package/dist/router/store.js +171 -0
- package/dist/router/store.js.map +1 -0
- package/dist/runtime/access.js +45 -0
- package/dist/runtime/access.js.map +1 -0
- package/dist/runtime/child-scope.d.ts +1 -1
- package/dist/runtime/child-scope.js +4 -1
- package/dist/runtime/child-scope.js.map +1 -1
- package/dist/runtime/component-cleanup.d.ts +16 -0
- package/dist/runtime/component-cleanup.d.ts.map +1 -0
- package/dist/runtime/component-cleanup.js +70 -0
- package/dist/runtime/component-cleanup.js.map +1 -0
- package/dist/runtime/component-commit.js +165 -0
- package/dist/runtime/component-commit.js.map +1 -0
- package/dist/runtime/component-contracts.js +5 -0
- package/dist/runtime/component-facade.d.ts +5 -0
- package/dist/runtime/component-facade.js +4 -0
- package/dist/runtime/component-internal.d.ts +100 -0
- package/dist/runtime/component-internal.d.ts.map +1 -0
- package/dist/runtime/component-internal.js +219 -0
- package/dist/runtime/component-internal.js.map +1 -0
- package/dist/runtime/component-lifecycle.d.ts +49 -0
- package/dist/runtime/component-lifecycle.d.ts.map +1 -0
- package/dist/runtime/component-lifecycle.js +176 -0
- package/dist/runtime/component-lifecycle.js.map +1 -0
- package/dist/runtime/component-scope.d.ts +55 -0
- package/dist/runtime/component-scope.d.ts.map +1 -0
- package/dist/runtime/component-scope.js +154 -0
- package/dist/runtime/component-scope.js.map +1 -0
- package/dist/runtime/component.d.ts +4 -152
- package/dist/runtime/component.js +4 -692
- package/dist/runtime/context.d.ts +1 -1
- package/dist/runtime/context.js +6 -4
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/control.d.ts +3 -3
- package/dist/runtime/control.js +2 -1
- package/dist/runtime/control.js.map +1 -1
- package/dist/runtime/derive.d.ts.map +1 -1
- package/dist/runtime/derive.js +6 -5
- package/dist/runtime/derive.js.map +1 -1
- package/dist/runtime/effect.d.ts +1 -1
- package/dist/runtime/effect.d.ts.map +1 -1
- package/dist/runtime/effect.js +2 -2
- package/dist/runtime/effect.js.map +1 -1
- package/dist/runtime/events.js +3 -3
- package/dist/runtime/events.js.map +1 -1
- package/dist/runtime/fastlane.js +13 -27
- package/dist/runtime/fastlane.js.map +1 -1
- package/dist/runtime/for-bench.d.ts +1 -1
- package/dist/runtime/for-bench.js +1 -4
- package/dist/runtime/for-bench.js.map +1 -1
- package/dist/runtime/for-internal.d.ts +43 -0
- package/dist/runtime/for-internal.d.ts.map +1 -0
- package/dist/runtime/for-internal.js +98 -0
- package/dist/runtime/for-internal.js.map +1 -0
- package/dist/runtime/for-reconcile.d.ts +8 -0
- package/dist/runtime/for-reconcile.d.ts.map +1 -0
- package/dist/runtime/for-reconcile.js +389 -0
- package/dist/runtime/for-reconcile.js.map +1 -0
- package/dist/runtime/for-scopes.d.ts +26 -0
- package/dist/runtime/for-scopes.d.ts.map +1 -0
- package/dist/runtime/for-scopes.js +160 -0
- package/dist/runtime/for-scopes.js.map +1 -0
- package/dist/runtime/for-signals.d.ts +30 -0
- package/dist/runtime/for-signals.d.ts.map +1 -0
- package/dist/runtime/for-signals.js +139 -0
- package/dist/runtime/for-signals.js.map +1 -0
- package/dist/runtime/for.d.ts +4 -66
- package/dist/runtime/for.js +5 -773
- package/dist/runtime/lifecycle-operations.d.ts +31 -0
- package/dist/runtime/lifecycle-operations.d.ts.map +1 -0
- package/dist/runtime/lifecycle-operations.js +195 -0
- package/dist/runtime/lifecycle-operations.js.map +1 -0
- package/dist/runtime/operations.d.ts +3 -40
- package/dist/runtime/operations.js +2 -357
- package/dist/runtime/readable.d.ts +2 -3
- package/dist/runtime/readable.d.ts.map +1 -1
- package/dist/runtime/readable.js +6 -5
- package/dist/runtime/readable.js.map +1 -1
- package/dist/runtime/resource-cell.js +2 -2
- package/dist/runtime/resource-cell.js.map +1 -1
- package/dist/runtime/resource-operation.d.ts +13 -0
- package/dist/runtime/resource-operation.d.ts.map +1 -0
- package/dist/runtime/resource-operation.js +170 -0
- package/dist/runtime/resource-operation.js.map +1 -0
- package/dist/runtime/runtime.d.ts +42 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +59 -0
- package/dist/runtime/runtime.js.map +1 -0
- package/dist/runtime/scheduler.d.ts +5 -1
- package/dist/runtime/scheduler.d.ts.map +1 -1
- package/dist/runtime/scheduler.js +17 -17
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/selector.js +4 -3
- package/dist/runtime/selector.js.map +1 -1
- package/dist/runtime/snapshot-source.d.ts +1 -1
- package/dist/runtime/snapshot-source.js +1 -1
- package/dist/runtime/state.js +2 -1
- package/dist/runtime/state.js.map +1 -1
- package/dist/ssg/batch-render.js +2 -1
- package/dist/ssg/batch-render.js.map +1 -1
- package/dist/ssg/create-static-gen.d.ts +9 -3
- package/dist/ssg/create-static-gen.d.ts.map +1 -1
- package/dist/ssg/create-static-gen.js +12 -99
- package/dist/ssg/create-static-gen.js.map +1 -1
- package/dist/ssg/generation-plan.js +70 -0
- package/dist/ssg/generation-plan.js.map +1 -0
- package/dist/ssg/incremental-manifest.js +1 -1
- package/dist/ssg/static-routes.js +101 -0
- package/dist/ssg/static-routes.js.map +1 -0
- package/dist/ssg/types.d.ts +15 -7
- package/dist/ssg/types.d.ts.map +1 -1
- package/dist/ssr/boundaries.js +113 -0
- package/dist/ssr/boundaries.js.map +1 -0
- package/dist/ssr/component-runtime.js +111 -0
- package/dist/ssr/component-runtime.js.map +1 -0
- package/dist/ssr/context.d.ts +3 -1
- package/dist/ssr/context.d.ts.map +1 -1
- package/dist/ssr/context.js +9 -2
- package/dist/ssr/context.js.map +1 -1
- package/dist/ssr/errors.d.ts +2 -0
- package/dist/ssr/errors.js +11 -1
- package/dist/ssr/errors.js.map +1 -1
- package/dist/ssr/escape.js +3 -3
- package/dist/ssr/escape.js.map +1 -1
- package/dist/ssr/hydration-data.js +10 -0
- package/dist/ssr/hydration-data.js.map +1 -0
- package/dist/ssr/hydration-verify.d.ts +12 -0
- package/dist/ssr/hydration-verify.d.ts.map +1 -0
- package/dist/ssr/hydration-verify.js +144 -0
- package/dist/ssr/hydration-verify.js.map +1 -0
- package/dist/ssr/index-internal.d.ts +15 -0
- package/dist/ssr/index-internal.d.ts.map +1 -0
- package/dist/ssr/index-internal.js +19 -0
- package/dist/ssr/index-internal.js.map +1 -0
- package/dist/ssr/index.d.ts +5 -57
- package/dist/ssr/index.js +3 -738
- package/dist/ssr/render-keys.js +9 -32
- package/dist/ssr/render-keys.js.map +1 -1
- package/dist/ssr/render-resolved.d.ts +1 -1
- package/dist/ssr/render-resolved.d.ts.map +1 -1
- package/dist/ssr/render-resolved.js +4 -2
- package/dist/ssr/render-resolved.js.map +1 -1
- package/dist/ssr/render-sync.d.ts +21 -0
- package/dist/ssr/render-sync.d.ts.map +1 -0
- package/dist/ssr/render-sync.js +275 -0
- package/dist/ssr/render-sync.js.map +1 -0
- package/dist/ssr/route-policy-resolution.js +77 -0
- package/dist/ssr/route-policy-resolution.js.map +1 -0
- package/dist/ssr/route-render.d.ts +77 -0
- package/dist/ssr/route-render.d.ts.map +1 -0
- package/dist/ssr/route-render.js +119 -0
- package/dist/ssr/route-render.js.map +1 -0
- package/dist/ssr/sink.d.ts +26 -0
- package/dist/ssr/sink.d.ts.map +1 -0
- package/dist/ssr/types.d.ts +1 -0
- package/dist/ssr/types.d.ts.map +1 -1
- package/dist/ssr/verify-hydration.js.map +1 -1
- package/dist/testing/index.d.ts +1 -2
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +4 -3
- package/dist/data/index.d.ts.map +0 -1
- package/dist/data/index.js.map +0 -1
- package/dist/renderer/dom.js.map +0 -1
- package/dist/router/route.d.ts.map +0 -1
- package/dist/router/route.js.map +0 -1
- package/dist/runtime/component.d.ts.map +0 -1
- package/dist/runtime/component.js.map +0 -1
- package/dist/runtime/for.d.ts.map +0 -1
- package/dist/runtime/for.js.map +0 -1
- package/dist/runtime/operations.d.ts.map +0 -1
- package/dist/runtime/operations.js.map +0 -1
- package/dist/runtime/ssr-bridge.js +0 -24
- package/dist/runtime/ssr-bridge.js.map +0 -1
- package/dist/ssr/index.d.ts.map +0 -1
- package/dist/ssr/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-static-gen.js","names":[],"sources":["../../src/ssg/create-static-gen.ts"],"sourcesContent":["/**\n * Static Site Generation API\n *\n * Main orchestrator for batch rendering, file I/O, and metadata generation\n */\n\nimport type {\n RouteConfig,\n RouteRenderReason,\n RouteRenderResult,\n SSGGenerateOptions,\n SSGMode,\n SSGOptions,\n SSGResult,\n} from './types';\nimport {\n expandRoutes,\n resolveSsgRouteData,\n resolveSsgData,\n validateRoutes,\n} from './resolve-ssg-data';\nimport { batchRenderRoutes } from './batch-render';\nimport { writeStaticFiles } from './write-static-files';\nimport {\n generateSSGResult,\n resultToMetadata,\n writeMetadata,\n} from './generate-metadata';\nimport {\n getExistingOutputFileSize,\n outputFileExists,\n readIncrementalManifest,\n type IncrementalManifest,\n type IncrementalManifestRouteEntry,\n writeIncrementalManifest,\n hashHtml,\n SSG_MANIFEST_SCHEMA_VERSION,\n} from './incremental-manifest';\nimport {\n resolveRouteDescriptor,\n type ResolvedRouteDescriptor,\n} from './route-utils';\nimport { addPerfDuration, incrementPerfMetric } from '../runtime/perf-metrics';\n\ntype AnyRouteConfig = RouteConfig<string>;\n\ntype StrictRouteConfig<TRoute extends AnyRouteConfig> = Omit<\n TRoute,\n 'params' | 'entries'\n> & {\n params?: RouteConfig<TRoute['path']>['params'];\n entries?: RouteConfig<TRoute['path']>['entries'];\n};\n\ntype StrictRouteConfigs<TRoutes extends readonly AnyRouteConfig[]> = {\n [TIndex in keyof TRoutes]: TRoutes[TIndex] extends AnyRouteConfig\n ? StrictRouteConfig<TRoutes[TIndex]>\n : never;\n};\n\ninterface SelectedRoute {\n descriptor: ResolvedRouteDescriptor;\n reason: RouteRenderReason;\n previous: IncrementalManifestRouteEntry | null;\n}\n\nfunction getRuntimeOnlyDiagnostic(\n descriptor: ResolvedRouteDescriptor\n): string | null {\n const { route } = descriptor;\n\n if (route.auth === true) {\n return `Skipped prerender for \"${descriptor.path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (route.role) {\n return `Skipped prerender for \"${descriptor.path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (route.permission) {\n return `Skipped prerender for \"${descriptor.path}\": permission-gated routes are runtime-only by default.`;\n }\n\n if (route.policies && route.policies.length > 0) {\n return `Skipped prerender for \"${descriptor.path}\": routes with custom policies are runtime-only by default.`;\n }\n\n return null;\n}\n\nfunction resolveParallelism(requested: number | 'auto' | undefined): number {\n if (requested !== 'auto') {\n return Math.max(1, requested ?? 1);\n }\n\n const maybeNavigator = globalThis as typeof globalThis & {\n navigator?: { hardwareConcurrency?: number };\n process?: { env?: Record<string, string | undefined> };\n };\n\n const envWorkers = Number(\n maybeNavigator.process?.env?.ASKR_SSG_WORKERS ??\n maybeNavigator.process?.env?.NUMBER_OF_PROCESSORS ??\n maybeNavigator.process?.env?.UV_THREADPOOL_SIZE\n );\n if (Number.isFinite(envWorkers) && envWorkers > 0) {\n return Math.max(1, Math.trunc(envWorkers));\n }\n\n if (typeof maybeNavigator.navigator?.hardwareConcurrency === 'number') {\n return Math.max(1, maybeNavigator.navigator.hardwareConcurrency);\n }\n\n return 1;\n}\n\n/**\n * Create a Static Site Generator\n *\n * Usage:\n * ```ts\n * const ssg = createStaticGen({\n * routes: [\n * { path: '/', component: HomePage },\n * { path: '/about', component: AboutPage },\n * ],\n * outputDir: './dist',\n * dataOverrides: {\n * '/api/posts': { posts: [...] }\n * }\n * });\n *\n * const result = await ssg.generate();\n * console.log(`Generated ${result.successful}/${result.totalRoutes} routes`);\n * ```\n */\nexport function createStaticGen<\n const TRoutes extends readonly AnyRouteConfig[],\n>(\n options: Omit<SSGOptions<TRoutes>, 'routes'> & {\n routes: TRoutes & StrictRouteConfigs<TRoutes>;\n }\n) {\n let result: SSGResult | null = null;\n const seed = options.seed ?? 12345;\n const resolvedParallelism = resolveParallelism(options.parallelism);\n const resolvedConcurrency = Math.max(\n 1,\n options.concurrency ?? resolvedParallelism\n );\n\n if (!Array.isArray(options.routes) || options.routes.length === 0) {\n throw new Error('routes array is required');\n }\n\n if (!options.outputDir || options.outputDir.trim().length === 0) {\n throw new Error('outputDir is required');\n }\n\n return {\n /**\n * Generate static HTML for all routes\n * Writes to outputDir with metadata.json\n * Returns detailed results\n */\n async generate(\n generateOptions: SSGGenerateOptions = {}\n ): Promise<SSGResult> {\n const routes = await expandRoutes(options.routes as RouteConfig[]);\n validateRoutes(routes);\n\n const changedKeys = dedupeStrings(generateOptions.changedKeys);\n const changedRoutes = dedupeStrings(generateOptions.changedRoutes);\n const requestedMode = generateOptions.mode ?? 'full';\n const previousManifest =\n !generateOptions.forceFull && requestedMode === 'incremental'\n ? readIncrementalManifest(options.outputDir, seed)\n : null;\n const effectiveMode: SSGMode =\n generateOptions.forceFull ||\n requestedMode !== 'incremental' ||\n previousManifest === null\n ? 'full'\n : 'incremental';\n\n // Resolve data\n const dataMap = resolveSsgData(routes, {\n dataOverrides: options.dataOverrides,\n });\n\n const descriptors = routes.map(resolveRouteDescriptor);\n const routeResultsById = new Map<string, RouteRenderResult>();\n const eligibleDescriptors: ResolvedRouteDescriptor[] = [];\n\n for (const descriptor of descriptors) {\n const diagnostic = getRuntimeOnlyDiagnostic(descriptor);\n if (diagnostic) {\n routeResultsById.set(descriptor.routeId, {\n path: descriptor.path,\n filePath: descriptor.filePath,\n html: '',\n fileSize: 0,\n renderDuration: 0,\n resourceCount: 0,\n status: 'skipped',\n reason: 'runtime-only',\n written: false,\n error: diagnostic,\n });\n continue;\n }\n\n eligibleDescriptors.push(descriptor);\n }\n\n const previousEntries = new Map(\n (previousManifest?.routes ?? []).map((entry) => [entry.routeId, entry])\n );\n const currentRouteIds = new Set(\n eligibleDescriptors.map((descriptor) => descriptor.routeId)\n );\n\n const selected: SelectedRoute[] = [];\n const routesToRender: SelectedRoute[] = [];\n for (let index = 0; index < eligibleDescriptors.length; index += 1) {\n const descriptor = eligibleDescriptors[index];\n const entry = selectRouteForGeneration(\n descriptor,\n previousEntries.get(descriptor.routeId) ?? null,\n effectiveMode,\n changedKeys,\n changedRoutes\n );\n selected.push(entry);\n if (entry.reason !== 'unchanged') {\n routesToRender.push(entry);\n }\n }\n const renderStartTime = performance.now();\n incrementPerfMetric('ssgWorkerCount', resolvedParallelism);\n const renderedResults =\n routesToRender.length > 0\n ? await batchRenderRoutes(getRoutesToRender(routesToRender), {\n seed,\n dataMap,\n concurrency: resolvedConcurrency,\n document: options.document,\n })\n : [];\n addPerfDuration('ssgRenderTimeMs', performance.now() - renderStartTime);\n const renderedByRouteId = new Map<string, RouteRenderResult>();\n for (let index = 0; index < renderedResults.length; index += 1) {\n renderedByRouteId.set(\n routesToRender[index].descriptor.routeId,\n renderedResults[index]\n );\n }\n\n let cacheHits = 0;\n const nextManifestRoutes: IncrementalManifestRouteEntry[] = [];\n\n for (const entry of selected) {\n const { descriptor, previous, reason } = entry;\n const resolvedData = resolveSsgRouteData(\n dataMap,\n descriptor.route.path,\n descriptor.path\n );\n const baseData = resolvedData.hasData ? resolvedData.data : undefined;\n const resourceCount =\n resolvedData.hasData && baseData ? Object.keys(baseData).length : 0;\n\n if (reason === 'unchanged') {\n routeResultsById.set(descriptor.routeId, {\n path: descriptor.path,\n filePath: descriptor.filePath,\n html: '',\n fileSize:\n previous?.htmlHash !== null && previous !== null\n ? getExistingOutputFileSize(\n options.outputDir,\n descriptor.filePath\n )\n : 0,\n renderDuration: 0,\n resourceCount,\n status: 'skipped',\n reason: 'unchanged',\n written: false,\n });\n\n if (previous) {\n nextManifestRoutes.push({\n ...previous,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n });\n }\n continue;\n }\n\n const rendered = renderedByRouteId.get(descriptor.routeId);\n if (!rendered) {\n throw new Error(\n `Missing rendered result for route \"${descriptor.path}\"`\n );\n }\n\n const nextResult: RouteRenderResult = {\n ...rendered,\n path: descriptor.path,\n filePath: descriptor.filePath,\n resourceCount,\n reason,\n written: false,\n };\n\n if (nextResult.status === 'success') {\n const htmlDigest = hashHtml(nextResult.html);\n const shouldWrite =\n effectiveMode === 'full' ||\n !previous ||\n previous.htmlHash !== htmlDigest ||\n !outputFileExists(options.outputDir, descriptor.filePath);\n\n nextResult.written = shouldWrite;\n if (!shouldWrite) {\n cacheHits += 1;\n }\n\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: htmlDigest,\n lastStatus: 'success',\n });\n } else {\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: previous?.htmlHash ?? null,\n lastStatus: 'error',\n });\n }\n\n routeResultsById.set(descriptor.routeId, nextResult);\n }\n\n const removedResults = collectRemovedRouteResults(\n previousManifest,\n currentRouteIds\n );\n const routeResults: RouteRenderResult[] = [];\n for (let index = 0; index < descriptors.length; index += 1) {\n const routeResult = routeResultsById.get(descriptors[index].routeId);\n if (routeResult) {\n routeResults.push(routeResult);\n }\n }\n routeResults.push(...removedResults);\n\n // Write HTML files to disk and remove stale output\n const writeStartTime = performance.now();\n await writeStaticFiles(routeResults, options.outputDir, {\n concurrency: resolvedConcurrency,\n });\n addPerfDuration('ssgWriteTimeMs', performance.now() - writeStartTime);\n\n // Generate result object\n result = generateSSGResult(routeResults, {\n mode: effectiveMode,\n cacheHits,\n invalidatedKeys: changedKeys,\n invalidatedRoutes: changedRoutes,\n });\n\n // Write metadata\n const metadata = resultToMetadata(result);\n await writeMetadata(metadata, options.outputDir);\n\n await writeIncrementalManifest(\n {\n schemaVersion: SSG_MANIFEST_SCHEMA_VERSION,\n seed,\n mode: effectiveMode,\n routes: nextManifestRoutes,\n },\n options.outputDir\n );\n\n return result;\n },\n\n /**\n * Get effective config in a serializable form for diagnostics.\n */\n getConfig() {\n return {\n routeCount: options.routes.length,\n outputDir: options.outputDir,\n seed,\n concurrency: resolvedConcurrency,\n parallelism: resolvedParallelism,\n hasDataOverrides: !!options.dataOverrides,\n };\n },\n\n /**\n * Get the last generation result\n * Returns null if generate() hasn't been called\n */\n getResult(): SSGResult | null {\n return result;\n },\n };\n}\n\nfunction dedupeStrings(values?: string[]): string[] {\n return values ? Array.from(new Set(values)) : [];\n}\n\nfunction getRoutesToRender(selected: SelectedRoute[]): RouteConfig[] {\n const routes: RouteConfig[] = [];\n for (let index = 0; index < selected.length; index += 1) {\n routes.push(selected[index].descriptor.route);\n }\n return routes;\n}\n\nfunction selectRouteForGeneration(\n descriptor: ResolvedRouteDescriptor,\n previous: IncrementalManifestRouteEntry | null,\n mode: SSGMode,\n changedKeys: string[],\n changedRoutes: string[]\n): SelectedRoute {\n if (mode === 'full') {\n return { descriptor, reason: 'full', previous };\n }\n\n if (!previous) {\n return { descriptor, reason: 'new-route', previous };\n }\n\n if (previous.lastStatus === 'error' || previous.htmlHash === null) {\n return { descriptor, reason: 'new-route', previous };\n }\n\n if (descriptor.invalidationKeys.length === 0) {\n return { descriptor, reason: 'no-keys', previous };\n }\n\n if (changedRoutes.includes(descriptor.path)) {\n return { descriptor, reason: 'changed-route', previous };\n }\n\n if (descriptor.invalidationKeys.some((key) => changedKeys.includes(key))) {\n return { descriptor, reason: 'changed-key', previous };\n }\n\n return { descriptor, reason: 'unchanged', previous };\n}\n\nfunction collectRemovedRouteResults(\n manifest: IncrementalManifest | null,\n currentRouteIds: Set<string>\n): RouteRenderResult[] {\n if (!manifest) {\n return [];\n }\n\n const results: RouteRenderResult[] = [];\n for (let index = 0; index < manifest.routes.length; index += 1) {\n const entry = manifest.routes[index];\n if (currentRouteIds.has(entry.routeId)) {\n continue;\n }\n results.push({\n path: entry.path,\n filePath: entry.filePath,\n html: '',\n fileSize: 0,\n renderDuration: 0,\n resourceCount: 0,\n status: 'removed' as const,\n reason: 'deleted' as const,\n written: false,\n });\n }\n\n return results;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create-static-gen.js","names":[],"sources":["../../src/ssg/create-static-gen.ts"],"sourcesContent":["/**\n * Static Site Generation API\n *\n * Main orchestrator for batch rendering, file I/O, and metadata generation\n */\n\nimport type {\n RouteConfig,\n RouteRenderResult,\n SSGGenerateOptions,\n SSGMode,\n SSGOptions,\n SSGResult,\n} from './types';\nimport type { RouteRegistry } from '../common/router';\nimport {\n resolveSsgRouteData,\n resolveSsgData,\n validateRoutes,\n} from './resolve-ssg-data';\nimport { batchRenderRoutes } from './batch-render';\nimport { writeStaticFiles } from './write-static-files';\nimport {\n generateSSGResult,\n resultToMetadata,\n writeMetadata,\n} from './generate-metadata';\nimport {\n getExistingOutputFileSize,\n outputFileExists,\n readIncrementalManifest,\n type IncrementalManifestRouteEntry,\n writeIncrementalManifest,\n hashHtml,\n SSG_MANIFEST_SCHEMA_VERSION,\n} from './incremental-manifest';\nimport { resolveRouteDescriptor } from './route-utils';\nimport {\n collectRemovedRouteResults,\n dedupeStrings,\n getRoutesToRender,\n selectRouteForGeneration,\n type SelectedRoute,\n} from './generation-plan';\nimport { normalizeStaticRoutes, splitStaticRoutes } from './static-routes';\nimport { addPerfDuration, incrementPerfMetric } from '../runtime/perf-metrics';\n\ntype AnyRouteConfig = RouteConfig<string>;\n\ntype StrictRouteConfig<TRoute extends AnyRouteConfig> = Omit<\n TRoute,\n 'params' | 'entries'\n> & {\n params?: RouteConfig<TRoute['path']>['params'];\n entries?: RouteConfig<TRoute['path']>['entries'];\n};\n\ntype StrictRouteConfigs<TRoutes extends readonly AnyRouteConfig[]> = {\n [TIndex in keyof TRoutes]: TRoutes[TIndex] extends AnyRouteConfig\n ? StrictRouteConfig<TRoutes[TIndex]>\n : never;\n};\n\ntype StaticGenRouteSource<TRoutes extends readonly AnyRouteConfig[]> =\n | {\n routes: TRoutes & StrictRouteConfigs<TRoutes>;\n registry?: never;\n }\n | {\n registry: RouteRegistry;\n routes?: never;\n };\n\nfunction resolveParallelism(requested: number | 'auto' | undefined): number {\n if (requested !== 'auto') {\n return Math.max(1, requested ?? 1);\n }\n\n const maybeNavigator = globalThis as typeof globalThis & {\n navigator?: { hardwareConcurrency?: number };\n process?: { env?: Record<string, string | undefined> };\n };\n\n const envWorkers = Number(\n maybeNavigator.process?.env?.ASKR_SSG_WORKERS ??\n maybeNavigator.process?.env?.NUMBER_OF_PROCESSORS ??\n maybeNavigator.process?.env?.UV_THREADPOOL_SIZE\n );\n if (Number.isFinite(envWorkers) && envWorkers > 0) {\n return Math.max(1, Math.trunc(envWorkers));\n }\n\n if (typeof maybeNavigator.navigator?.hardwareConcurrency === 'number') {\n return Math.max(1, maybeNavigator.navigator.hardwareConcurrency);\n }\n\n return 1;\n}\n\n/**\n * Create a Static Site Generator\n *\n * Usage:\n * ```ts\n * const ssg = createStaticGen({\n * routes: [\n * { path: '/', component: HomePage },\n * { path: '/about', component: AboutPage },\n * ],\n * outputDir: './dist',\n * dataOverrides: {\n * '/api/posts': { posts: [...] }\n * }\n * });\n *\n * const result = await ssg.generate();\n * console.log(`Generated ${result.successful}/${result.totalRoutes} routes`);\n * ```\n */\nexport function createStaticGen<\n const TRoutes extends readonly AnyRouteConfig[],\n>(\n options: Omit<SSGOptions<TRoutes>, 'routes' | 'registry'> &\n StaticGenRouteSource<TRoutes>\n) {\n let result: SSGResult | null = null;\n const configuredRoutes = normalizeStaticRoutes(options);\n const seed = options.seed ?? 12345;\n const resolvedParallelism = resolveParallelism(options.parallelism);\n const resolvedConcurrency = Math.max(\n 1,\n options.concurrency ?? resolvedParallelism\n );\n\n if (configuredRoutes.length === 0) {\n throw new Error('routes array or route registry is required');\n }\n\n if (!options.outputDir || options.outputDir.trim().length === 0) {\n throw new Error('outputDir is required');\n }\n\n return {\n /**\n * Generate static HTML for all routes\n * Writes to outputDir with metadata.json\n * Returns detailed results\n */\n async generate(\n generateOptions: SSGGenerateOptions = {}\n ): Promise<SSGResult> {\n const splitRoutes = await splitStaticRoutes(configuredRoutes);\n const routes = splitRoutes.routes;\n validateRoutes(routes);\n\n const changedKeys = dedupeStrings(generateOptions.changedKeys);\n const changedRoutes = dedupeStrings(generateOptions.changedRoutes);\n const requestedMode = generateOptions.mode ?? 'full';\n const previousManifest =\n !generateOptions.forceFull && requestedMode === 'incremental'\n ? readIncrementalManifest(options.outputDir, seed)\n : null;\n const effectiveMode: SSGMode =\n generateOptions.forceFull ||\n requestedMode !== 'incremental' ||\n previousManifest === null\n ? 'full'\n : 'incremental';\n\n // Resolve data\n const dataMap = resolveSsgData(routes, {\n dataOverrides: options.dataOverrides,\n });\n\n const descriptors = routes.map(resolveRouteDescriptor);\n const routeResultsById = new Map<string, RouteRenderResult>();\n for (const runtimeRoute of splitRoutes.runtimeOnly) {\n routeResultsById.set(runtimeRoute.routeId, runtimeRoute.result);\n }\n const eligibleDescriptors = descriptors;\n\n const previousEntries = new Map(\n (previousManifest?.routes ?? []).map((entry) => [entry.routeId, entry])\n );\n const currentRouteIds = new Set(\n eligibleDescriptors.map((descriptor) => descriptor.routeId)\n );\n\n const selected: SelectedRoute[] = [];\n const routesToRender: SelectedRoute[] = [];\n for (let index = 0; index < eligibleDescriptors.length; index += 1) {\n const descriptor = eligibleDescriptors[index];\n const entry = selectRouteForGeneration(\n descriptor,\n previousEntries.get(descriptor.routeId) ?? null,\n effectiveMode,\n changedKeys,\n changedRoutes\n );\n selected.push(entry);\n if (entry.reason !== 'unchanged') {\n routesToRender.push(entry);\n }\n }\n const renderStartTime = performance.now();\n incrementPerfMetric('ssgWorkerCount', resolvedParallelism);\n const renderedResults =\n routesToRender.length > 0\n ? await batchRenderRoutes(getRoutesToRender(routesToRender), {\n seed,\n dataMap,\n concurrency: resolvedConcurrency,\n document: options.document,\n })\n : [];\n addPerfDuration('ssgRenderTimeMs', performance.now() - renderStartTime);\n const renderedByRouteId = new Map<string, RouteRenderResult>();\n for (let index = 0; index < renderedResults.length; index += 1) {\n renderedByRouteId.set(\n routesToRender[index].descriptor.routeId,\n renderedResults[index]\n );\n }\n\n let cacheHits = 0;\n const nextManifestRoutes: IncrementalManifestRouteEntry[] = [];\n\n for (const entry of selected) {\n const { descriptor, previous, reason } = entry;\n const resolvedData = resolveSsgRouteData(\n dataMap,\n descriptor.route.path,\n descriptor.path\n );\n const baseData = resolvedData.hasData ? resolvedData.data : undefined;\n const resourceCount =\n resolvedData.hasData && baseData ? Object.keys(baseData).length : 0;\n\n if (reason === 'unchanged') {\n routeResultsById.set(descriptor.routeId, {\n path: descriptor.path,\n filePath: descriptor.filePath,\n html: '',\n fileSize:\n previous?.htmlHash !== null && previous !== null\n ? getExistingOutputFileSize(\n options.outputDir,\n descriptor.filePath\n )\n : 0,\n renderDuration: 0,\n resourceCount,\n status: 'skipped',\n reason: 'unchanged',\n written: false,\n });\n\n if (previous) {\n nextManifestRoutes.push({\n ...previous,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n });\n }\n continue;\n }\n\n const rendered = renderedByRouteId.get(descriptor.routeId);\n if (!rendered) {\n throw new Error(\n `Missing rendered result for route \"${descriptor.path}\"`\n );\n }\n\n const nextResult: RouteRenderResult = {\n ...rendered,\n path: descriptor.path,\n filePath: descriptor.filePath,\n resourceCount,\n reason,\n written: false,\n };\n\n if (nextResult.status === 'success') {\n const htmlDigest = hashHtml(nextResult.html);\n const shouldWrite =\n effectiveMode === 'full' ||\n !previous ||\n previous.htmlHash !== htmlDigest ||\n !outputFileExists(options.outputDir, descriptor.filePath);\n\n nextResult.written = shouldWrite;\n if (!shouldWrite) {\n cacheHits += 1;\n }\n\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: htmlDigest,\n lastStatus: 'success',\n });\n } else {\n nextManifestRoutes.push({\n routeId: descriptor.routeId,\n path: descriptor.path,\n filePath: descriptor.filePath,\n invalidationKeys: descriptor.invalidationKeys.slice(),\n htmlHash: previous?.htmlHash ?? null,\n lastStatus: 'error',\n });\n }\n\n routeResultsById.set(descriptor.routeId, nextResult);\n }\n\n const removedResults = collectRemovedRouteResults(\n previousManifest,\n currentRouteIds\n );\n const routeResults: RouteRenderResult[] = [];\n for (const routeId of splitRoutes.outputRouteIds) {\n const routeResult = routeResultsById.get(routeId);\n if (routeResult) {\n routeResults.push(routeResult);\n }\n }\n routeResults.push(...removedResults);\n\n // Write HTML files to disk and remove stale output\n const writeStartTime = performance.now();\n await writeStaticFiles(routeResults, options.outputDir, {\n concurrency: resolvedConcurrency,\n });\n addPerfDuration('ssgWriteTimeMs', performance.now() - writeStartTime);\n\n // Generate result object\n result = generateSSGResult(routeResults, {\n mode: effectiveMode,\n cacheHits,\n invalidatedKeys: changedKeys,\n invalidatedRoutes: changedRoutes,\n });\n\n // Write metadata\n const metadata = resultToMetadata(result);\n await writeMetadata(metadata, options.outputDir);\n\n await writeIncrementalManifest(\n {\n schemaVersion: SSG_MANIFEST_SCHEMA_VERSION,\n seed,\n mode: effectiveMode,\n routes: nextManifestRoutes,\n },\n options.outputDir\n );\n\n return result;\n },\n\n /**\n * Get effective config in a serializable form for diagnostics.\n */\n getConfig() {\n return {\n routeCount: configuredRoutes.length,\n outputDir: options.outputDir,\n seed,\n concurrency: resolvedConcurrency,\n parallelism: resolvedParallelism,\n hasDataOverrides: !!options.dataOverrides,\n };\n },\n\n /**\n * Get the last generation result\n * Returns null if generate() hasn't been called\n */\n getResult(): SSGResult | null {\n return result;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/ssg/generation-plan.ts
|
|
2
|
+
function dedupeStrings(values) {
|
|
3
|
+
return values ? Array.from(new Set(values)) : [];
|
|
4
|
+
}
|
|
5
|
+
function getRoutesToRender(selected) {
|
|
6
|
+
const routes = [];
|
|
7
|
+
for (let index = 0; index < selected.length; index += 1) routes.push(selected[index].descriptor.route);
|
|
8
|
+
return routes;
|
|
9
|
+
}
|
|
10
|
+
function selectRouteForGeneration(descriptor, previous, mode, changedKeys, changedRoutes) {
|
|
11
|
+
if (mode === "full") return {
|
|
12
|
+
descriptor,
|
|
13
|
+
reason: "full",
|
|
14
|
+
previous
|
|
15
|
+
};
|
|
16
|
+
if (!previous) return {
|
|
17
|
+
descriptor,
|
|
18
|
+
reason: "new-route",
|
|
19
|
+
previous
|
|
20
|
+
};
|
|
21
|
+
if (previous.lastStatus === "error" || previous.htmlHash === null) return {
|
|
22
|
+
descriptor,
|
|
23
|
+
reason: "new-route",
|
|
24
|
+
previous
|
|
25
|
+
};
|
|
26
|
+
if (descriptor.invalidationKeys.length === 0) return {
|
|
27
|
+
descriptor,
|
|
28
|
+
reason: "no-keys",
|
|
29
|
+
previous
|
|
30
|
+
};
|
|
31
|
+
if (changedRoutes.includes(descriptor.path)) return {
|
|
32
|
+
descriptor,
|
|
33
|
+
reason: "changed-route",
|
|
34
|
+
previous
|
|
35
|
+
};
|
|
36
|
+
if (descriptor.invalidationKeys.some((key) => changedKeys.includes(key))) return {
|
|
37
|
+
descriptor,
|
|
38
|
+
reason: "changed-key",
|
|
39
|
+
previous
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
descriptor,
|
|
43
|
+
reason: "unchanged",
|
|
44
|
+
previous
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function collectRemovedRouteResults(manifest, currentRouteIds) {
|
|
48
|
+
if (!manifest) return [];
|
|
49
|
+
const results = [];
|
|
50
|
+
for (let index = 0; index < manifest.routes.length; index += 1) {
|
|
51
|
+
const entry = manifest.routes[index];
|
|
52
|
+
if (currentRouteIds.has(entry.routeId)) continue;
|
|
53
|
+
results.push({
|
|
54
|
+
path: entry.path,
|
|
55
|
+
filePath: entry.filePath,
|
|
56
|
+
html: "",
|
|
57
|
+
fileSize: 0,
|
|
58
|
+
renderDuration: 0,
|
|
59
|
+
resourceCount: 0,
|
|
60
|
+
status: "removed",
|
|
61
|
+
reason: "deleted",
|
|
62
|
+
written: false
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return results;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { collectRemovedRouteResults, dedupeStrings, getRoutesToRender, selectRouteForGeneration };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=generation-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation-plan.js","names":[],"sources":["../../src/ssg/generation-plan.ts"],"sourcesContent":["/**\n * SSG incremental generation planning.\n */\n\nimport type {\n RouteConfig,\n RouteRenderReason,\n RouteRenderResult,\n SSGMode,\n} from './types';\nimport type {\n IncrementalManifest,\n IncrementalManifestRouteEntry,\n} from './incremental-manifest';\nimport type { ResolvedRouteDescriptor } from './route-utils';\n\nexport interface SelectedRoute {\n descriptor: ResolvedRouteDescriptor;\n reason: RouteRenderReason;\n previous: IncrementalManifestRouteEntry | null;\n}\n\nexport function dedupeStrings(values?: string[]): string[] {\n return values ? Array.from(new Set(values)) : [];\n}\n\nexport function getRoutesToRender(selected: SelectedRoute[]): RouteConfig[] {\n const routes: RouteConfig[] = [];\n for (let index = 0; index < selected.length; index += 1) {\n routes.push(selected[index].descriptor.route);\n }\n return routes;\n}\n\nexport function selectRouteForGeneration(\n descriptor: ResolvedRouteDescriptor,\n previous: IncrementalManifestRouteEntry | null,\n mode: SSGMode,\n changedKeys: string[],\n changedRoutes: string[]\n): SelectedRoute {\n if (mode === 'full') {\n return { descriptor, reason: 'full', previous };\n }\n\n if (!previous) {\n return { descriptor, reason: 'new-route', previous };\n }\n\n if (previous.lastStatus === 'error' || previous.htmlHash === null) {\n return { descriptor, reason: 'new-route', previous };\n }\n\n if (descriptor.invalidationKeys.length === 0) {\n return { descriptor, reason: 'no-keys', previous };\n }\n\n if (changedRoutes.includes(descriptor.path)) {\n return { descriptor, reason: 'changed-route', previous };\n }\n\n if (descriptor.invalidationKeys.some((key) => changedKeys.includes(key))) {\n return { descriptor, reason: 'changed-key', previous };\n }\n\n return { descriptor, reason: 'unchanged', previous };\n}\n\nexport function collectRemovedRouteResults(\n manifest: IncrementalManifest | null,\n currentRouteIds: Set<string>\n): RouteRenderResult[] {\n if (!manifest) {\n return [];\n }\n\n const results: RouteRenderResult[] = [];\n for (let index = 0; index < manifest.routes.length; index += 1) {\n const entry = manifest.routes[index];\n if (currentRouteIds.has(entry.routeId)) {\n continue;\n }\n results.push({\n path: entry.path,\n filePath: entry.filePath,\n html: '',\n fileSize: 0,\n renderDuration: 0,\n resourceCount: 0,\n status: 'removed' as const,\n reason: 'deleted' as const,\n written: false,\n });\n }\n\n return results;\n}\n"],"mappings":";AAsBA,SAAgB,cAAc,QAA6B;CACzD,OAAO,SAAS,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC;AACjD;AAEA,SAAgB,kBAAkB,UAA0C;CAC1E,MAAM,SAAwB,CAAC;CAC/B,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,GACpD,OAAO,KAAK,SAAS,MAAM,CAAC,WAAW,KAAK;CAE9C,OAAO;AACT;AAEA,SAAgB,yBACd,YACA,UACA,MACA,aACA,eACe;CACf,IAAI,SAAS,QACX,OAAO;EAAE;EAAY,QAAQ;EAAQ;CAAS;CAGhD,IAAI,CAAC,UACH,OAAO;EAAE;EAAY,QAAQ;EAAa;CAAS;CAGrD,IAAI,SAAS,eAAe,WAAW,SAAS,aAAa,MAC3D,OAAO;EAAE;EAAY,QAAQ;EAAa;CAAS;CAGrD,IAAI,WAAW,iBAAiB,WAAW,GACzC,OAAO;EAAE;EAAY,QAAQ;EAAW;CAAS;CAGnD,IAAI,cAAc,SAAS,WAAW,IAAI,GACxC,OAAO;EAAE;EAAY,QAAQ;EAAiB;CAAS;CAGzD,IAAI,WAAW,iBAAiB,MAAM,QAAQ,YAAY,SAAS,GAAG,CAAC,GACrE,OAAO;EAAE;EAAY,QAAQ;EAAe;CAAS;CAGvD,OAAO;EAAE;EAAY,QAAQ;EAAa;CAAS;AACrD;AAEA,SAAgB,2BACd,UACA,iBACqB;CACrB,IAAI,CAAC,UACH,OAAO,CAAC;CAGV,MAAM,UAA+B,CAAC;CACtC,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,OAAO,QAAQ,SAAS,GAAG;EAC9D,MAAM,QAAQ,SAAS,OAAO;EAC9B,IAAI,gBAAgB,IAAI,MAAM,OAAO,GACnC;EAEF,QAAQ,KAAK;GACX,MAAM,MAAM;GACZ,UAAU,MAAM;GAChB,MAAM;GACN,UAAU;GACV,gBAAgB;GAChB,eAAe;GACf,QAAQ;GACR,QAAQ;GACR,SAAS;EACX,CAAC;CACH;CAEA,OAAO;AACT"}
|
|
@@ -51,6 +51,6 @@ function outputFileExists(outputDir, filePath) {
|
|
|
51
51
|
return fs.existsSync(pathModule.join(outputDir, filePath));
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
|
-
export { getExistingOutputFileSize, hashHtml, outputFileExists, readIncrementalManifest, writeIncrementalManifest };
|
|
54
|
+
export { getExistingOutputFileSize, getIncrementalManifestPath, hashHtml, outputFileExists, readIncrementalManifest, writeIncrementalManifest };
|
|
55
55
|
|
|
56
56
|
//# sourceMappingURL=incremental-manifest.js.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { _getBuiltInRoutePolicy } from "../router/policy.js";
|
|
2
|
+
import { getOutputFilePath, interpolateRoutePath, resolveRouteDescriptor } from "./route-utils.js";
|
|
3
|
+
import { expandRoutes } from "./resolve-ssg-data.js";
|
|
4
|
+
//#region src/ssg/static-routes.ts
|
|
5
|
+
function getRuntimeOnlyDiagnostic(route, path) {
|
|
6
|
+
const policies = route.policies ?? [];
|
|
7
|
+
if (route.auth === true) return `Skipped prerender for "${path}": authenticated routes are runtime-only by default.`;
|
|
8
|
+
if (route.role) return `Skipped prerender for "${path}": role-gated routes are runtime-only by default.`;
|
|
9
|
+
if (route.permission) return `Skipped prerender for "${path}": permission-gated routes are runtime-only by default.`;
|
|
10
|
+
if (policies.length > 0) {
|
|
11
|
+
let hasAuthPolicy = false;
|
|
12
|
+
let hasRolePolicy = false;
|
|
13
|
+
let hasPermissionPolicy = false;
|
|
14
|
+
for (const policy of policies) {
|
|
15
|
+
const metadata = _getBuiltInRoutePolicy(policy);
|
|
16
|
+
if (!metadata) return `Skipped prerender for "${path}": routes with custom policies are runtime-only by default.`;
|
|
17
|
+
if (metadata.kind === "auth") hasAuthPolicy = true;
|
|
18
|
+
else if (metadata.kind === "role") hasRolePolicy = true;
|
|
19
|
+
else if (metadata.kind === "permission") hasPermissionPolicy = true;
|
|
20
|
+
}
|
|
21
|
+
if (hasAuthPolicy) return `Skipped prerender for "${path}": authenticated routes are runtime-only by default.`;
|
|
22
|
+
if (hasRolePolicy) return `Skipped prerender for "${path}": role-gated routes are runtime-only by default.`;
|
|
23
|
+
if (hasPermissionPolicy) return `Skipped prerender for "${path}": permission-gated routes are runtime-only by default.`;
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function getRouteResultPath(route) {
|
|
29
|
+
return route.params ? interpolateRoutePath(route.path, route.params) : route.path;
|
|
30
|
+
}
|
|
31
|
+
function createRuntimeOnlyRoute(route, diagnostic) {
|
|
32
|
+
const path = getRouteResultPath(route);
|
|
33
|
+
const filePath = getOutputFilePath(path);
|
|
34
|
+
return {
|
|
35
|
+
routeId: `${path}::${filePath}`,
|
|
36
|
+
result: {
|
|
37
|
+
path,
|
|
38
|
+
filePath,
|
|
39
|
+
html: "",
|
|
40
|
+
fileSize: 0,
|
|
41
|
+
renderDuration: 0,
|
|
42
|
+
resourceCount: 0,
|
|
43
|
+
status: "skipped",
|
|
44
|
+
reason: "runtime-only",
|
|
45
|
+
written: false,
|
|
46
|
+
error: diagnostic
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async function splitStaticRoutes(routes) {
|
|
51
|
+
const prerenderableRoutes = [];
|
|
52
|
+
const runtimeOnly = [];
|
|
53
|
+
const outputRouteIds = [];
|
|
54
|
+
for (const route of routes) {
|
|
55
|
+
const diagnostic = getRuntimeOnlyDiagnostic(route, getRouteResultPath(route));
|
|
56
|
+
if (diagnostic) {
|
|
57
|
+
const runtimeRoute = createRuntimeOnlyRoute(route, diagnostic);
|
|
58
|
+
runtimeOnly.push(runtimeRoute);
|
|
59
|
+
outputRouteIds.push(runtimeRoute.routeId);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const expanded = await expandRoutes([route]);
|
|
63
|
+
prerenderableRoutes.push(...expanded);
|
|
64
|
+
for (const expandedRoute of expanded) outputRouteIds.push(resolveRouteDescriptor(expandedRoute).routeId);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
routes: prerenderableRoutes,
|
|
68
|
+
runtimeOnly,
|
|
69
|
+
outputRouteIds
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function normalizeStaticRoutes(options) {
|
|
73
|
+
if (options.registry) return routeRegistryToRouteConfigs(options.registry);
|
|
74
|
+
return [...options.routes ?? []];
|
|
75
|
+
}
|
|
76
|
+
function routeRegistryToRouteConfigs(registry) {
|
|
77
|
+
const routeConfigs = [];
|
|
78
|
+
for (const record of registry.manifest.records) {
|
|
79
|
+
if (record.isFallback) continue;
|
|
80
|
+
routeConfigs.push({
|
|
81
|
+
path: record.path,
|
|
82
|
+
handler: record.handler,
|
|
83
|
+
namespace: record.options.namespace,
|
|
84
|
+
auth: record.options.auth,
|
|
85
|
+
role: record.options.role,
|
|
86
|
+
permission: record.options.permission,
|
|
87
|
+
policies: stripRegistryGuestPolicies(record.options.policies),
|
|
88
|
+
entries: record.options.entries
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return routeConfigs;
|
|
92
|
+
}
|
|
93
|
+
function stripRegistryGuestPolicies(policies) {
|
|
94
|
+
if (!policies || policies.length === 0) return;
|
|
95
|
+
const filtered = policies.filter((policy) => _getBuiltInRoutePolicy(policy)?.kind !== "guest");
|
|
96
|
+
return filtered.length > 0 ? filtered : void 0;
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
export { normalizeStaticRoutes, splitStaticRoutes };
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=static-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-routes.js","names":[],"sources":["../../src/ssg/static-routes.ts"],"sourcesContent":["/**\n * SSG route source normalization and runtime-only filtering.\n */\n\nimport type { RouteConfig, RouteRenderResult } from './types';\nimport type { RoutePolicy, RouteRegistry } from '../common/router';\nimport { _getBuiltInRoutePolicy } from '../router/policy';\nimport { expandRoutes } from './resolve-ssg-data';\nimport {\n getOutputFilePath,\n interpolateRoutePath,\n resolveRouteDescriptor,\n} from './route-utils';\n\ntype StaticRouteSource = {\n registry?: RouteRegistry;\n routes?: readonly RouteConfig[];\n};\n\nexport type RuntimeOnlyRoute = {\n routeId: string;\n result: RouteRenderResult;\n};\n\nexport interface SplitStaticRoutesResult {\n routes: RouteConfig[];\n runtimeOnly: RuntimeOnlyRoute[];\n outputRouteIds: string[];\n}\n\nfunction getRuntimeOnlyDiagnostic(\n route: RouteConfig,\n path: string\n): string | null {\n const policies = route.policies ?? [];\n\n if (route.auth === true) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (route.role) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (route.permission) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n if (policies.length > 0) {\n let hasAuthPolicy = false;\n let hasRolePolicy = false;\n let hasPermissionPolicy = false;\n\n for (const policy of policies) {\n const metadata = _getBuiltInRoutePolicy(policy);\n if (!metadata) {\n return `Skipped prerender for \"${path}\": routes with custom policies are runtime-only by default.`;\n }\n\n if (metadata.kind === 'auth') {\n hasAuthPolicy = true;\n } else if (metadata.kind === 'role') {\n hasRolePolicy = true;\n } else if (metadata.kind === 'permission') {\n hasPermissionPolicy = true;\n }\n }\n\n if (hasAuthPolicy) {\n return `Skipped prerender for \"${path}\": authenticated routes are runtime-only by default.`;\n }\n\n if (hasRolePolicy) {\n return `Skipped prerender for \"${path}\": role-gated routes are runtime-only by default.`;\n }\n\n if (hasPermissionPolicy) {\n return `Skipped prerender for \"${path}\": permission-gated routes are runtime-only by default.`;\n }\n\n return null;\n }\n\n return null;\n}\n\nfunction getRouteResultPath(route: RouteConfig): string {\n return route.params\n ? interpolateRoutePath(route.path, route.params)\n : route.path;\n}\n\nfunction createRuntimeOnlyRoute(\n route: RouteConfig,\n diagnostic: string\n): RuntimeOnlyRoute {\n const path = getRouteResultPath(route);\n const filePath = getOutputFilePath(path);\n\n return {\n routeId: `${path}::${filePath}`,\n result: {\n path,\n filePath,\n html: '',\n fileSize: 0,\n renderDuration: 0,\n resourceCount: 0,\n status: 'skipped',\n reason: 'runtime-only',\n written: false,\n error: diagnostic,\n },\n };\n}\n\nexport async function splitStaticRoutes(\n routes: readonly RouteConfig[]\n): Promise<SplitStaticRoutesResult> {\n const prerenderableRoutes: RouteConfig[] = [];\n const runtimeOnly: RuntimeOnlyRoute[] = [];\n const outputRouteIds: string[] = [];\n\n for (const route of routes) {\n const routePath = getRouteResultPath(route);\n const diagnostic = getRuntimeOnlyDiagnostic(route, routePath);\n if (diagnostic) {\n const runtimeRoute = createRuntimeOnlyRoute(route, diagnostic);\n runtimeOnly.push(runtimeRoute);\n outputRouteIds.push(runtimeRoute.routeId);\n continue;\n }\n\n const expanded = await expandRoutes([route]);\n prerenderableRoutes.push(...expanded);\n for (const expandedRoute of expanded) {\n outputRouteIds.push(resolveRouteDescriptor(expandedRoute).routeId);\n }\n }\n\n return {\n routes: prerenderableRoutes,\n runtimeOnly,\n outputRouteIds,\n };\n}\n\nexport function normalizeStaticRoutes(\n options: StaticRouteSource\n): RouteConfig[] {\n if (options.registry) {\n return routeRegistryToRouteConfigs(options.registry);\n }\n\n return [...(options.routes ?? [])];\n}\n\nfunction routeRegistryToRouteConfigs(registry: RouteRegistry): RouteConfig[] {\n const routeConfigs: RouteConfig[] = [];\n\n for (const record of registry.manifest.records) {\n if (record.isFallback) {\n continue;\n }\n\n routeConfigs.push({\n path: record.path,\n handler: record.handler,\n namespace: record.options.namespace,\n auth: record.options.auth,\n role: record.options.role,\n permission: record.options.permission,\n policies: stripRegistryGuestPolicies(record.options.policies),\n entries: record.options.entries,\n });\n }\n\n return routeConfigs;\n}\n\nfunction stripRegistryGuestPolicies(\n policies: readonly RoutePolicy[] | undefined\n): readonly RoutePolicy[] | undefined {\n if (!policies || policies.length === 0) {\n return undefined;\n }\n\n const filtered = policies.filter(\n (policy) => _getBuiltInRoutePolicy(policy)?.kind !== 'guest'\n );\n\n return filtered.length > 0 ? filtered : undefined;\n}\n"],"mappings":";;;;AA8BA,SAAS,yBACP,OACA,MACe;CACf,MAAM,WAAW,MAAM,YAAY,CAAC;CAEpC,IAAI,MAAM,SAAS,MACjB,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,MACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,MAAM,YACR,OAAO,0BAA0B,KAAK;CAGxC,IAAI,SAAS,SAAS,GAAG;EACvB,IAAI,gBAAgB;EACpB,IAAI,gBAAgB;EACpB,IAAI,sBAAsB;EAE1B,KAAK,MAAM,UAAU,UAAU;GAC7B,MAAM,WAAW,uBAAuB,MAAM;GAC9C,IAAI,CAAC,UACH,OAAO,0BAA0B,KAAK;GAGxC,IAAI,SAAS,SAAS,QACpB,gBAAgB;QACX,IAAI,SAAS,SAAS,QAC3B,gBAAgB;QACX,IAAI,SAAS,SAAS,cAC3B,sBAAsB;EAE1B;EAEA,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,eACF,OAAO,0BAA0B,KAAK;EAGxC,IAAI,qBACF,OAAO,0BAA0B,KAAK;EAGxC,OAAO;CACT;CAEA,OAAO;AACT;AAEA,SAAS,mBAAmB,OAA4B;CACtD,OAAO,MAAM,SACT,qBAAqB,MAAM,MAAM,MAAM,MAAM,IAC7C,MAAM;AACZ;AAEA,SAAS,uBACP,OACA,YACkB;CAClB,MAAM,OAAO,mBAAmB,KAAK;CACrC,MAAM,WAAW,kBAAkB,IAAI;CAEvC,OAAO;EACL,SAAS,GAAG,KAAK,IAAI;EACrB,QAAQ;GACN;GACA;GACA,MAAM;GACN,UAAU;GACV,gBAAgB;GAChB,eAAe;GACf,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,OAAO;EACT;CACF;AACF;AAEA,eAAsB,kBACpB,QACkC;CAClC,MAAM,sBAAqC,CAAC;CAC5C,MAAM,cAAkC,CAAC;CACzC,MAAM,iBAA2B,CAAC;CAElC,KAAK,MAAM,SAAS,QAAQ;EAE1B,MAAM,aAAa,yBAAyB,OAD1B,mBAAmB,KACc,CAAS;EAC5D,IAAI,YAAY;GACd,MAAM,eAAe,uBAAuB,OAAO,UAAU;GAC7D,YAAY,KAAK,YAAY;GAC7B,eAAe,KAAK,aAAa,OAAO;GACxC;EACF;EAEA,MAAM,WAAW,MAAM,aAAa,CAAC,KAAK,CAAC;EAC3C,oBAAoB,KAAK,GAAG,QAAQ;EACpC,KAAK,MAAM,iBAAiB,UAC1B,eAAe,KAAK,uBAAuB,aAAa,CAAC,CAAC,OAAO;CAErE;CAEA,OAAO;EACL,QAAQ;EACR;EACA;CACF;AACF;AAEA,SAAgB,sBACd,SACe;CACf,IAAI,QAAQ,UACV,OAAO,4BAA4B,QAAQ,QAAQ;CAGrD,OAAO,CAAC,GAAI,QAAQ,UAAU,CAAC,CAAE;AACnC;AAEA,SAAS,4BAA4B,UAAwC;CAC3E,MAAM,eAA8B,CAAC;CAErC,KAAK,MAAM,UAAU,SAAS,SAAS,SAAS;EAC9C,IAAI,OAAO,YACT;EAGF,aAAa,KAAK;GAChB,MAAM,OAAO;GACb,SAAS,OAAO;GAChB,WAAW,OAAO,QAAQ;GAC1B,MAAM,OAAO,QAAQ;GACrB,MAAM,OAAO,QAAQ;GACrB,YAAY,OAAO,QAAQ;GAC3B,UAAU,2BAA2B,OAAO,QAAQ,QAAQ;GAC5D,SAAS,OAAO,QAAQ;EAC1B,CAAC;CACH;CAEA,OAAO;AACT;AAEA,SAAS,2BACP,UACoC;CACpC,IAAI,CAAC,YAAY,SAAS,WAAW,GACnC;CAGF,MAAM,WAAW,SAAS,QACvB,WAAW,uBAAuB,MAAM,CAAC,EAAE,SAAS,OACvD;CAEA,OAAO,SAAS,SAAS,IAAI,WAAW;AAC1C"}
|
package/dist/ssg/types.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { ComponentFunction } from "../common/component.js";
|
|
2
1
|
import { DocumentRenderer } from "../common/ssr.js";
|
|
3
|
-
import {
|
|
2
|
+
import { RenderableChild } from "../common/vnode.js";
|
|
3
|
+
import { ComponentFunction } from "../common/component.js";
|
|
4
|
+
import { RouteAuthMode, RouteHandler, RoutePathParams, RoutePolicy, RouteRegistry } from "../common/router.js";
|
|
4
5
|
|
|
5
6
|
//#region src/ssg/types.d.ts
|
|
6
7
|
type SSGMode = 'full' | 'incremental';
|
|
7
8
|
type RouteRenderStatus = 'success' | 'error' | 'skipped' | 'removed';
|
|
8
9
|
type RouteRenderReason = 'full' | 'changed-key' | 'changed-route' | 'new-route' | 'no-keys' | 'unchanged' | 'deleted' | 'runtime-only';
|
|
9
10
|
type RouteConfigParams<Path extends string> = string extends Path ? Record<string, string> : RoutePathParams<Path>;
|
|
11
|
+
type RouteComponentProps<Path extends string> = RouteConfigParams<Path> & Record<string, unknown>;
|
|
12
|
+
type StaticRouteComponent<Path extends string> = (props: RouteComponentProps<Path>, context?: Parameters<ComponentFunction>[1]) => RenderableChild;
|
|
10
13
|
/**
|
|
11
14
|
* Route config accepted by SSG.
|
|
12
15
|
*
|
|
@@ -19,7 +22,7 @@ interface RouteConfig<Path extends string = string> {
|
|
|
19
22
|
/** Route handler compatible with router/SSR */
|
|
20
23
|
handler?: RouteHandler;
|
|
21
24
|
/** Backward-compatible alias for handler */
|
|
22
|
-
component?:
|
|
25
|
+
component?: StaticRouteComponent<Path>;
|
|
23
26
|
/** Optional base props merged with route params during render */
|
|
24
27
|
props?: Record<string, unknown>;
|
|
25
28
|
/** Optional namespace for router compatibility */
|
|
@@ -50,10 +53,7 @@ interface RouteConfig<Path extends string = string> {
|
|
|
50
53
|
*/
|
|
51
54
|
entries?: () => Array<RouteConfigParams<Path>> | Promise<Array<RouteConfigParams<Path>>>;
|
|
52
55
|
}
|
|
53
|
-
|
|
54
|
-
interface SSGOptions<TRoutes extends readonly RouteConfig[] = RouteConfig[]> {
|
|
55
|
-
/** Routes to generate */
|
|
56
|
-
routes: TRoutes;
|
|
56
|
+
interface SSGBaseOptions {
|
|
57
57
|
/** Output directory for generated HTML files */
|
|
58
58
|
outputDir: string;
|
|
59
59
|
/** Optional seed for deterministic rendering */
|
|
@@ -67,6 +67,14 @@ interface SSGOptions<TRoutes extends readonly RouteConfig[] = RouteConfig[]> {
|
|
|
67
67
|
/** Preferred render parallelism. `'auto'` resolves from the host machine. */
|
|
68
68
|
parallelism?: number | 'auto';
|
|
69
69
|
}
|
|
70
|
+
/** Options for createStaticGen */
|
|
71
|
+
type SSGOptions<TRoutes extends readonly RouteConfig[] = RouteConfig[]> = SSGBaseOptions & ({
|
|
72
|
+
/** Routes to generate. Prefer `registry` when routes are already defined through the router DSL. */routes: TRoutes;
|
|
73
|
+
registry?: never;
|
|
74
|
+
} | {
|
|
75
|
+
/** Explicit route registry captured with `createRouteRegistry()`. */registry: RouteRegistry;
|
|
76
|
+
routes?: never;
|
|
77
|
+
});
|
|
70
78
|
/** Options for a single generation run */
|
|
71
79
|
interface SSGGenerateOptions {
|
|
72
80
|
/** Generation mode */
|
package/dist/ssg/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/ssg/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../src/ssg/types.ts"],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { __CONTROL_BOUNDARY__ } from "../common/control.js";
|
|
2
|
+
import { ELEMENT_TYPE } from "../common/jsx.js";
|
|
3
|
+
import { evaluateForState } from "../runtime/for-internal.js";
|
|
4
|
+
import "../runtime/for.js";
|
|
5
|
+
import { evaluateCaseState, evaluateShowState } from "../runtime/control.js";
|
|
6
|
+
import "../jsx/index.js";
|
|
7
|
+
//#region src/ssr/boundaries.ts
|
|
8
|
+
function normalizeRenderableChildren(value) {
|
|
9
|
+
if (value === null || value === void 0 || value === false) return [];
|
|
10
|
+
return Array.isArray(value) ? value : [value];
|
|
11
|
+
}
|
|
12
|
+
function getRenderableChildren(node) {
|
|
13
|
+
if (Array.isArray(node.children)) return node.children;
|
|
14
|
+
if (Array.isArray(node.props?.children)) return node.props.children;
|
|
15
|
+
if (node.props?.children !== void 0 && node.props.children !== null && node.props.children !== false) return [node.props.children];
|
|
16
|
+
}
|
|
17
|
+
function getErrorBoundaryState(node) {
|
|
18
|
+
return node.__instance?.errorBoundaryState ?? null;
|
|
19
|
+
}
|
|
20
|
+
function resetErrorBoundaryState(node) {
|
|
21
|
+
const state = node.__instance?.errorBoundaryState;
|
|
22
|
+
if (state) {
|
|
23
|
+
state.error = null;
|
|
24
|
+
state.notified = false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function createErrorBoundaryReset(node) {
|
|
28
|
+
return () => resetErrorBoundaryState(node);
|
|
29
|
+
}
|
|
30
|
+
function createDefaultErrorBoundaryFallbackVNode(error) {
|
|
31
|
+
const message = error instanceof Error ? error.stack || error.message || error.name : typeof error === "string" ? error : (() => {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.stringify(error);
|
|
34
|
+
} catch {
|
|
35
|
+
return String(error);
|
|
36
|
+
}
|
|
37
|
+
})();
|
|
38
|
+
return {
|
|
39
|
+
$$typeof: ELEMENT_TYPE,
|
|
40
|
+
type: "div",
|
|
41
|
+
props: {
|
|
42
|
+
role: "alert",
|
|
43
|
+
"data-askr-error-boundary": "true",
|
|
44
|
+
style: {
|
|
45
|
+
boxSizing: "border-box",
|
|
46
|
+
padding: "1rem",
|
|
47
|
+
border: "1px solid currentColor",
|
|
48
|
+
borderRadius: "0.75rem",
|
|
49
|
+
display: "grid",
|
|
50
|
+
gap: "0.75rem",
|
|
51
|
+
maxWidth: "100%"
|
|
52
|
+
},
|
|
53
|
+
children: [
|
|
54
|
+
{
|
|
55
|
+
$$typeof: ELEMENT_TYPE,
|
|
56
|
+
type: "strong",
|
|
57
|
+
props: { children: ["Something went wrong while rendering this view."] }
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
$$typeof: ELEMENT_TYPE,
|
|
61
|
+
type: "p",
|
|
62
|
+
props: {
|
|
63
|
+
style: { margin: "0" },
|
|
64
|
+
children: ["The app recovered into a visible fallback so the error is not hidden in the console."]
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
$$typeof: ELEMENT_TYPE,
|
|
69
|
+
type: "details",
|
|
70
|
+
props: {
|
|
71
|
+
open: true,
|
|
72
|
+
children: [{
|
|
73
|
+
$$typeof: ELEMENT_TYPE,
|
|
74
|
+
type: "summary",
|
|
75
|
+
props: { children: ["Error details"] }
|
|
76
|
+
}, {
|
|
77
|
+
$$typeof: ELEMENT_TYPE,
|
|
78
|
+
type: "pre",
|
|
79
|
+
props: {
|
|
80
|
+
style: {
|
|
81
|
+
margin: "0",
|
|
82
|
+
whiteSpace: "pre-wrap",
|
|
83
|
+
wordBreak: "break-word"
|
|
84
|
+
},
|
|
85
|
+
children: [message]
|
|
86
|
+
}
|
|
87
|
+
}]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
key: null
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function resolveErrorBoundaryFallbackNode(fallback, error, reset) {
|
|
96
|
+
return typeof fallback === "function" ? fallback(error, reset) : fallback !== void 0 ? fallback : createDefaultErrorBoundaryFallbackVNode(error);
|
|
97
|
+
}
|
|
98
|
+
function getControlBoundaryState(node) {
|
|
99
|
+
const boundaryNode = node;
|
|
100
|
+
return boundaryNode._controlState ?? boundaryNode._forState ?? null;
|
|
101
|
+
}
|
|
102
|
+
function evaluateControlBoundaryChildren(node) {
|
|
103
|
+
if (node.type !== __CONTROL_BOUNDARY__) return;
|
|
104
|
+
const controlState = getControlBoundaryState(node);
|
|
105
|
+
if (!controlState) return [];
|
|
106
|
+
if (controlState.kind === "for") return evaluateForState(controlState);
|
|
107
|
+
if (controlState.kind === "show") return evaluateShowState(controlState);
|
|
108
|
+
return evaluateCaseState(controlState);
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { createErrorBoundaryReset, evaluateControlBoundaryChildren, getControlBoundaryState, getErrorBoundaryState, getRenderableChildren, normalizeRenderableChildren, resetErrorBoundaryState, resolveErrorBoundaryFallbackNode };
|
|
112
|
+
|
|
113
|
+
//# sourceMappingURL=boundaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundaries.js","names":[],"sources":["../../src/ssr/boundaries.ts"],"sourcesContent":["/**\n * Shared SSR boundary state and renderable child helpers.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport { __CONTROL_BOUNDARY__ } from '../common/control';\nimport type { DOMElement } from '../common/vnode';\nimport { ELEMENT_TYPE } from '../jsx';\nimport type { ComponentInstance } from '../runtime/component';\nimport {\n type ControlBoundaryState,\n evaluateCaseState,\n evaluateShowState,\n} from '../runtime/control';\nimport { evaluateForState } from '../runtime/for';\nimport type { VNode } from './types';\n\ntype ErrorBoundaryState = NonNullable<ComponentInstance['errorBoundaryState']>;\n\nexport function normalizeRenderableChildren(value: unknown): unknown[] {\n if (value === null || value === undefined || value === false) {\n return [];\n }\n\n return Array.isArray(value) ? value : [value];\n}\n\nexport function getRenderableChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (Array.isArray((node as VNode).children)) {\n return (node as VNode).children;\n }\n if (Array.isArray(node.props?.children)) {\n return node.props.children as unknown[];\n }\n if (\n node.props?.children !== undefined &&\n node.props.children !== null &&\n node.props.children !== false\n ) {\n return [node.props.children];\n }\n return undefined;\n}\n\nexport function getErrorBoundaryState(\n node: VNode | JSXElement\n): ErrorBoundaryState | null {\n return (\n (node as DOMElement & { __instance?: ComponentInstance }).__instance\n ?.errorBoundaryState ?? null\n );\n}\n\nexport function resetErrorBoundaryState(node: VNode | JSXElement): void {\n const instance = (node as DOMElement & { __instance?: ComponentInstance })\n .__instance;\n const state = instance?.errorBoundaryState;\n if (state) {\n state.error = null;\n state.notified = false;\n }\n}\n\nexport function createErrorBoundaryReset(node: VNode | JSXElement): () => void {\n return () => resetErrorBoundaryState(node);\n}\n\nfunction createDefaultErrorBoundaryFallbackVNode(error: unknown): JSXElement {\n const message =\n error instanceof Error\n ? error.stack || error.message || error.name\n : typeof error === 'string'\n ? error\n : (() => {\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n })();\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: 'div',\n props: {\n role: 'alert',\n 'data-askr-error-boundary': 'true',\n style: {\n boxSizing: 'border-box',\n padding: '1rem',\n border: '1px solid currentColor',\n borderRadius: '0.75rem',\n display: 'grid',\n gap: '0.75rem',\n maxWidth: '100%',\n },\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'strong',\n props: {\n children: ['Something went wrong while rendering this view.'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'p',\n props: {\n style: { margin: '0' },\n children: [\n 'The app recovered into a visible fallback so the error is not hidden in the console.',\n ],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'details',\n props: {\n open: process.env.NODE_ENV !== 'production',\n children: [\n {\n $$typeof: ELEMENT_TYPE,\n type: 'summary',\n props: {\n children: ['Error details'],\n },\n },\n {\n $$typeof: ELEMENT_TYPE,\n type: 'pre',\n props: {\n style: {\n margin: '0',\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n },\n children: [message],\n },\n },\n ],\n },\n },\n ],\n },\n key: null,\n } as JSXElement;\n}\n\nexport function resolveErrorBoundaryFallbackNode(\n fallback: unknown,\n error: unknown,\n reset: () => void\n): unknown {\n return typeof fallback === 'function'\n ? (fallback as (error: unknown, reset: () => void) => unknown)(error, reset)\n : fallback !== undefined\n ? fallback\n : createDefaultErrorBoundaryFallbackVNode(error);\n}\n\nexport function getControlBoundaryState(\n node: VNode | JSXElement\n): ControlBoundaryState | null {\n const boundaryNode = node as DOMElement;\n\n return (\n boundaryNode._controlState ??\n (boundaryNode._forState as ControlBoundaryState | undefined) ??\n null\n );\n}\n\nexport function evaluateControlBoundaryChildren(\n node: VNode | JSXElement\n): unknown[] | undefined {\n if (node.type !== __CONTROL_BOUNDARY__) {\n return undefined;\n }\n\n const controlState = getControlBoundaryState(node);\n if (!controlState) {\n return [];\n }\n\n if (controlState.kind === 'for') {\n return evaluateForState(controlState);\n }\n if (controlState.kind === 'show') {\n return evaluateShowState(controlState);\n }\n return evaluateCaseState(controlState);\n}\n"],"mappings":";;;;;;;AAmBA,SAAgB,4BAA4B,OAA2B;CACrE,IAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,OACrD,OAAO,CAAC;CAGV,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC9C;AAEA,SAAgB,sBACd,MACuB;CACvB,IAAI,MAAM,QAAS,KAAe,QAAQ,GACxC,OAAQ,KAAe;CAEzB,IAAI,MAAM,QAAQ,KAAK,OAAO,QAAQ,GACpC,OAAO,KAAK,MAAM;CAEpB,IACE,KAAK,OAAO,aAAa,UACzB,KAAK,MAAM,aAAa,QACxB,KAAK,MAAM,aAAa,OAExB,OAAO,CAAC,KAAK,MAAM,QAAQ;AAG/B;AAEA,SAAgB,sBACd,MAC2B;CAC3B,OACG,KAAyD,YACtD,sBAAsB;AAE9B;AAEA,SAAgB,wBAAwB,MAAgC;CAGtE,MAAM,QAFY,KACf,YACqB;CACxB,IAAI,OAAO;EACT,MAAM,QAAQ;EACd,MAAM,WAAW;CACnB;AACF;AAEA,SAAgB,yBAAyB,MAAsC;CAC7E,aAAa,wBAAwB,IAAI;AAC3C;AAEA,SAAS,wCAAwC,OAA4B;CAC3E,MAAM,UACJ,iBAAiB,QACb,MAAM,SAAS,MAAM,WAAW,MAAM,OACtC,OAAO,UAAU,WACf,eACO;EACL,IAAI;GACF,OAAO,KAAK,UAAU,KAAK;EAC7B,QAAQ;GACN,OAAO,OAAO,KAAK;EACrB;CACF,EAAA,CAAG;CAEX,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO;GACL,MAAM;GACN,4BAA4B;GAC5B,OAAO;IACL,WAAW;IACX,SAAS;IACT,QAAQ;IACR,cAAc;IACd,SAAS;IACT,KAAK;IACL,UAAU;GACZ;GACA,UAAU;IACR;KACE,UAAU;KACV,MAAM;KACN,OAAO,EACL,UAAU,CAAC,iDAAiD,EAC9D;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,OAAO,EAAE,QAAQ,IAAI;MACrB,UAAU,CACR,sFACF;KACF;IACF;IACA;KACE,UAAU;KACV,MAAM;KACN,OAAO;MACL,MAAA;MACA,UAAU,CACR;OACE,UAAU;OACV,MAAM;OACN,OAAO,EACL,UAAU,CAAC,eAAe,EAC5B;MACF,GACA;OACE,UAAU;OACV,MAAM;OACN,OAAO;QACL,OAAO;SACL,QAAQ;SACR,YAAY;SACZ,WAAW;QACb;QACA,UAAU,CAAC,OAAO;OACpB;MACF,CACF;KACF;IACF;GACF;EACF;EACA,KAAK;CACP;AACF;AAEA,SAAgB,iCACd,UACA,OACA,OACS;CACT,OAAO,OAAO,aAAa,aACtB,SAA4D,OAAO,KAAK,IACzE,aAAa,SACX,WACA,wCAAwC,KAAK;AACrD;AAEA,SAAgB,wBACd,MAC6B;CAC7B,MAAM,eAAe;CAErB,OACE,aAAa,iBACZ,aAAa,aACd;AAEJ;AAEA,SAAgB,gCACd,MACuB;CACvB,IAAI,KAAK,SAAS,sBAChB;CAGF,MAAM,eAAe,wBAAwB,IAAI;CACjD,IAAI,CAAC,cACH,OAAO,CAAC;CAGV,IAAI,aAAa,SAAS,OACxB,OAAO,iBAAiB,YAAY;CAEtC,IAAI,aAAa,SAAS,QACxB,OAAO,kBAAkB,YAAY;CAEvC,OAAO,kBAAkB,YAAY;AACvC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { ELEMENT_TYPE, Fragment } from "../common/jsx.js";
|
|
2
|
+
import { getCurrentComponentInstance, setCurrentComponentInstance } from "../runtime/component-scope.js";
|
|
3
|
+
import { cleanupComponent } from "../runtime/component-cleanup.js";
|
|
4
|
+
import { isPromiseLike } from "../common/promise.js";
|
|
5
|
+
import { createComponentInstance } from "../runtime/component-internal.js";
|
|
6
|
+
import "../runtime/component.js";
|
|
7
|
+
import { DefaultPortal, disposeDefaultPortalScope } from "../foundations/structures/portal.js";
|
|
8
|
+
import "../jsx/index.js";
|
|
9
|
+
import { throwSSRDataMissing } from "./context.js";
|
|
10
|
+
//#region src/ssr/component-runtime.ts
|
|
11
|
+
const __ssrGuardStack = [];
|
|
12
|
+
function pushSSRStrictPurityGuard() {
|
|
13
|
+
__ssrGuardStack.push({
|
|
14
|
+
random: Reflect.get(Math, "random"),
|
|
15
|
+
now: Reflect.get(Date, "now")
|
|
16
|
+
});
|
|
17
|
+
Reflect.set(Math, "random", () => {
|
|
18
|
+
throw new Error("SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead.");
|
|
19
|
+
});
|
|
20
|
+
Reflect.set(Date, "now", () => {
|
|
21
|
+
throw new Error("SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers.");
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function popSSRStrictPurityGuard() {
|
|
25
|
+
const prev = __ssrGuardStack.pop();
|
|
26
|
+
if (prev) {
|
|
27
|
+
Reflect.set(Math, "random", prev.random);
|
|
28
|
+
Reflect.set(Date, "now", prev.now);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function executeComponentSync(component, props, ctx) {
|
|
32
|
+
try {
|
|
33
|
+
pushSSRStrictPurityGuard();
|
|
34
|
+
const prev = getCurrentComponentInstance();
|
|
35
|
+
const temp = createComponentInstance("ssr-temp", component, props || {}, null);
|
|
36
|
+
temp.ssr = true;
|
|
37
|
+
temp.portalScope = temp;
|
|
38
|
+
ctx.ssrCleanupFns.push(() => {
|
|
39
|
+
let cleanupError = null;
|
|
40
|
+
try {
|
|
41
|
+
cleanupComponent(temp);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
cleanupError = error;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
disposeDefaultPortalScope(temp);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (cleanupError) throw new AggregateError([cleanupError, error], "SSR temporary owner cleanup failed");
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
if (cleanupError) throw cleanupError;
|
|
52
|
+
});
|
|
53
|
+
setCurrentComponentInstance(temp);
|
|
54
|
+
try {
|
|
55
|
+
const result = component(props || {}, { ssr: ctx });
|
|
56
|
+
if (isPromiseLike(result)) throwSSRDataMissing();
|
|
57
|
+
if (typeof result === "string" || typeof result === "number" || typeof result === "boolean" || result === null || result === void 0) {
|
|
58
|
+
const inner = result === null || result === void 0 || result === false ? "" : String(result);
|
|
59
|
+
return {
|
|
60
|
+
$$typeof: ELEMENT_TYPE,
|
|
61
|
+
type: Fragment,
|
|
62
|
+
props: { children: inner ? [inner] : [] }
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
} finally {
|
|
67
|
+
setCurrentComponentInstance(prev);
|
|
68
|
+
}
|
|
69
|
+
} finally {
|
|
70
|
+
popSSRStrictPurityGuard();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function disposeSSRTemporaryOwners(ctx) {
|
|
74
|
+
const cleanupFns = ctx.ssrCleanupFns;
|
|
75
|
+
ctx.ssrCleanupFns = [];
|
|
76
|
+
const cleanupErrors = [];
|
|
77
|
+
for (let index = cleanupFns.length - 1; index >= 0; index -= 1) try {
|
|
78
|
+
cleanupFns[index]();
|
|
79
|
+
} catch (error) {
|
|
80
|
+
cleanupErrors.push(error);
|
|
81
|
+
}
|
|
82
|
+
if (cleanupErrors.length === 1) throw cleanupErrors[0];
|
|
83
|
+
if (cleanupErrors.length > 1) throw new AggregateError(cleanupErrors, "SSR temporary owner cleanup failed");
|
|
84
|
+
}
|
|
85
|
+
function wrapWithDefaultPortal(out) {
|
|
86
|
+
if (isPromiseLike(out)) throwSSRDataMissing();
|
|
87
|
+
const portalVNode = {
|
|
88
|
+
$$typeof: ELEMENT_TYPE,
|
|
89
|
+
type: DefaultPortal,
|
|
90
|
+
props: {},
|
|
91
|
+
key: "__default_portal"
|
|
92
|
+
};
|
|
93
|
+
if (out == null) return {
|
|
94
|
+
$$typeof: ELEMENT_TYPE,
|
|
95
|
+
type: Fragment,
|
|
96
|
+
props: { children: [portalVNode] }
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
$$typeof: ELEMENT_TYPE,
|
|
100
|
+
type: Fragment,
|
|
101
|
+
props: { children: [out, portalVNode] }
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function renderSyncComponentRoot(component, props, ctx) {
|
|
105
|
+
const wrapped = (p, c) => wrapWithDefaultPortal(component(p ?? {}, c));
|
|
106
|
+
return executeComponentSync(wrapped, props || {}, ctx);
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
export { disposeSSRTemporaryOwners, executeComponentSync, renderSyncComponentRoot };
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=component-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-runtime.js","names":[],"sources":["../../src/ssr/component-runtime.ts"],"sourcesContent":["/**\n * SSR component execution and temporary owner lifecycle.\n */\n\nimport type { JSXElement } from '../common/jsx';\nimport type { Props } from '../common/props';\nimport type { ComponentFunction } from '../common/component';\nimport { isPromiseLike } from '../common/promise';\nimport { Fragment, ELEMENT_TYPE } from '../jsx';\nimport { DefaultPortal } from '../foundations/structures/portal';\nimport { disposeDefaultPortalScope } from '../foundations/structures/portal';\nimport {\n cleanupComponent,\n createComponentInstance,\n getCurrentComponentInstance,\n setCurrentComponentInstance,\n} from '../runtime/component';\nimport { throwSSRDataMissing, type RenderContext } from './context';\nimport type { SSRComponent, VNode } from './types';\n\nexport type Component = SSRComponent;\n\nconst __ssrGuardStack: Array<{ random: () => number; now: () => number }> = [];\n\nfunction pushSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n __ssrGuardStack.push({\n random: Reflect.get(Math, 'random') as () => number,\n now: Reflect.get(Date, 'now') as () => number,\n });\n Reflect.set(Math, 'random', () => {\n throw new Error(\n 'SSR Strict Purity: Math.random is not allowed during synchronous SSR. Use the provided `ssr` context RNG instead.'\n );\n });\n Reflect.set(Date, 'now', () => {\n throw new Error(\n 'SSR Strict Purity: Date.now is not allowed during synchronous SSR. Pass timestamps explicitly or use deterministic helpers.'\n );\n });\n}\n\nfunction popSSRStrictPurityGuard() {\n /* istanbul ignore if - dev-only guard */\n if (process.env.NODE_ENV === 'production') return;\n const prev = __ssrGuardStack.pop();\n if (prev) {\n Reflect.set(Math, 'random', prev.random);\n Reflect.set(Date, 'now', prev.now);\n }\n}\n\nexport function executeComponentSync(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n try {\n if (process.env.NODE_ENV !== 'production') {\n pushSSRStrictPurityGuard();\n }\n const prev = getCurrentComponentInstance();\n const temp = createComponentInstance(\n 'ssr-temp',\n component as ComponentFunction,\n (props || {}) as Props,\n null\n );\n temp.ssr = true;\n temp.portalScope = temp;\n ctx.ssrCleanupFns.push(() => {\n let cleanupError: unknown = null;\n\n try {\n cleanupComponent(temp);\n } catch (error) {\n cleanupError = error;\n }\n\n try {\n disposeDefaultPortalScope(temp);\n } catch (error) {\n if (cleanupError) {\n throw new AggregateError(\n [cleanupError, error],\n 'SSR temporary owner cleanup failed'\n );\n }\n throw error;\n }\n\n if (cleanupError) {\n throw cleanupError;\n }\n });\n setCurrentComponentInstance(temp);\n try {\n const result = component((props || {}) as Props, { ssr: ctx });\n if (isPromiseLike(result)) {\n throwSSRDataMissing();\n }\n if (\n typeof result === 'string' ||\n typeof result === 'number' ||\n typeof result === 'boolean' ||\n result === null ||\n result === undefined\n ) {\n const inner =\n result === null || result === undefined || result === false\n ? ''\n : String(result);\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: inner ? [inner] : [] },\n } as unknown as VNode | JSXElement;\n }\n return result as VNode | JSXElement;\n } finally {\n setCurrentComponentInstance(prev);\n }\n } finally {\n if (process.env.NODE_ENV !== 'production') popSSRStrictPurityGuard();\n }\n}\n\nexport function disposeSSRTemporaryOwners(ctx: RenderContext): void {\n const cleanupFns = ctx.ssrCleanupFns;\n ctx.ssrCleanupFns = [];\n const cleanupErrors: unknown[] = [];\n\n for (let index = cleanupFns.length - 1; index >= 0; index -= 1) {\n try {\n cleanupFns[index]();\n } catch (error) {\n cleanupErrors.push(error);\n }\n }\n\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n\n if (cleanupErrors.length > 1) {\n throw new AggregateError(\n cleanupErrors,\n 'SSR temporary owner cleanup failed'\n );\n }\n}\n\nfunction wrapWithDefaultPortal(out: unknown): VNode | JSXElement {\n if (isPromiseLike(out)) {\n throwSSRDataMissing();\n }\n\n const portalVNode = {\n $$typeof: ELEMENT_TYPE,\n type: DefaultPortal,\n props: {},\n key: '__default_portal',\n } as unknown;\n\n if (out == null) {\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [portalVNode] },\n } as unknown as VNode | JSXElement;\n }\n\n return {\n $$typeof: ELEMENT_TYPE,\n type: Fragment,\n props: { children: [out as unknown, portalVNode] },\n } as unknown as VNode | JSXElement;\n}\n\nexport function renderSyncComponentRoot(\n component: Component,\n props: Record<string, unknown> | undefined,\n ctx: RenderContext\n): VNode | JSXElement {\n const wrapped: Component = (\n p?: Record<string, unknown>,\n c?: { signal?: AbortSignal; ssr?: RenderContext }\n ) => wrapWithDefaultPortal(component(p ?? {}, c));\n\n return executeComponentSync(wrapped, props || {}, ctx);\n}\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,kBAAsE,CAAC;AAE7E,SAAS,2BAA2B;CAGlC,gBAAgB,KAAK;EACnB,QAAQ,QAAQ,IAAI,MAAM,QAAQ;EAClC,KAAK,QAAQ,IAAI,MAAM,KAAK;CAC9B,CAAC;CACD,QAAQ,IAAI,MAAM,gBAAgB;EAChC,MAAM,IAAI,MACR,mHACF;CACF,CAAC;CACD,QAAQ,IAAI,MAAM,aAAa;EAC7B,MAAM,IAAI,MACR,6HACF;CACF,CAAC;AACH;AAEA,SAAS,0BAA0B;CAGjC,MAAM,OAAO,gBAAgB,IAAI;CACjC,IAAI,MAAM;EACR,QAAQ,IAAI,MAAM,UAAU,KAAK,MAAM;EACvC,QAAQ,IAAI,MAAM,OAAO,KAAK,GAAG;CACnC;AACF;AAEA,SAAgB,qBACd,WACA,OACA,KACoB;CACpB,IAAI;EAEA,yBAAyB;EAE3B,MAAM,OAAO,4BAA4B;EACzC,MAAM,OAAO,wBACX,YACA,WACC,SAAS,CAAC,GACX,IACF;EACA,KAAK,MAAM;EACX,KAAK,cAAc;EACnB,IAAI,cAAc,WAAW;GAC3B,IAAI,eAAwB;GAE5B,IAAI;IACF,iBAAiB,IAAI;GACvB,SAAS,OAAO;IACd,eAAe;GACjB;GAEA,IAAI;IACF,0BAA0B,IAAI;GAChC,SAAS,OAAO;IACd,IAAI,cACF,MAAM,IAAI,eACR,CAAC,cAAc,KAAK,GACpB,oCACF;IAEF,MAAM;GACR;GAEA,IAAI,cACF,MAAM;EAEV,CAAC;EACD,4BAA4B,IAAI;EAChC,IAAI;GACF,MAAM,SAAS,UAAW,SAAS,CAAC,GAAa,EAAE,KAAK,IAAI,CAAC;GAC7D,IAAI,cAAc,MAAM,GACtB,oBAAoB;GAEtB,IACE,OAAO,WAAW,YAClB,OAAO,WAAW,YAClB,OAAO,WAAW,aAClB,WAAW,QACX,WAAW,QACX;IACA,MAAM,QACJ,WAAW,QAAQ,WAAW,UAAa,WAAW,QAClD,KACA,OAAO,MAAM;IACnB,OAAO;KACL,UAAU;KACV,MAAM;KACN,OAAO,EAAE,UAAU,QAAQ,CAAC,KAAK,IAAI,CAAC,EAAE;IAC1C;GACF;GACA,OAAO;EACT,UAAU;GACR,4BAA4B,IAAI;EAClC;CACF,UAAU;EACmC,wBAAwB;CACrE;AACF;AAEA,SAAgB,0BAA0B,KAA0B;CAClE,MAAM,aAAa,IAAI;CACvB,IAAI,gBAAgB,CAAC;CACrB,MAAM,gBAA2B,CAAC;CAElC,KAAK,IAAI,QAAQ,WAAW,SAAS,GAAG,SAAS,GAAG,SAAS,GAC3D,IAAI;EACF,WAAW,MAAM,CAAC;CACpB,SAAS,OAAO;EACd,cAAc,KAAK,KAAK;CAC1B;CAGF,IAAI,cAAc,WAAW,GAC3B,MAAM,cAAc;CAGtB,IAAI,cAAc,SAAS,GACzB,MAAM,IAAI,eACR,eACA,oCACF;AAEJ;AAEA,SAAS,sBAAsB,KAAkC;CAC/D,IAAI,cAAc,GAAG,GACnB,oBAAoB;CAGtB,MAAM,cAAc;EAClB,UAAU;EACV,MAAM;EACN,OAAO,CAAC;EACR,KAAK;CACP;CAEA,IAAI,OAAO,MACT,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU,CAAC,WAAW,EAAE;CACnC;CAGF,OAAO;EACL,UAAU;EACV,MAAM;EACN,OAAO,EAAE,UAAU,CAAC,KAAgB,WAAW,EAAE;CACnD;AACF;AAEA,SAAgB,wBACd,WACA,OACA,KACoB;CACpB,MAAM,WACJ,GACA,MACG,sBAAsB,UAAU,KAAK,CAAC,GAAG,CAAC,CAAC;CAEhD,OAAO,qBAAqB,SAAS,SAAS,CAAC,GAAG,GAAG;AACvD"}
|