@ecopages/core 0.2.0-beta.2 → 0.2.0-beta.21
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/README.md +1 -1
- package/package.json +163 -3
- package/src/adapters/abstract/application-adapter.d.ts +104 -5
- package/src/adapters/abstract/application-adapter.js +125 -1
- package/src/adapters/abstract/server-adapter.d.ts +6 -2
- package/src/adapters/abstract/ws-pattern-matcher.d.ts +60 -0
- package/src/adapters/abstract/ws-pattern-matcher.js +61 -0
- package/src/adapters/bun/client-bridge.d.ts +1 -0
- package/src/adapters/bun/client-bridge.js +3 -0
- package/src/adapters/bun/create-app.d.ts +6 -4
- package/src/adapters/bun/create-app.js +65 -43
- package/src/adapters/bun/server-adapter.d.ts +90 -22
- package/src/adapters/bun/server-adapter.js +266 -84
- package/src/adapters/bun/static-preview-host.js +25 -20
- package/src/adapters/create-app.d.ts +13 -11
- package/src/adapters/create-app.js +2 -51
- package/src/adapters/index.d.ts +1 -1
- package/src/adapters/index.js +1 -2
- package/src/adapters/node/create-app.d.ts +5 -1
- package/src/adapters/node/create-app.js +51 -12
- package/src/adapters/node/node-client-bridge.d.ts +1 -0
- package/src/adapters/node/node-client-bridge.js +3 -0
- package/src/adapters/node/server-adapter-dependencies.js +4 -0
- package/src/adapters/node/server-adapter.d.ts +62 -20
- package/src/adapters/node/server-adapter.js +160 -131
- package/src/adapters/node/static-content-server.d.ts +1 -0
- package/src/adapters/node/static-content-server.js +10 -2
- package/src/adapters/node/static-preview-host.js +27 -12
- package/src/adapters/shared/bun-user-websocket-lifecycle.d.ts +22 -0
- package/src/adapters/shared/bun-user-websocket-lifecycle.js +96 -0
- package/src/adapters/shared/copy-runtime-public-dir.d.ts +6 -0
- package/src/adapters/shared/copy-runtime-public-dir.js +24 -0
- package/src/adapters/shared/fs-server-response-matcher.d.ts +2 -0
- package/src/adapters/shared/fs-server-response-matcher.js +40 -18
- package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +21 -30
- package/src/adapters/shared/hmr-entrypoint-registrar.js +49 -54
- package/src/adapters/shared/hmr-html-response.d.ts +1 -1
- package/src/adapters/shared/hmr-html-response.js +4 -1
- package/src/adapters/shared/node-http-websocket-upgrades.d.ts +21 -0
- package/src/adapters/shared/node-http-websocket-upgrades.js +100 -0
- package/src/adapters/shared/port-manager.d.ts +116 -0
- package/src/adapters/shared/port-manager.js +196 -0
- package/src/adapters/shared/runtime-app-bootstrap.d.ts +2 -1
- package/src/adapters/shared/runtime-app-bootstrap.js +3 -6
- package/src/adapters/shared/runtime-server-lifecycle.d.ts +46 -0
- package/src/adapters/shared/runtime-server-lifecycle.js +50 -0
- package/src/adapters/shared/server-adapter.d.ts +2 -1
- package/src/adapters/shared/server-adapter.js +13 -6
- package/src/adapters/shared/server-route-handler.d.ts +4 -1
- package/src/adapters/shared/server-route-handler.js +5 -2
- package/src/adapters/shared/server-static-builder.d.ts +23 -32
- package/src/adapters/shared/server-static-builder.js +100 -73
- package/src/adapters/shared/shared-hmr-manager.d.ts +45 -11
- package/src/adapters/shared/shared-hmr-manager.js +204 -58
- package/src/adapters/shared/static-preview-host.d.ts +5 -0
- package/src/adapters/shared/websocket-lifecycle.d.ts +24 -0
- package/src/adapters/shared/websocket-lifecycle.js +55 -0
- package/src/build/README.md +77 -14
- package/src/build/app-build-manifest-runtime.d.ts +9 -0
- package/src/build/app-build-manifest-runtime.js +87 -0
- package/src/build/build-adapter.d.ts +17 -319
- package/src/build/build-adapter.js +28 -94
- package/src/build/build-contracts.d.ts +97 -0
- package/src/build/build-contracts.js +0 -0
- package/src/build/build-input-fingerprint.d.ts +28 -0
- package/src/build/build-input-fingerprint.js +31 -0
- package/src/build/build-profile-options.d.ts +7 -0
- package/src/build/build-profile-options.js +37 -0
- package/src/build/build-runtime.d.ts +24 -0
- package/src/build/build-runtime.js +65 -0
- package/src/build/deduping-build-executor.d.ts +28 -0
- package/src/build/deduping-build-executor.js +56 -0
- package/src/build/jsx-ownership-plugins.d.ts +24 -0
- package/src/build/jsx-ownership-plugins.js +41 -0
- package/src/build/pages-unified-graph-build.d.ts +31 -0
- package/src/build/pages-unified-graph-build.js +206 -0
- package/src/build/parallel-build-executor.d.ts +21 -0
- package/src/build/parallel-build-executor.js +52 -0
- package/src/build/production-build-cache.d.ts +20 -0
- package/src/build/production-build-cache.js +63 -0
- package/src/build/rolldown-adapter-helpers.d.ts +3 -6
- package/src/build/rolldown-adapter-helpers.js +71 -6
- package/src/build/rolldown-build-adapter.d.ts +2 -6
- package/src/build/rolldown-build-adapter.js +3 -3
- package/src/build/rolldown-build-invocation-metrics.d.ts +12 -0
- package/src/build/rolldown-build-invocation-metrics.js +43 -0
- package/src/build/rolldown-plugin-bridge.d.ts +15 -1
- package/src/build/rolldown-plugin-bridge.js +20 -5
- package/src/build/rolldown-source-transform-pass.d.ts +15 -0
- package/src/build/rolldown-source-transform-pass.js +58 -0
- package/src/build/runtime-build-executor.d.ts +8 -15
- package/src/build/runtime-build-executor.js +12 -15
- package/src/build/runtime-build-output-normalizer.d.ts +7 -0
- package/src/build/runtime-build-output-normalizer.js +94 -2
- package/src/build/server-entry-build-cache.d.ts +44 -0
- package/src/build/server-entry-build-cache.js +161 -0
- package/src/client/navigation-scripts/classification.d.ts +16 -0
- package/src/client/navigation-scripts/classification.js +41 -0
- package/src/client/navigation-scripts/index.d.ts +3 -0
- package/src/client/navigation-scripts/index.js +23 -0
- package/src/client/navigation-scripts/navigation-scripts.test.browser.js +65 -0
- package/src/client/navigation-scripts/registry.d.ts +11 -0
- package/src/client/navigation-scripts/registry.js +12 -0
- package/src/client/navigation-scripts/rerun-queue.d.ts +37 -0
- package/src/client/navigation-scripts/rerun-queue.js +73 -0
- package/src/client/scroll.d.ts +17 -0
- package/src/client/scroll.js +25 -0
- package/src/client/scroll.test.browser.js +37 -0
- package/src/client/view-transitions.d.ts +16 -0
- package/src/client/view-transitions.js +63 -0
- package/src/config/config-builder.d.ts +12 -7
- package/src/config/config-builder.js +12 -9
- package/src/dev/client-bridge-registry.d.ts +5 -0
- package/src/dev/client-bridge-registry.js +15 -0
- package/src/dev/dev-client-ownership.d.ts +7 -0
- package/src/dev/dev-client-ownership.js +6 -0
- package/src/dev/hmr-manager-registry.d.ts +8 -0
- package/src/dev/hmr-manager-registry.js +15 -0
- package/src/dev/host-runtime.d.ts +3 -0
- package/src/dev/host-runtime.js +7 -0
- package/src/dev/runtime-server-started-message.d.ts +2 -0
- package/src/dev/runtime-server-started-message.js +6 -0
- package/src/eco/README.md +11 -0
- package/src/eco/eco-declared-component.d.ts +14 -0
- package/src/eco/eco-declared-component.js +16 -0
- package/src/eco/eco.browser.js +5 -6
- package/src/eco/eco.js +5 -6
- package/src/eco/eco.types.d.ts +2 -2
- package/src/eco/page-layout-normalization.d.ts +21 -0
- package/src/eco/page-layout-normalization.js +59 -0
- package/src/errors/index.d.ts +1 -0
- package/src/errors/index.js +7 -1
- package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
- package/src/errors/undeclared-component-dependency-error.js +17 -0
- package/src/hmr/client/hmr-runtime.js +5 -2
- package/src/hmr/hmr-entrypoint-output.d.ts +43 -0
- package/src/hmr/hmr-entrypoint-output.js +53 -0
- package/src/hmr/hmr-strategy.d.ts +15 -0
- package/src/hmr/hmr-strategy.js +19 -0
- package/src/hmr/strategies/js-hmr-strategy.d.ts +3 -5
- package/src/hmr/strategies/js-hmr-strategy.js +67 -19
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
- package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +29 -0
- package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
- package/src/integrations/ghtml/ghtml-renderer.js +2 -51
- package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
- package/src/integrations/ghtml/ghtml.plugin.js +7 -14
- package/src/plugins/define-integration.d.ts +26 -0
- package/src/plugins/define-integration.js +19 -0
- package/src/plugins/eco-component-meta-plugin.js +5 -8
- package/src/plugins/foreign-jsx-override-plugin.js +4 -6
- package/src/plugins/integration-plugin.d.ts +19 -9
- package/src/plugins/integration-plugin.js +7 -4
- package/src/plugins/jsx-import-source.utils.d.ts +8 -0
- package/src/plugins/jsx-import-source.utils.js +26 -0
- package/src/plugins/processor.d.ts +19 -4
- package/src/plugins/processor.js +22 -4
- package/src/plugins/source-transform.d.ts +31 -0
- package/src/plugins/source-transform.js +23 -1
- package/src/route-renderer/GRAPH.md +8 -8
- package/src/route-renderer/README.md +30 -28
- package/src/route-renderer/orchestration/component-graph-collectors.d.ts +10 -0
- package/src/route-renderer/orchestration/component-graph-collectors.js +143 -0
- package/src/route-renderer/orchestration/component-graph.d.ts +36 -0
- package/src/route-renderer/orchestration/component-graph.js +98 -0
- package/src/route-renderer/orchestration/component-render-context.d.ts +3 -10
- package/src/route-renderer/orchestration/component-render-context.js +3 -1
- package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +1 -18
- package/src/route-renderer/orchestration/declared-ownership-graph.js +5 -31
- package/src/route-renderer/orchestration/document-shell-render.service.d.ts +90 -0
- package/src/route-renderer/orchestration/document-shell-render.service.js +120 -0
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +59 -29
- package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +164 -35
- package/src/route-renderer/orchestration/global-injector-assets.service.d.ts +7 -0
- package/src/route-renderer/orchestration/global-injector-assets.service.js +32 -0
- package/src/route-renderer/orchestration/integration-renderer.d.ts +18 -54
- package/src/route-renderer/orchestration/integration-renderer.js +113 -195
- package/src/route-renderer/orchestration/integration-route-render-adapter.d.ts +38 -0
- package/src/route-renderer/orchestration/integration-route-render-adapter.js +27 -0
- package/src/route-renderer/orchestration/layout-shell-props.service.d.ts +20 -0
- package/src/route-renderer/orchestration/layout-shell-props.service.js +31 -0
- package/src/route-renderer/orchestration/ownership-validation.service.d.ts +5 -0
- package/src/route-renderer/orchestration/ownership-validation.service.js +29 -1
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.d.ts +9 -0
- package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.js +7 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.d.ts +25 -0
- package/src/route-renderer/orchestration/page-browser-graph.service.js +174 -0
- package/src/route-renderer/orchestration/render-output.utils.d.ts +2 -0
- package/src/route-renderer/orchestration/render-output.utils.js +4 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.d.ts +17 -0
- package/src/route-renderer/orchestration/route-html-finalization.service.js +26 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.d.ts +26 -0
- package/src/route-renderer/orchestration/route-prepared-options.builder.js +54 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.d.ts +4 -0
- package/src/route-renderer/orchestration/route-prepared-options.utils.js +33 -0
- package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +8 -39
- package/src/route-renderer/orchestration/route-render-orchestrator.js +53 -461
- package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
- package/src/route-renderer/orchestration/string-markup-renderer.js +55 -0
- package/src/route-renderer/page-loading/component-dependency-collection.js +5 -2
- package/src/router/client/link-intent.d.ts +11 -21
- package/src/router/client/link-intent.js +10 -0
- package/src/router/client/link-intent.test.browser.js +12 -1
- package/src/router/client/link-navigation-policy.d.ts +45 -0
- package/src/router/client/link-navigation-policy.js +101 -0
- package/src/router/client/link-navigation-policy.test.browser.d.ts +1 -0
- package/src/router/client/link-navigation-policy.test.browser.js +92 -0
- package/src/router/client/navigation-coordinator.d.ts +1 -1
- package/src/router/client/navigation-coordinator.js +12 -2
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +1 -0
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
- package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +27 -7
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.d.ts +0 -1
- package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +18 -15
- package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +17 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -31
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
- package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +2 -30
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
- package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +43 -0
- package/src/services/assets/browser-bundle.service.d.ts +3 -1
- package/src/services/assets/browser-bundle.service.js +17 -5
- package/src/services/html/html-transformer.service.d.ts +1 -1
- package/src/services/html/html-transformer.service.js +4 -4
- package/src/services/invalidation/development-invalidation.service.d.ts +20 -2
- package/src/services/invalidation/development-invalidation.service.js +56 -2
- package/src/services/module-loading/README.md +49 -0
- package/src/services/module-loading/app-server-module-transpiler.service.js +5 -17
- package/src/services/module-loading/page-module-import.service.d.ts +5 -1
- package/src/services/module-loading/page-module-import.service.js +96 -45
- package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
- package/src/services/module-loading/route-module-build-cache-registry.js +37 -0
- package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
- package/src/services/module-loading/route-module-build-cache.js +38 -0
- package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
- package/src/services/module-loading/route-module-build-cache.store.js +207 -0
- package/src/services/module-loading/route-module-build-manifest.d.ts +61 -0
- package/src/services/module-loading/route-module-build-manifest.js +116 -0
- package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
- package/src/services/module-loading/route-module-dependency-hasher.js +122 -0
- package/src/services/module-loading/server-module-transpiler.service.js +1 -1
- package/src/static-site-generator/README.md +33 -0
- package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
- package/src/static-site-generator/static-build-invalidation.js +59 -0
- package/src/static-site-generator/static-export-context.d.ts +22 -0
- package/src/static-site-generator/static-export-context.js +0 -0
- package/src/static-site-generator/static-site-generator.d.ts +17 -20
- package/src/static-site-generator/static-site-generator.js +188 -85
- package/src/types/internal-types.d.ts +16 -9
- package/src/types/public-types.d.ts +144 -40
- package/src/utils/parse-cli-args.d.ts +2 -0
- package/src/utils/parse-cli-args.js +6 -0
- package/src/utils/server-utils.module.d.ts +3 -2
- package/src/utils/server-utils.module.js +5 -6
- package/src/utils/static-file-extensions.d.ts +12 -0
- package/src/utils/static-file-extensions.js +48 -0
- package/src/watchers/project-watcher-ignore.d.ts +11 -0
- package/src/watchers/project-watcher-ignore.js +16 -0
- package/src/watchers/project-watcher.d.ts +26 -3
- package/src/watchers/project-watcher.js +132 -30
- package/src/watchers/project-watcher.test-helpers.js +5 -5
- package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
- package/src/build/rolldown-dev-build-adapter.js +0 -166
- package/src/hmr/hmr.postcss.test.e2e.js +0 -31
- package/src/hmr/hmr.test.e2e.js +0 -43
- package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
- package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
- package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
- /package/src/{hmr/hmr.postcss.test.e2e.d.ts → client/navigation-scripts/navigation-scripts.test.browser.d.ts} +0 -0
- /package/src/{hmr/hmr.test.e2e.d.ts → client/scroll.test.browser.d.ts} +0 -0
|
@@ -16,18 +16,30 @@ The route renderer layer is responsible for:
|
|
|
16
16
|
|
|
17
17
|
The architecture is organized around three distinct concepts:
|
|
18
18
|
|
|
19
|
-
- `ownership`:
|
|
19
|
+
- `ownership`: declared component dependency metadata validated before render
|
|
20
20
|
- `foreign child`: a component encountered during render whose owning integration differs from the current integration
|
|
21
21
|
- `foreign subtree`: the resolved HTML, assets, and root-attachment metadata returned by the owning renderer for that foreign child
|
|
22
22
|
|
|
23
23
|
These concepts intentionally live in different places:
|
|
24
24
|
|
|
25
|
-
- `ownership-
|
|
26
|
-
- `ownership-validation.service.ts` validates declared foreign ownership up front
|
|
25
|
+
- `ownership-validation.service.ts` validates declared foreign ownership up front and fails the render on misconfiguration
|
|
27
26
|
- `component-render-context.ts` intercepts foreign children during active component render
|
|
28
|
-
- `
|
|
29
|
-
- `
|
|
30
|
-
- `
|
|
27
|
+
- `foreign-subtree-execution.service.ts` owns mixed-integration execution policy and queued token resolution
|
|
28
|
+
- `document-shell-render.service.ts` composes page, layout, and html template shells with one execution-scoped renderer cache
|
|
29
|
+
- `integration-renderer.ts` owns renderer-to-renderer delegation and integration-specific render hooks
|
|
30
|
+
- `route-render-orchestrator.ts` owns route preparation, final response capture, and unresolved artifact enforcement
|
|
31
|
+
|
|
32
|
+
## Build-Time JSX vs Runtime Foreign Children
|
|
33
|
+
|
|
34
|
+
Mixed-integration apps use two separate mechanisms:
|
|
35
|
+
|
|
36
|
+
| Layer | Mechanism | Purpose |
|
|
37
|
+
| ------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
|
38
|
+
| Build | `getJsxOwnershipPlugins()` / `getHostScopedJsxOwnershipPlugins()` | Prepend `@jsxImportSource` so bundled `.tsx` files compile with the correct JSX runtime |
|
|
39
|
+
| Build | `eco-component-meta-plugin` | Prepends the owning integration pragma when injecting `__eco` metadata into native files |
|
|
40
|
+
| Runtime | `eco.component()` / `eco.embed()` + foreign-child runtime | Hand off cross-integration children during SSR |
|
|
41
|
+
|
|
42
|
+
See [`../build/README.md`](../build/README.md) for the JSX ownership helper split.
|
|
31
43
|
|
|
32
44
|
## Main Files
|
|
33
45
|
|
|
@@ -38,12 +50,12 @@ These concepts intentionally live in different places:
|
|
|
38
50
|
|
|
39
51
|
### `orchestration/`
|
|
40
52
|
|
|
41
|
-
- `route-render-
|
|
53
|
+
- `route-render-orchestrator.ts`: one route render from page-module loading through final HTML output
|
|
42
54
|
- `integration-renderer.ts`: abstract base class for route rendering, explicit view rendering, and foreign-child delegation
|
|
43
|
-
- `ownership-planning.service.ts`: declared ownership graph construction
|
|
44
55
|
- `ownership-validation.service.ts`: up-front ownership validation for route roots and declared descendants
|
|
56
|
+
- `foreign-subtree-execution.service.ts`: foreign-child execution policy, queue token resolution, and `toForeignSubtreeRenderPayload()`
|
|
57
|
+
- `document-shell-render.service.ts`: shared page/layout/html shell composition and attribute stamping helpers
|
|
45
58
|
- `component-render-context.ts`: active render context used by `eco.component()` to intercept foreign children
|
|
46
|
-
- `queued-foreign-subtree-resolution.service.ts`: queue resolution for renderers that need token-based foreign-subtree handoff
|
|
47
59
|
- `render-output.utils.ts`: unresolved artifact normalization and marker inspection
|
|
48
60
|
|
|
49
61
|
### `page-loading/`
|
|
@@ -56,11 +68,11 @@ These concepts intentionally live in different places:
|
|
|
56
68
|
The route-render contract is:
|
|
57
69
|
|
|
58
70
|
1. `RouteRendererFactory` selects the owning integration renderer.
|
|
59
|
-
2. `IntegrationRenderer.execute()` delegates preparation and finalization to `
|
|
60
|
-
3. `
|
|
71
|
+
2. `IntegrationRenderer.execute()` delegates preparation and finalization to `RouteRenderOrchestrator`.
|
|
72
|
+
3. `RouteRenderOrchestrator.prepareRenderOptions()` loads the page module, validates ownership (fail-fast), resolves page data, resolves dependencies, and builds the page browser graph.
|
|
61
73
|
4. The integration renderer performs page, layout, and document-shell rendering. When it encounters a foreign child, it delegates that child back to the owning renderer.
|
|
62
74
|
5. If a renderer needs queued handoff, it emits internal foreign-subtree tokens and resolves them before returning final HTML.
|
|
63
|
-
6. `
|
|
75
|
+
6. `RouteRenderOrchestrator.executePrepared()` captures the final body, rejects unresolved `<eco-marker>` artifacts, stamps root or document attributes when needed, and runs the HTML transformer.
|
|
64
76
|
|
|
65
77
|
Important:
|
|
66
78
|
|
|
@@ -72,38 +84,28 @@ Important:
|
|
|
72
84
|
|
|
73
85
|
Mixed-integration component configs must declare every possible foreign child in `config.dependencies.components`.
|
|
74
86
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
- `OwnershipValidationService` surfaces missing metadata or unknown integrations before render execution
|
|
78
|
-
- `OwnershipPlanningService` records the expected ownership shape in `ownershipPlan`
|
|
87
|
+
`OwnershipValidationService` surfaces missing metadata or unknown integrations during `prepareRenderOptions()` and throws before render execution starts.
|
|
79
88
|
|
|
80
89
|
At runtime, renderers still discover actual foreign children through the active component render context.
|
|
81
90
|
|
|
82
91
|
## Foreign Subtree Contract
|
|
83
92
|
|
|
84
|
-
`
|
|
85
|
-
|
|
86
|
-
- `html`
|
|
87
|
-
- `assets`
|
|
88
|
-
- `rootTag`
|
|
89
|
-
- optional `rootAttributes`
|
|
90
|
-
- `attachmentPolicy`
|
|
91
|
-
- `integrationName`
|
|
92
|
-
|
|
93
|
-
`renderComponentWithForeignChildren()` is the higher-level renderer entrypoint. It is responsible for:
|
|
93
|
+
`renderComponentWithForeignChildren()` is the renderer entrypoint for mixed-integration trees. It is responsible for:
|
|
94
94
|
|
|
95
95
|
- reusing the execution-scoped owning-renderer cache
|
|
96
96
|
- deciding whether the current component can stay local
|
|
97
97
|
- creating a foreign-child runtime when nested foreign ownership must be resolved
|
|
98
98
|
- normalizing unresolved artifact HTML before the render leaves the renderer
|
|
99
99
|
|
|
100
|
+
Queue resolution maps owning-renderer output into the foreign-subtree payload shape via `toForeignSubtreeRenderPayload()` inside `foreign-subtree-execution.service.ts`.
|
|
101
|
+
|
|
100
102
|
## Queue Model
|
|
101
103
|
|
|
102
104
|
Not every integration needs queue-based handoff.
|
|
103
105
|
|
|
104
106
|
- If a renderer can resolve a foreign child inline, it returns resolved output immediately.
|
|
105
107
|
- If it cannot, it may emit internal foreign-subtree tokens and resolve them before returning final HTML.
|
|
106
|
-
-
|
|
108
|
+
- Queue mechanics live inside `ForeignSubtreeExecutionService`; they are renderer-owned transport inside one render pass, not a general route-level fallback mechanism.
|
|
107
109
|
|
|
108
110
|
## React Island Notes
|
|
109
111
|
|
|
@@ -114,5 +116,5 @@ Not every integration needs queue-based handoff.
|
|
|
114
116
|
|
|
115
117
|
## Current Limits
|
|
116
118
|
|
|
117
|
-
- `ownershipPlan` is still diagnostic and preparatory metadata; it does not yet drive a full route-composer execution model.
|
|
118
119
|
- Different integrations still own different foreign-child runtime strategies, which is intentional where child transport or hydration behavior differs.
|
|
120
|
+
- `integration-renderer.ts` remains the largest integration hook surface even after document-shell extraction.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EcoPagesAppConfig } from '../../types/internal-types.js';
|
|
2
|
+
import type { EcoComponent, ResolvedLazyTrigger } from '../../types/public-types.js';
|
|
3
|
+
import type { AssetDefinition } from '../../services/assets/asset-processing-service/index.js';
|
|
4
|
+
import type { AssetProcessingService, ProcessedAsset } from '../../services/assets/asset-processing-service/index.js';
|
|
5
|
+
export declare function collectIntegrationNamesFromGraph(components: (EcoComponent | Partial<EcoComponent>)[], currentIntegrationName: string): Set<string>;
|
|
6
|
+
export declare function collectResolvedLazyTriggersFromGraph(components: (EcoComponent | Partial<EcoComponent>)[], currentIntegrationName: string): ResolvedLazyTrigger[];
|
|
7
|
+
export declare function hasForeignChildDescendantsInGraph(component: EcoComponent, currentIntegrationName: string): boolean;
|
|
8
|
+
export declare function collectEagerSsrLazyScriptDefinitions(components: (EcoComponent | Partial<EcoComponent>)[]): AssetDefinition[];
|
|
9
|
+
export declare function collectUsedIntegrationDependenciesFromGraph(appConfig: EcoPagesAppConfig, components: (EcoComponent | Partial<EcoComponent>)[], currentIntegrationName: string): ProcessedAsset[];
|
|
10
|
+
export declare function buildEagerSsrLazyAssetsFromGraph(assetProcessingService: AssetProcessingService, components: (EcoComponent | Partial<EcoComponent>)[], currentIntegrationName: string): Promise<ProcessedAsset[]>;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { AssetFactory } from "../../services/assets/asset-processing-service/index.js";
|
|
3
|
+
import { walkComponentGraph } from "./component-graph.js";
|
|
4
|
+
function toGraphRoots(components) {
|
|
5
|
+
return components.filter(Boolean).map((component) => ({ component }));
|
|
6
|
+
}
|
|
7
|
+
function collectIntegrationNamesFromGraph(components, currentIntegrationName) {
|
|
8
|
+
const integrationNames = /* @__PURE__ */ new Set();
|
|
9
|
+
walkComponentGraph({
|
|
10
|
+
roots: toGraphRoots(components),
|
|
11
|
+
currentIntegrationName,
|
|
12
|
+
onComponent: ({ component }) => {
|
|
13
|
+
const integrationName = component.config?.integration ?? component.config?.__eco?.integration;
|
|
14
|
+
if (integrationName) {
|
|
15
|
+
integrationNames.add(integrationName);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
return integrationNames;
|
|
20
|
+
}
|
|
21
|
+
function collectResolvedLazyTriggersFromGraph(components, currentIntegrationName) {
|
|
22
|
+
const triggers = [];
|
|
23
|
+
walkComponentGraph({
|
|
24
|
+
roots: toGraphRoots(components),
|
|
25
|
+
currentIntegrationName,
|
|
26
|
+
onComponent: ({ component }) => {
|
|
27
|
+
const ownTriggers = component.config?._resolvedLazyTriggers;
|
|
28
|
+
if (ownTriggers?.length) {
|
|
29
|
+
triggers.push(...ownTriggers);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return triggers;
|
|
34
|
+
}
|
|
35
|
+
function hasForeignChildDescendantsInGraph(component, currentIntegrationName) {
|
|
36
|
+
let foundForeign = false;
|
|
37
|
+
walkComponentGraph({
|
|
38
|
+
roots: [{ component }],
|
|
39
|
+
currentIntegrationName,
|
|
40
|
+
onComponent: ({ component: currentComponent }) => {
|
|
41
|
+
if (foundForeign) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
const integrationName = currentComponent.config?.integration ?? currentComponent.config?.__eco?.integration;
|
|
45
|
+
if (integrationName && integrationName !== currentIntegrationName) {
|
|
46
|
+
foundForeign = true;
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return foundForeign;
|
|
52
|
+
}
|
|
53
|
+
function collectEagerSsrLazyScriptDefinitions(components) {
|
|
54
|
+
const dependencies = [];
|
|
55
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
56
|
+
const normalizeAttributes = (attributes) => ({
|
|
57
|
+
type: "module",
|
|
58
|
+
defer: "",
|
|
59
|
+
...attributes ?? {}
|
|
60
|
+
});
|
|
61
|
+
walkComponentGraph({
|
|
62
|
+
roots: toGraphRoots(components),
|
|
63
|
+
currentIntegrationName: "",
|
|
64
|
+
visitLayout: true,
|
|
65
|
+
onConfig: (config) => {
|
|
66
|
+
const componentFile = config?.__eco?.file;
|
|
67
|
+
if (!componentFile) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const componentDir = path.dirname(componentFile);
|
|
71
|
+
for (const script of config.dependencies?.scripts ?? []) {
|
|
72
|
+
if (typeof script === "string" || !script.lazy || script.ssr !== true) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const attributes = normalizeAttributes(script.attributes);
|
|
76
|
+
if (script.content) {
|
|
77
|
+
const key2 = `content:${script.content}:${JSON.stringify(attributes)}`;
|
|
78
|
+
if (seenKeys.has(key2)) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
seenKeys.add(key2);
|
|
82
|
+
dependencies.push(
|
|
83
|
+
AssetFactory.createContentScript({
|
|
84
|
+
position: "head",
|
|
85
|
+
content: script.content,
|
|
86
|
+
attributes,
|
|
87
|
+
packageRole: "dynamic-chunk"
|
|
88
|
+
})
|
|
89
|
+
);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!script.src) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const resolvedPath = path.resolve(componentDir, script.src);
|
|
96
|
+
const key = `file:${resolvedPath}:${JSON.stringify(attributes)}`;
|
|
97
|
+
if (seenKeys.has(key)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
seenKeys.add(key);
|
|
101
|
+
dependencies.push(
|
|
102
|
+
AssetFactory.createFileScript({
|
|
103
|
+
filepath: resolvedPath,
|
|
104
|
+
position: "head",
|
|
105
|
+
attributes,
|
|
106
|
+
packageRole: "dynamic-chunk"
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
return dependencies;
|
|
113
|
+
}
|
|
114
|
+
function collectUsedIntegrationDependenciesFromGraph(appConfig, components, currentIntegrationName) {
|
|
115
|
+
const integrationNames = collectIntegrationNamesFromGraph(components, currentIntegrationName);
|
|
116
|
+
const dependencies = [];
|
|
117
|
+
for (const integrationName of integrationNames) {
|
|
118
|
+
if (integrationName === currentIntegrationName) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const integrationPlugin = appConfig.integrations.find((integration) => integration.name === integrationName);
|
|
122
|
+
if (!integrationPlugin || typeof integrationPlugin.getResolvedIntegrationDependencies !== "function") {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
dependencies.push(...integrationPlugin.getResolvedIntegrationDependencies());
|
|
126
|
+
}
|
|
127
|
+
return dependencies;
|
|
128
|
+
}
|
|
129
|
+
async function buildEagerSsrLazyAssetsFromGraph(assetProcessingService, components, currentIntegrationName) {
|
|
130
|
+
const dependencies = collectEagerSsrLazyScriptDefinitions(components);
|
|
131
|
+
if (dependencies.length === 0) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
return assetProcessingService.processDependencies(dependencies, `${currentIntegrationName}:ssr-lazy`);
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
buildEagerSsrLazyAssetsFromGraph,
|
|
138
|
+
collectEagerSsrLazyScriptDefinitions,
|
|
139
|
+
collectIntegrationNamesFromGraph,
|
|
140
|
+
collectResolvedLazyTriggersFromGraph,
|
|
141
|
+
collectUsedIntegrationDependenciesFromGraph,
|
|
142
|
+
hasForeignChildDescendantsInGraph
|
|
143
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EcoComponent, OwnershipPlanNodeSource } from '../../types/public-types.js';
|
|
2
|
+
export type DeclaredOwnershipRoot = {
|
|
3
|
+
component: EcoComponent;
|
|
4
|
+
source: Extract<OwnershipPlanNodeSource, 'page' | 'layout' | 'html-template'>;
|
|
5
|
+
};
|
|
6
|
+
export type DeclaredOwnershipNodeInput = {
|
|
7
|
+
component: EcoComponent;
|
|
8
|
+
source: Exclude<OwnershipPlanNodeSource, 'route'>;
|
|
9
|
+
parentIntegrationName: string;
|
|
10
|
+
integrationName: string;
|
|
11
|
+
componentId: string;
|
|
12
|
+
isForeignToParent: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type ComponentGraphRoot = {
|
|
15
|
+
component: EcoComponent | Partial<EcoComponent>;
|
|
16
|
+
source?: Exclude<OwnershipPlanNodeSource, 'route'>;
|
|
17
|
+
};
|
|
18
|
+
export type ComponentGraphWalkInput = {
|
|
19
|
+
component: EcoComponent;
|
|
20
|
+
parentIntegrationName: string;
|
|
21
|
+
source?: Exclude<OwnershipPlanNodeSource, 'route'>;
|
|
22
|
+
};
|
|
23
|
+
export declare function walkComponentGraph(input: {
|
|
24
|
+
roots: ComponentGraphRoot[];
|
|
25
|
+
currentIntegrationName: string;
|
|
26
|
+
visitLayout?: boolean;
|
|
27
|
+
onComponent?: (node: ComponentGraphWalkInput) => void | boolean;
|
|
28
|
+
onConfig?: (config: EcoComponent['config']) => void;
|
|
29
|
+
}): void;
|
|
30
|
+
export declare function mapComponentGraph<T>(input: {
|
|
31
|
+
roots: DeclaredOwnershipRoot[];
|
|
32
|
+
currentIntegrationName: string;
|
|
33
|
+
mapNode: (node: DeclaredOwnershipNodeInput, children: T[]) => T;
|
|
34
|
+
}): T[];
|
|
35
|
+
/** @deprecated Use `mapComponentGraph` from `component-graph.ts`. */
|
|
36
|
+
export declare const mapDeclaredOwnershipGraph: typeof mapComponentGraph;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
function walkComponentGraph(input) {
|
|
2
|
+
const seenComponents = /* @__PURE__ */ new Set();
|
|
3
|
+
const seenConfigs = /* @__PURE__ */ new Set();
|
|
4
|
+
const visitComponent = (component, parentIntegrationName, source) => {
|
|
5
|
+
if (!component) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const ecoComponent = component;
|
|
9
|
+
if (seenComponents.has(ecoComponent)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
seenComponents.add(ecoComponent);
|
|
13
|
+
const integrationName = ecoComponent.config?.integration ?? ecoComponent.config?.__eco?.integration ?? parentIntegrationName;
|
|
14
|
+
if (input.onConfig && ecoComponent.config && !seenConfigs.has(ecoComponent.config)) {
|
|
15
|
+
seenConfigs.add(ecoComponent.config);
|
|
16
|
+
input.onConfig(ecoComponent.config);
|
|
17
|
+
}
|
|
18
|
+
if (input.onComponent) {
|
|
19
|
+
const shouldContinue = input.onComponent({
|
|
20
|
+
component: ecoComponent,
|
|
21
|
+
parentIntegrationName,
|
|
22
|
+
source
|
|
23
|
+
});
|
|
24
|
+
if (shouldContinue === false) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (input.visitLayout) {
|
|
29
|
+
for (const layout of ecoComponent.config?.layouts ?? []) {
|
|
30
|
+
if (layout?.config) {
|
|
31
|
+
visitConfig(layout.config, integrationName);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
for (const child of ecoComponent.config?.dependencies?.components ?? []) {
|
|
36
|
+
visitComponent(child, integrationName, "dependency");
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const visitConfig = (config, parentIntegrationName) => {
|
|
40
|
+
if (!config || seenConfigs.has(config)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
seenConfigs.add(config);
|
|
44
|
+
if (input.onConfig) {
|
|
45
|
+
input.onConfig(config);
|
|
46
|
+
}
|
|
47
|
+
if (input.visitLayout) {
|
|
48
|
+
for (const layout of config.layouts ?? []) {
|
|
49
|
+
if (layout?.config) {
|
|
50
|
+
visitConfig(layout.config, parentIntegrationName);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const child of config.dependencies?.components ?? []) {
|
|
55
|
+
visitComponent(child, parentIntegrationName, "dependency");
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
for (const root of input.roots) {
|
|
59
|
+
visitComponent(root.component, input.currentIntegrationName, root.source);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function mapComponentGraph(input) {
|
|
63
|
+
let nextSyntheticId = 0;
|
|
64
|
+
const mapComponent = (component, source, parentIntegrationName, lineage) => {
|
|
65
|
+
const integrationName = component.config?.integration ?? component.config?.__eco?.integration ?? parentIntegrationName;
|
|
66
|
+
const componentMeta = component.config?.__eco;
|
|
67
|
+
const isForeignToParent = integrationName !== parentIntegrationName;
|
|
68
|
+
const componentId = componentMeta?.id ?? componentMeta?.file ?? `${source}:${nextSyntheticId += 1}`;
|
|
69
|
+
const nextLineage = new Set(lineage);
|
|
70
|
+
nextLineage.add(component);
|
|
71
|
+
const children = (component.config?.dependencies?.components ?? []).flatMap((child) => {
|
|
72
|
+
if (!child || nextLineage.has(child)) {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
return [mapComponent(child, "dependency", integrationName, nextLineage)];
|
|
76
|
+
});
|
|
77
|
+
return input.mapNode(
|
|
78
|
+
{
|
|
79
|
+
component,
|
|
80
|
+
source,
|
|
81
|
+
parentIntegrationName,
|
|
82
|
+
integrationName,
|
|
83
|
+
componentId,
|
|
84
|
+
isForeignToParent
|
|
85
|
+
},
|
|
86
|
+
children
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
return input.roots.map(
|
|
90
|
+
({ component, source }) => mapComponent(component, source, input.currentIntegrationName, /* @__PURE__ */ new Set())
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const mapDeclaredOwnershipGraph = mapComponentGraph;
|
|
94
|
+
export {
|
|
95
|
+
mapComponentGraph,
|
|
96
|
+
mapDeclaredOwnershipGraph,
|
|
97
|
+
walkComponentGraph
|
|
98
|
+
};
|
|
@@ -12,13 +12,6 @@ export type ForeignChildInterceptionResult = {
|
|
|
12
12
|
} | {
|
|
13
13
|
kind: 'resolved';
|
|
14
14
|
value: unknown;
|
|
15
|
-
};
|
|
16
|
-
export type ForeignChildRenderInterception = {
|
|
17
|
-
kind: 'inline';
|
|
18
|
-
props?: Record<string, unknown>;
|
|
19
|
-
} | {
|
|
20
|
-
kind: 'resolved';
|
|
21
|
-
value: unknown;
|
|
22
15
|
} | undefined;
|
|
23
16
|
/**
|
|
24
17
|
* Foreign-child metadata passed into the active renderer-owned runtime.
|
|
@@ -44,7 +37,7 @@ export interface ForeignChildRuntime {
|
|
|
44
37
|
* which decides whether the child stays inline or leaves the current renderer.
|
|
45
38
|
*/
|
|
46
39
|
interceptForeignChild?(input: ForeignChildInterceptionInput): ForeignChildInterceptionResult | Promise<ForeignChildInterceptionResult>;
|
|
47
|
-
interceptForeignChildSync?(input: ForeignChildInterceptionInput): ForeignChildInterceptionResult
|
|
40
|
+
interceptForeignChildSync?(input: ForeignChildInterceptionInput): Exclude<ForeignChildInterceptionResult, undefined>;
|
|
48
41
|
}
|
|
49
42
|
type ForeignChildRenderInput = {
|
|
50
43
|
component: EcoComponent;
|
|
@@ -58,7 +51,7 @@ type ForeignChildRenderInput = {
|
|
|
58
51
|
export type ComponentRenderContext = {
|
|
59
52
|
currentIntegration: string;
|
|
60
53
|
foreignChildRuntime?: ForeignChildRuntime;
|
|
61
|
-
interceptForeignChild(input: ForeignChildRenderInput): Promise<
|
|
54
|
+
interceptForeignChild(input: ForeignChildRenderInput): Promise<ForeignChildInterceptionResult> | ForeignChildInterceptionResult;
|
|
62
55
|
finalizeComponentRender<T>(component: EcoComponent, content: T): T;
|
|
63
56
|
};
|
|
64
57
|
/**
|
|
@@ -72,7 +65,7 @@ export declare function getComponentRenderContext(): ComponentRenderContext | un
|
|
|
72
65
|
*
|
|
73
66
|
* The active runtime may resolve the foreign child immediately or keep it inline.
|
|
74
67
|
*/
|
|
75
|
-
export declare function interceptForeignChild(input: ForeignChildRenderInput): Promise<
|
|
68
|
+
export declare function interceptForeignChild(input: ForeignChildRenderInput): Promise<ForeignChildInterceptionResult> | ForeignChildInterceptionResult;
|
|
76
69
|
/**
|
|
77
70
|
* Applies lazy trigger or injector wrapping to completed component output.
|
|
78
71
|
*
|
|
@@ -51,7 +51,9 @@ class ContextualComponentRenderRuntime extends ComponentRenderOutputRuntime {
|
|
|
51
51
|
const asyncInterception = this.context.foreignChildRuntime?.interceptForeignChild?.(foreignChildRuntimeInput);
|
|
52
52
|
if (asyncInterception !== void 0) {
|
|
53
53
|
if (isThenable(asyncInterception)) {
|
|
54
|
-
return asyncInterception.then(
|
|
54
|
+
return asyncInterception.then(
|
|
55
|
+
(result) => result === void 0 ? void 0 : this.applyForeignChildInterceptionResult(result)
|
|
56
|
+
);
|
|
55
57
|
}
|
|
56
58
|
return this.applyForeignChildInterceptionResult(asyncInterception);
|
|
57
59
|
}
|
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export type DeclaredOwnershipRoot = {
|
|
3
|
-
component: EcoComponent;
|
|
4
|
-
source: Extract<OwnershipPlanNodeSource, 'page' | 'layout' | 'html-template'>;
|
|
5
|
-
};
|
|
6
|
-
export type DeclaredOwnershipNodeInput = {
|
|
7
|
-
component: EcoComponent;
|
|
8
|
-
source: Exclude<OwnershipPlanNodeSource, 'route'>;
|
|
9
|
-
parentIntegrationName: string;
|
|
10
|
-
integrationName: string;
|
|
11
|
-
componentId: string;
|
|
12
|
-
isForeignToParent: boolean;
|
|
13
|
-
};
|
|
14
|
-
export declare function mapDeclaredOwnershipGraph<T>(input: {
|
|
15
|
-
roots: DeclaredOwnershipRoot[];
|
|
16
|
-
currentIntegrationName: string;
|
|
17
|
-
mapNode: (node: DeclaredOwnershipNodeInput, children: T[]) => T;
|
|
18
|
-
}): T[];
|
|
1
|
+
export { mapComponentGraph, mapDeclaredOwnershipGraph, type ComponentGraphRoot, type ComponentGraphWalkInput, type DeclaredOwnershipNodeInput, type DeclaredOwnershipRoot, } from './component-graph.js';
|
|
@@ -1,34 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const componentMeta = component.config?.__eco;
|
|
6
|
-
const isForeignToParent = integrationName !== parentIntegrationName;
|
|
7
|
-
const componentId = componentMeta?.id ?? componentMeta?.file ?? `${source}:${nextSyntheticId += 1}`;
|
|
8
|
-
const nextLineage = new Set(lineage);
|
|
9
|
-
nextLineage.add(component);
|
|
10
|
-
const children = (component.config?.dependencies?.components ?? []).flatMap((child) => {
|
|
11
|
-
if (!child || nextLineage.has(child)) {
|
|
12
|
-
return [];
|
|
13
|
-
}
|
|
14
|
-
return [mapComponent(child, "dependency", integrationName, nextLineage)];
|
|
15
|
-
});
|
|
16
|
-
return input.mapNode(
|
|
17
|
-
{
|
|
18
|
-
component,
|
|
19
|
-
source,
|
|
20
|
-
parentIntegrationName,
|
|
21
|
-
integrationName,
|
|
22
|
-
componentId,
|
|
23
|
-
isForeignToParent
|
|
24
|
-
},
|
|
25
|
-
children
|
|
26
|
-
);
|
|
27
|
-
};
|
|
28
|
-
return input.roots.map(
|
|
29
|
-
({ component, source }) => mapComponent(component, source, input.currentIntegrationName, /* @__PURE__ */ new Set())
|
|
30
|
-
);
|
|
31
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
mapComponentGraph,
|
|
3
|
+
mapDeclaredOwnershipGraph
|
|
4
|
+
} from "./component-graph.js";
|
|
32
5
|
export {
|
|
6
|
+
mapComponentGraph,
|
|
33
7
|
mapDeclaredOwnershipGraph
|
|
34
8
|
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { BaseIntegrationContext, ComponentRenderInput, ComponentRenderResult, EcoComponent, PageMetadataProps } from '../../types/public-types.js';
|
|
2
|
+
import type { ProcessedAsset } from '../../services/assets/asset-processing-service/index.js';
|
|
3
|
+
export type DocumentShellLayoutInput = {
|
|
4
|
+
component: EcoComponent;
|
|
5
|
+
props?: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
export type DocumentShellComposeChildrenContext = {
|
|
8
|
+
primaryComponent: EcoComponent;
|
|
9
|
+
primaryProps: Record<string, unknown>;
|
|
10
|
+
primaryRender?: ComponentRenderResult;
|
|
11
|
+
layouts: DocumentShellLayoutInput[];
|
|
12
|
+
rendererCache: BaseIntegrationContext['rendererCache'];
|
|
13
|
+
renderComponentWithForeignChildren: DocumentShellRenderDependencies['renderComponentWithForeignChildren'];
|
|
14
|
+
};
|
|
15
|
+
export type DocumentShellComposeChildrenResult = {
|
|
16
|
+
/** Serialized or element children passed to the HTML template shell. */
|
|
17
|
+
children: unknown;
|
|
18
|
+
layoutRenders: ComponentRenderResult[];
|
|
19
|
+
/**
|
|
20
|
+
* Primary/page render assets when the hook performs unified composition.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* Omit only when the default sequential string path runs (core renders primary first).
|
|
24
|
+
*/
|
|
25
|
+
primaryRender?: ComponentRenderResult;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Optional hook that replaces default sequential string layout wrapping.
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* When provided, core skips the initial primary render and expects the hook to return
|
|
32
|
+
* `children` for the HTML template. Supply `primaryRender` so dependency assets still merge.
|
|
33
|
+
*/
|
|
34
|
+
export type DocumentShellComposeChildrenHook = (context: DocumentShellComposeChildrenContext) => Promise<DocumentShellComposeChildrenResult>;
|
|
35
|
+
export type DocumentShellComposeInput = {
|
|
36
|
+
primaryComponent: EcoComponent;
|
|
37
|
+
primaryProps: Record<string, unknown>;
|
|
38
|
+
layout?: DocumentShellLayoutInput;
|
|
39
|
+
layouts?: DocumentShellLayoutInput[];
|
|
40
|
+
composeChildren?: DocumentShellComposeChildrenHook;
|
|
41
|
+
htmlTemplate: EcoComponent;
|
|
42
|
+
documentProps: Record<string, unknown>;
|
|
43
|
+
};
|
|
44
|
+
export type DocumentShellPageRenderInput = {
|
|
45
|
+
page: {
|
|
46
|
+
component: EcoComponent;
|
|
47
|
+
props: Record<string, unknown>;
|
|
48
|
+
};
|
|
49
|
+
layout?: DocumentShellLayoutInput;
|
|
50
|
+
layouts?: DocumentShellLayoutInput[];
|
|
51
|
+
composeChildren?: DocumentShellComposeChildrenHook;
|
|
52
|
+
htmlTemplate: EcoComponent;
|
|
53
|
+
metadata: PageMetadataProps;
|
|
54
|
+
pageProps: Record<string, unknown>;
|
|
55
|
+
documentProps?: Record<string, unknown>;
|
|
56
|
+
transformDocumentHtml?: (html: string) => string;
|
|
57
|
+
};
|
|
58
|
+
export type DocumentShellRenderDependencies = {
|
|
59
|
+
renderComponentWithForeignChildren(input: ComponentRenderInput): Promise<ComponentRenderResult>;
|
|
60
|
+
appendProcessedDependencies(...assetGroups: Array<readonly ProcessedAsset[] | undefined>): ProcessedAsset[];
|
|
61
|
+
};
|
|
62
|
+
export type DocumentShellAttributeStamping = {
|
|
63
|
+
applyAttributesToFirstBodyElement(html: string, attributes: Record<string, string>): string;
|
|
64
|
+
applyAttributesToHtmlElement(html: string, attributes: Record<string, string>): string;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Default sequential string-child composition for document shell layers.
|
|
68
|
+
*/
|
|
69
|
+
export declare function composeSequentialLayoutChildren(context: DocumentShellComposeChildrenContext): Promise<DocumentShellComposeChildrenResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Composes page or view content through optional layout and document shells.
|
|
72
|
+
*
|
|
73
|
+
* One execution-scoped renderer cache is threaded through every shell layer so
|
|
74
|
+
* repeated foreign delegation reuses initialized renderers within one render pass.
|
|
75
|
+
*/
|
|
76
|
+
export declare function composeDocumentShell(dependencies: DocumentShellRenderDependencies, input: DocumentShellComposeInput): Promise<{
|
|
77
|
+
documentHtml: string;
|
|
78
|
+
}>;
|
|
79
|
+
/**
|
|
80
|
+
* Applies optional component-root and document-root attribute stamping before HTML
|
|
81
|
+
* transformation runs on explicit renderer-owned paths.
|
|
82
|
+
*/
|
|
83
|
+
export declare function applyDocumentShellAttributeStamping(html: string, stamping: DocumentShellAttributeStamping, options: {
|
|
84
|
+
componentRootAttributes?: Record<string, string>;
|
|
85
|
+
documentAttributes?: Record<string, string>;
|
|
86
|
+
}): string;
|
|
87
|
+
/**
|
|
88
|
+
* Builds the final serialized document HTML for one route page render.
|
|
89
|
+
*/
|
|
90
|
+
export declare function renderPageDocumentShell(dependencies: DocumentShellRenderDependencies, input: DocumentShellPageRenderInput, docType: string): Promise<string>;
|