@ecopages/core 0.2.0-beta.2 → 0.2.0-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. package/README.md +1 -1
  2. package/package.json +163 -3
  3. package/src/adapters/abstract/application-adapter.d.ts +104 -5
  4. package/src/adapters/abstract/application-adapter.js +125 -1
  5. package/src/adapters/abstract/server-adapter.d.ts +6 -2
  6. package/src/adapters/abstract/ws-pattern-matcher.d.ts +60 -0
  7. package/src/adapters/abstract/ws-pattern-matcher.js +61 -0
  8. package/src/adapters/bun/client-bridge.d.ts +1 -0
  9. package/src/adapters/bun/client-bridge.js +3 -0
  10. package/src/adapters/bun/create-app.d.ts +6 -4
  11. package/src/adapters/bun/create-app.js +65 -43
  12. package/src/adapters/bun/hmr-manager.d.ts +2 -1
  13. package/src/adapters/bun/hmr-manager.js +2 -2
  14. package/src/adapters/bun/server-adapter.d.ts +90 -22
  15. package/src/adapters/bun/server-adapter.js +265 -84
  16. package/src/adapters/bun/static-preview-host.js +25 -20
  17. package/src/adapters/create-app.d.ts +13 -11
  18. package/src/adapters/create-app.js +2 -51
  19. package/src/adapters/index.d.ts +1 -1
  20. package/src/adapters/index.js +1 -2
  21. package/src/adapters/node/create-app.d.ts +5 -1
  22. package/src/adapters/node/create-app.js +51 -12
  23. package/src/adapters/node/node-client-bridge.d.ts +1 -0
  24. package/src/adapters/node/node-client-bridge.js +3 -0
  25. package/src/adapters/node/node-hmr-manager.d.ts +2 -1
  26. package/src/adapters/node/node-hmr-manager.js +2 -2
  27. package/src/adapters/node/server-adapter-dependencies.js +4 -0
  28. package/src/adapters/node/server-adapter.d.ts +62 -20
  29. package/src/adapters/node/server-adapter.js +161 -131
  30. package/src/adapters/node/static-content-server.d.ts +1 -0
  31. package/src/adapters/node/static-content-server.js +10 -2
  32. package/src/adapters/node/static-preview-host.js +27 -12
  33. package/src/adapters/shared/bun-user-websocket-lifecycle.d.ts +22 -0
  34. package/src/adapters/shared/bun-user-websocket-lifecycle.js +96 -0
  35. package/src/adapters/shared/copy-runtime-public-dir.d.ts +6 -0
  36. package/src/adapters/shared/copy-runtime-public-dir.js +24 -0
  37. package/src/adapters/shared/fs-server-response-matcher.d.ts +2 -0
  38. package/src/adapters/shared/fs-server-response-matcher.js +40 -18
  39. package/src/adapters/shared/hmr-entrypoint-registrar.d.ts +0 -2
  40. package/src/adapters/shared/hmr-entrypoint-registrar.js +3 -26
  41. package/src/adapters/shared/hmr-html-response.d.ts +1 -1
  42. package/src/adapters/shared/hmr-html-response.js +4 -1
  43. package/src/adapters/shared/node-http-websocket-upgrades.d.ts +21 -0
  44. package/src/adapters/shared/node-http-websocket-upgrades.js +100 -0
  45. package/src/adapters/shared/port-manager.d.ts +116 -0
  46. package/src/adapters/shared/port-manager.js +196 -0
  47. package/src/adapters/shared/runtime-app-bootstrap.d.ts +2 -1
  48. package/src/adapters/shared/runtime-app-bootstrap.js +3 -6
  49. package/src/adapters/shared/runtime-server-lifecycle.d.ts +38 -0
  50. package/src/adapters/shared/runtime-server-lifecycle.js +43 -0
  51. package/src/adapters/shared/server-adapter.d.ts +2 -1
  52. package/src/adapters/shared/server-adapter.js +13 -6
  53. package/src/adapters/shared/server-route-handler.d.ts +4 -1
  54. package/src/adapters/shared/server-route-handler.js +5 -2
  55. package/src/adapters/shared/server-static-builder.d.ts +23 -32
  56. package/src/adapters/shared/server-static-builder.js +97 -73
  57. package/src/adapters/shared/shared-hmr-manager.d.ts +28 -0
  58. package/src/adapters/shared/shared-hmr-manager.js +119 -9
  59. package/src/adapters/shared/static-preview-host.d.ts +5 -0
  60. package/src/adapters/shared/websocket-lifecycle.d.ts +24 -0
  61. package/src/adapters/shared/websocket-lifecycle.js +55 -0
  62. package/src/build/README.md +77 -14
  63. package/src/build/app-build-manifest-runtime.d.ts +10 -0
  64. package/src/build/app-build-manifest-runtime.js +90 -0
  65. package/src/build/build-adapter.d.ts +17 -319
  66. package/src/build/build-adapter.js +28 -94
  67. package/src/build/build-contracts.d.ts +97 -0
  68. package/src/build/build-contracts.js +0 -0
  69. package/src/build/build-input-fingerprint.d.ts +28 -0
  70. package/src/build/build-input-fingerprint.js +31 -0
  71. package/src/build/build-profile-options.d.ts +7 -0
  72. package/src/build/build-profile-options.js +37 -0
  73. package/src/build/build-runtime.d.ts +24 -0
  74. package/src/build/build-runtime.js +65 -0
  75. package/src/build/deduping-build-executor.d.ts +28 -0
  76. package/src/build/deduping-build-executor.js +56 -0
  77. package/src/build/jsx-ownership-plugins.d.ts +24 -0
  78. package/src/build/jsx-ownership-plugins.js +41 -0
  79. package/src/build/pages-unified-graph-build.d.ts +31 -0
  80. package/src/build/pages-unified-graph-build.js +206 -0
  81. package/src/build/parallel-build-executor.d.ts +21 -0
  82. package/src/build/parallel-build-executor.js +52 -0
  83. package/src/build/production-build-cache.d.ts +20 -0
  84. package/src/build/production-build-cache.js +63 -0
  85. package/src/build/rolldown-adapter-helpers.d.ts +3 -6
  86. package/src/build/rolldown-adapter-helpers.js +71 -6
  87. package/src/build/rolldown-build-adapter.d.ts +2 -6
  88. package/src/build/rolldown-build-adapter.js +3 -3
  89. package/src/build/rolldown-build-invocation-metrics.d.ts +12 -0
  90. package/src/build/rolldown-build-invocation-metrics.js +43 -0
  91. package/src/build/rolldown-plugin-bridge.d.ts +15 -1
  92. package/src/build/rolldown-plugin-bridge.js +20 -5
  93. package/src/build/rolldown-source-transform-pass.d.ts +15 -0
  94. package/src/build/rolldown-source-transform-pass.js +58 -0
  95. package/src/build/runtime-build-executor.d.ts +8 -15
  96. package/src/build/runtime-build-executor.js +12 -15
  97. package/src/build/runtime-build-output-normalizer.d.ts +7 -0
  98. package/src/build/runtime-build-output-normalizer.js +94 -2
  99. package/src/build/server-entry-build-cache.d.ts +44 -0
  100. package/src/build/server-entry-build-cache.js +161 -0
  101. package/src/client/navigation-scripts/classification.d.ts +16 -0
  102. package/src/client/navigation-scripts/classification.js +41 -0
  103. package/src/client/navigation-scripts/index.d.ts +3 -0
  104. package/src/client/navigation-scripts/index.js +23 -0
  105. package/src/client/navigation-scripts/navigation-scripts.test.browser.js +65 -0
  106. package/src/client/navigation-scripts/registry.d.ts +11 -0
  107. package/src/client/navigation-scripts/registry.js +12 -0
  108. package/src/client/navigation-scripts/rerun-queue.d.ts +37 -0
  109. package/src/client/navigation-scripts/rerun-queue.js +73 -0
  110. package/src/client/scroll.d.ts +17 -0
  111. package/src/client/scroll.js +25 -0
  112. package/src/client/scroll.test.browser.js +37 -0
  113. package/src/client/view-transitions.d.ts +16 -0
  114. package/src/client/view-transitions.js +63 -0
  115. package/src/config/config-builder.d.ts +12 -7
  116. package/src/config/config-builder.js +12 -9
  117. package/src/dev/client-bridge-registry.d.ts +5 -0
  118. package/src/dev/client-bridge-registry.js +15 -0
  119. package/src/dev/dev-client-ownership.d.ts +7 -0
  120. package/src/dev/dev-client-ownership.js +6 -0
  121. package/src/dev/hmr-manager-registry.d.ts +8 -0
  122. package/src/dev/hmr-manager-registry.js +15 -0
  123. package/src/dev/host-runtime.d.ts +3 -0
  124. package/src/dev/host-runtime.js +7 -0
  125. package/src/dev/runtime-server-started-message.d.ts +2 -0
  126. package/src/dev/runtime-server-started-message.js +6 -0
  127. package/src/eco/README.md +11 -0
  128. package/src/eco/eco-declared-component.d.ts +14 -0
  129. package/src/eco/eco-declared-component.js +16 -0
  130. package/src/eco/eco.browser.js +5 -6
  131. package/src/eco/eco.js +5 -6
  132. package/src/eco/eco.types.d.ts +2 -2
  133. package/src/eco/page-layout-normalization.d.ts +21 -0
  134. package/src/eco/page-layout-normalization.js +59 -0
  135. package/src/errors/index.d.ts +1 -0
  136. package/src/errors/index.js +7 -1
  137. package/src/errors/undeclared-component-dependency-error.d.ts +11 -0
  138. package/src/errors/undeclared-component-dependency-error.js +17 -0
  139. package/src/hmr/client/hmr-runtime.js +5 -2
  140. package/src/hmr/hmr-entrypoint-output.d.ts +28 -0
  141. package/src/hmr/hmr-entrypoint-output.js +58 -0
  142. package/src/hmr/strategies/js-hmr-strategy.d.ts +3 -0
  143. package/src/hmr/strategies/js-hmr-strategy.js +68 -18
  144. package/src/hmr/strategies/server-rendered-template-hmr-strategy.d.ts +17 -0
  145. package/src/hmr/strategies/server-rendered-template-hmr-strategy.js +29 -0
  146. package/src/integrations/ghtml/ghtml-renderer.d.ts +2 -6
  147. package/src/integrations/ghtml/ghtml-renderer.js +2 -51
  148. package/src/integrations/ghtml/ghtml.plugin.d.ts +3 -16
  149. package/src/integrations/ghtml/ghtml.plugin.js +7 -14
  150. package/src/plugins/define-integration.d.ts +26 -0
  151. package/src/plugins/define-integration.js +19 -0
  152. package/src/plugins/eco-component-meta-plugin.js +5 -8
  153. package/src/plugins/foreign-jsx-override-plugin.js +4 -6
  154. package/src/plugins/integration-plugin.d.ts +19 -9
  155. package/src/plugins/integration-plugin.js +7 -4
  156. package/src/plugins/jsx-import-source.utils.d.ts +8 -0
  157. package/src/plugins/jsx-import-source.utils.js +26 -0
  158. package/src/plugins/processor.d.ts +19 -4
  159. package/src/plugins/processor.js +22 -4
  160. package/src/plugins/source-transform.d.ts +31 -0
  161. package/src/plugins/source-transform.js +23 -1
  162. package/src/route-renderer/GRAPH.md +8 -8
  163. package/src/route-renderer/README.md +30 -28
  164. package/src/route-renderer/orchestration/component-graph-collectors.d.ts +10 -0
  165. package/src/route-renderer/orchestration/component-graph-collectors.js +143 -0
  166. package/src/route-renderer/orchestration/component-graph.d.ts +36 -0
  167. package/src/route-renderer/orchestration/component-graph.js +98 -0
  168. package/src/route-renderer/orchestration/component-render-context.d.ts +3 -10
  169. package/src/route-renderer/orchestration/component-render-context.js +3 -1
  170. package/src/route-renderer/orchestration/declared-ownership-graph.d.ts +1 -18
  171. package/src/route-renderer/orchestration/declared-ownership-graph.js +5 -31
  172. package/src/route-renderer/orchestration/document-shell-render.service.d.ts +90 -0
  173. package/src/route-renderer/orchestration/document-shell-render.service.js +120 -0
  174. package/src/route-renderer/orchestration/foreign-subtree-execution.service.d.ts +59 -29
  175. package/src/route-renderer/orchestration/foreign-subtree-execution.service.js +164 -35
  176. package/src/route-renderer/orchestration/global-injector-assets.service.d.ts +7 -0
  177. package/src/route-renderer/orchestration/global-injector-assets.service.js +32 -0
  178. package/src/route-renderer/orchestration/integration-renderer.d.ts +18 -54
  179. package/src/route-renderer/orchestration/integration-renderer.js +113 -195
  180. package/src/route-renderer/orchestration/integration-route-render-adapter.d.ts +38 -0
  181. package/src/route-renderer/orchestration/integration-route-render-adapter.js +27 -0
  182. package/src/route-renderer/orchestration/layout-shell-props.service.d.ts +20 -0
  183. package/src/route-renderer/orchestration/layout-shell-props.service.js +31 -0
  184. package/src/route-renderer/orchestration/ownership-validation.service.d.ts +5 -0
  185. package/src/route-renderer/orchestration/ownership-validation.service.js +29 -1
  186. package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.d.ts +9 -0
  187. package/src/route-renderer/orchestration/page-browser-graph-contribution.loader.js +7 -0
  188. package/src/route-renderer/orchestration/page-browser-graph.service.d.ts +25 -0
  189. package/src/route-renderer/orchestration/page-browser-graph.service.js +174 -0
  190. package/src/route-renderer/orchestration/render-output.utils.d.ts +2 -0
  191. package/src/route-renderer/orchestration/render-output.utils.js +4 -0
  192. package/src/route-renderer/orchestration/route-html-finalization.service.d.ts +17 -0
  193. package/src/route-renderer/orchestration/route-html-finalization.service.js +26 -0
  194. package/src/route-renderer/orchestration/route-prepared-options.builder.d.ts +26 -0
  195. package/src/route-renderer/orchestration/route-prepared-options.builder.js +54 -0
  196. package/src/route-renderer/orchestration/route-prepared-options.utils.d.ts +4 -0
  197. package/src/route-renderer/orchestration/route-prepared-options.utils.js +33 -0
  198. package/src/route-renderer/orchestration/route-render-orchestrator.d.ts +8 -39
  199. package/src/route-renderer/orchestration/route-render-orchestrator.js +53 -461
  200. package/src/route-renderer/orchestration/string-markup-renderer.d.ts +14 -0
  201. package/src/route-renderer/orchestration/string-markup-renderer.js +55 -0
  202. package/src/route-renderer/page-loading/component-dependency-collection.js +5 -2
  203. package/src/router/client/link-intent.d.ts +11 -21
  204. package/src/router/client/link-intent.js +10 -0
  205. package/src/router/client/link-intent.test.browser.js +12 -1
  206. package/src/router/client/link-navigation-policy.d.ts +45 -0
  207. package/src/router/client/link-navigation-policy.js +101 -0
  208. package/src/router/client/link-navigation-policy.test.browser.d.ts +1 -0
  209. package/src/router/client/link-navigation-policy.test.browser.js +92 -0
  210. package/src/router/client/navigation-coordinator.d.ts +1 -1
  211. package/src/router/client/navigation-coordinator.js +12 -2
  212. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.d.ts +1 -0
  213. package/src/services/assets/asset-processing-service/browser-runtime-asset.factory.js +1 -0
  214. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.d.ts +4 -2
  215. package/src/services/assets/asset-processing-service/browser-runtime-entry.factory.js +27 -7
  216. package/src/services/assets/asset-processing-service/processors/script/file-script.processor.js +36 -14
  217. package/src/services/assets/asset-processing-service/processors/script/node-module-script.processor.js +17 -3
  218. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.d.ts +0 -3
  219. package/src/services/assets/asset-processing-service/processors/stylesheet/content-stylesheet.processor.js +2 -31
  220. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.d.ts +0 -3
  221. package/src/services/assets/asset-processing-service/processors/stylesheet/file-stylesheet.processor.js +2 -30
  222. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.d.ts +2 -0
  223. package/src/services/assets/asset-processing-service/processors/stylesheet/stylesheet-processor-pipeline.js +43 -0
  224. package/src/services/assets/browser-bundle.service.d.ts +3 -1
  225. package/src/services/assets/browser-bundle.service.js +17 -5
  226. package/src/services/html/html-transformer.service.d.ts +1 -1
  227. package/src/services/html/html-transformer.service.js +4 -4
  228. package/src/services/invalidation/development-invalidation.service.d.ts +20 -2
  229. package/src/services/invalidation/development-invalidation.service.js +56 -2
  230. package/src/services/module-loading/README.md +49 -0
  231. package/src/services/module-loading/app-server-module-transpiler.service.js +5 -17
  232. package/src/services/module-loading/page-module-import.service.d.ts +5 -1
  233. package/src/services/module-loading/page-module-import.service.js +97 -45
  234. package/src/services/module-loading/route-module-build-cache-registry.d.ts +24 -0
  235. package/src/services/module-loading/route-module-build-cache-registry.js +37 -0
  236. package/src/services/module-loading/route-module-build-cache.d.ts +4 -0
  237. package/src/services/module-loading/route-module-build-cache.js +38 -0
  238. package/src/services/module-loading/route-module-build-cache.store.d.ts +57 -0
  239. package/src/services/module-loading/route-module-build-cache.store.js +207 -0
  240. package/src/services/module-loading/route-module-build-manifest.d.ts +61 -0
  241. package/src/services/module-loading/route-module-build-manifest.js +116 -0
  242. package/src/services/module-loading/route-module-dependency-hasher.d.ts +81 -0
  243. package/src/services/module-loading/route-module-dependency-hasher.js +121 -0
  244. package/src/services/module-loading/server-module-transpiler.service.js +1 -1
  245. package/src/static-site-generator/README.md +33 -0
  246. package/src/static-site-generator/static-build-invalidation.d.ts +10 -0
  247. package/src/static-site-generator/static-build-invalidation.js +59 -0
  248. package/src/static-site-generator/static-export-context.d.ts +22 -0
  249. package/src/static-site-generator/static-export-context.js +0 -0
  250. package/src/static-site-generator/static-site-generator.d.ts +17 -20
  251. package/src/static-site-generator/static-site-generator.js +188 -85
  252. package/src/types/internal-types.d.ts +16 -9
  253. package/src/types/public-types.d.ts +138 -26
  254. package/src/utils/parse-cli-args.d.ts +2 -0
  255. package/src/utils/parse-cli-args.js +6 -0
  256. package/src/utils/server-utils.module.d.ts +3 -2
  257. package/src/utils/server-utils.module.js +5 -6
  258. package/src/utils/static-file-extensions.d.ts +12 -0
  259. package/src/utils/static-file-extensions.js +48 -0
  260. package/src/watchers/project-watcher-ignore.d.ts +11 -0
  261. package/src/watchers/project-watcher-ignore.js +16 -0
  262. package/src/watchers/project-watcher.d.ts +25 -2
  263. package/src/watchers/project-watcher.js +130 -23
  264. package/src/build/rolldown-dev-build-adapter.d.ts +0 -82
  265. package/src/build/rolldown-dev-build-adapter.js +0 -166
  266. package/src/hmr/hmr.postcss.test.e2e.js +0 -31
  267. package/src/hmr/hmr.test.e2e.js +0 -43
  268. package/src/route-renderer/orchestration/ownership-planning.service.d.ts +0 -24
  269. package/src/route-renderer/orchestration/ownership-planning.service.js +0 -63
  270. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.d.ts +0 -91
  271. package/src/route-renderer/orchestration/queued-foreign-subtree-resolution.service.js +0 -170
  272. /package/src/{hmr/hmr.postcss.test.e2e.d.ts → client/navigation-scripts/navigation-scripts.test.browser.d.ts} +0 -0
  273. /package/src/{hmr/hmr.test.e2e.d.ts → client/scroll.test.browser.d.ts} +0 -0
@@ -2,17 +2,18 @@ import {
2
2
  getComponentRenderContext,
3
3
  runWithComponentRenderContext
4
4
  } from "./component-render-context.js";
5
- import {
6
- QueuedForeignSubtreeResolutionService
7
- } from "./queued-foreign-subtree-resolution.service.js";
8
- function isMarkupNodeLike(value) {
9
- return typeof value === "object" && value !== null && "nodeType" in value && typeof value.nodeType === "number" && (!("outerHTML" in value) || typeof value.outerHTML === "string");
5
+ import { isMarkupNodeLike } from "./render-output.utils.js";
6
+ function toForeignSubtreeRenderPayload(result) {
7
+ return {
8
+ html: result.html,
9
+ assets: result.assets ?? [],
10
+ rootTag: result.rootTag,
11
+ rootAttributes: result.rootAttributes,
12
+ attachmentPolicy: result.canAttachAttributes ? { kind: "first-element" } : { kind: "none" },
13
+ integrationName: result.integrationName
14
+ };
10
15
  }
11
16
  class ForeignSubtreeExecutionService {
12
- queuedForeignSubtreeResolutionService;
13
- constructor(queuedForeignSubtreeResolutionService = new QueuedForeignSubtreeResolutionService()) {
14
- this.queuedForeignSubtreeResolutionService = queuedForeignSubtreeResolutionService;
15
- }
16
17
  requiresForeignChildRuntime(input) {
17
18
  const children = input.children ?? input.props.children;
18
19
  if (children === void 0 || children === null) {
@@ -26,18 +27,9 @@ class ForeignSubtreeExecutionService {
26
27
  }
27
28
  return !isMarkupNodeLike(children);
28
29
  }
29
- /**
30
- * Returns whether the current render pass must hand the child off to a foreign owner.
31
- */
32
30
  shouldDelegateForeignChild(input) {
33
31
  return !!input.targetIntegration && input.targetIntegration !== input.currentIntegration;
34
32
  }
35
- /**
36
- * Creates the base runtime used when a renderer has not supplied its own queueing runtime.
37
- *
38
- * The runtime allows same-integration children to continue inline and fails fast
39
- * when execution crosses into a foreign owner without a renderer-owned handoff.
40
- */
41
33
  createFailFastRuntime(rendererName) {
42
34
  const interceptForeignChild = (input) => {
43
35
  if (!this.shouldDelegateForeignChild(input)) {
@@ -56,10 +48,10 @@ class ForeignSubtreeExecutionService {
56
48
  };
57
49
  }
58
50
  getQueuedRuntimeContext(input, runtimeContextKey) {
59
- return this.queuedForeignSubtreeResolutionService.getRuntimeContext(input, runtimeContextKey);
51
+ return this.getRuntimeContext(input, runtimeContextKey);
60
52
  }
61
53
  createQueuedRuntime(options) {
62
- return this.queuedForeignSubtreeResolutionService.createRuntime({
54
+ return this.createQueueRuntime({
63
55
  renderInput: options.renderInput,
64
56
  rendererCache: options.rendererCache,
65
57
  runtimeContextKey: options.runtimeContextKey,
@@ -68,9 +60,42 @@ class ForeignSubtreeExecutionService {
68
60
  createRuntimeContext: options.createRuntimeContext
69
61
  });
70
62
  }
71
- /**
72
- * Resolves a string-first renderer HTML fragment that may contain queued Foreign Subtree tokens.
73
- */
63
+ createQueueRuntime(options) {
64
+ const runtimeContext = this.ensureRuntimeContext(options);
65
+ const interceptForeignChild = (input) => {
66
+ if (!options.shouldQueueForeignChild(input)) {
67
+ return {
68
+ kind: "inline",
69
+ props: { ...input.props }
70
+ };
71
+ }
72
+ runtimeContext.nextForeignSubtreeId += 1;
73
+ const foreignSubtreeId = runtimeContext.nextForeignSubtreeId;
74
+ const token = this.createForeignSubtreeToken(options.tokenPrefix, runtimeContext, foreignSubtreeId);
75
+ runtimeContext.queuedResolutions.push({
76
+ token,
77
+ component: input.component,
78
+ props: { ...input.props },
79
+ componentInstanceId: runtimeContext.componentInstanceScope ? `${runtimeContext.componentInstanceScope}_n_${foreignSubtreeId}` : `n_${foreignSubtreeId}`
80
+ });
81
+ return {
82
+ kind: "resolved",
83
+ value: token
84
+ };
85
+ };
86
+ return {
87
+ interceptForeignChild,
88
+ interceptForeignChildSync: interceptForeignChild
89
+ };
90
+ }
91
+ getRuntimeContext(input, runtimeContextKey) {
92
+ const integrationContext = input.integrationContext;
93
+ const runtimeContext = integrationContext?.[runtimeContextKey];
94
+ if (typeof runtimeContext !== "object" || runtimeContext === null) {
95
+ return void 0;
96
+ }
97
+ return runtimeContext;
98
+ }
74
99
  async resolveStringQueuedHtml(options) {
75
100
  const runtimeContext = this.getQueuedRuntimeContext(options.renderInput, options.runtimeContextKey);
76
101
  return this.resolveQueuedHtml({
@@ -98,7 +123,7 @@ class ForeignSubtreeExecutionService {
98
123
  });
99
124
  }
100
125
  async resolveQueuedHtml(options) {
101
- return this.queuedForeignSubtreeResolutionService.resolveQueuedHtml({
126
+ return this.resolveQueuedForeignSubtreeTokens({
102
127
  html: options.html,
103
128
  runtimeContext: options.runtimeContext,
104
129
  queueLabel: options.queueLabel,
@@ -113,9 +138,93 @@ class ForeignSubtreeExecutionService {
113
138
  dedupeProcessedAssets: options.dedupeProcessedAssets
114
139
  });
115
140
  }
116
- /**
117
- * Executes one component render with Foreign Child support under the current integration.
118
- */
141
+ async resolveQueuedForeignSubtreeTokens(options) {
142
+ if (!options.runtimeContext || options.runtimeContext.queuedResolutions.length === 0) {
143
+ return { assets: [], html: options.html };
144
+ }
145
+ const runtimeContext = options.runtimeContext;
146
+ const queuedResolutionsByToken = /* @__PURE__ */ new Map();
147
+ const resolvedHtmlByToken = /* @__PURE__ */ new Map();
148
+ const resolvingTokens = /* @__PURE__ */ new Set();
149
+ const collectedAssets = [];
150
+ const syncQueuedResolutions = () => {
151
+ for (const resolution of runtimeContext.queuedResolutions) {
152
+ if (!queuedResolutionsByToken.has(resolution.token)) {
153
+ queuedResolutionsByToken.set(resolution.token, resolution);
154
+ }
155
+ }
156
+ };
157
+ const resolveToken = async (token) => {
158
+ syncQueuedResolutions();
159
+ const cachedHtml = resolvedHtmlByToken.get(token);
160
+ if (cachedHtml) {
161
+ return cachedHtml;
162
+ }
163
+ const resolution = queuedResolutionsByToken.get(token);
164
+ if (!resolution) {
165
+ return token;
166
+ }
167
+ if (resolvingTokens.has(token)) {
168
+ throw new Error(
169
+ `[ecopages] ${options.queueLabel} foreign-subtree queue contains a cycle or unresolved dependency links.`
170
+ );
171
+ }
172
+ resolvingTokens.add(token);
173
+ try {
174
+ const renderedChildren = await options.renderQueuedChildren(
175
+ resolution.props.children,
176
+ runtimeContext,
177
+ queuedResolutionsByToken,
178
+ resolveToken
179
+ );
180
+ syncQueuedResolutions();
181
+ if (renderedChildren.assets.length > 0) {
182
+ collectedAssets.push(...renderedChildren.assets);
183
+ }
184
+ const foreignSubtreeRender = await options.resolveForeignSubtree(
185
+ {
186
+ component: resolution.component,
187
+ props: { ...resolution.props },
188
+ children: renderedChildren.html ?? renderedChildren.children,
189
+ integrationContext: {
190
+ rendererCache: runtimeContext.rendererCache,
191
+ componentInstanceId: resolution.componentInstanceId
192
+ }
193
+ },
194
+ runtimeContext.rendererCache
195
+ );
196
+ if (!foreignSubtreeRender) {
197
+ throw new Error(
198
+ `[ecopages] ${options.queueLabel} queued foreign subtree could not resolve its owning renderer.`
199
+ );
200
+ }
201
+ if ((foreignSubtreeRender.assets?.length ?? 0) > 0) {
202
+ collectedAssets.push(...foreignSubtreeRender.assets ?? []);
203
+ }
204
+ const resolvedHtml2 = foreignSubtreeRender.attachmentPolicy.kind === "first-element" && foreignSubtreeRender.rootAttributes ? options.applyAttributesToFirstElement(
205
+ foreignSubtreeRender.html,
206
+ foreignSubtreeRender.rootAttributes
207
+ ) : foreignSubtreeRender.html;
208
+ resolvedHtmlByToken.set(token, resolvedHtml2);
209
+ return resolvedHtml2;
210
+ } finally {
211
+ resolvingTokens.delete(token);
212
+ }
213
+ };
214
+ let resolvedHtml = options.html;
215
+ for (let index = 0; index < runtimeContext.queuedResolutions.length; index += 1) {
216
+ syncQueuedResolutions();
217
+ const resolution = runtimeContext.queuedResolutions[index];
218
+ if (!resolvedHtml.includes(resolution.token)) {
219
+ continue;
220
+ }
221
+ resolvedHtml = resolvedHtml.split(resolution.token).join(await resolveToken(resolution.token));
222
+ }
223
+ return {
224
+ assets: options.dedupeProcessedAssets(collectedAssets),
225
+ html: resolvedHtml
226
+ };
227
+ }
119
228
  async executeComponentRender(options) {
120
229
  const rendererCache = this.getRendererCache(options.input.integrationContext) ?? /* @__PURE__ */ new Map();
121
230
  const delegatedForeignChildRender = await this.resolveForeignChildInOwningRenderer({
@@ -167,12 +276,6 @@ class ForeignSubtreeExecutionService {
167
276
  integrationContext: integrationContext ? { ...integrationContext, rendererCache: sharedRendererCache } : { rendererCache: sharedRendererCache }
168
277
  };
169
278
  }
170
- /**
171
- * Returns the delegatable owning renderer integration for one component.
172
- *
173
- * The pseudo `html` integration marks document-shell ownership only and does
174
- * not participate in component-level foreign subtree execution.
175
- */
176
279
  getForeignOwnerIntegrationName(component, currentIntegrationName) {
177
280
  const integrationName = component.config?.integration ?? component.config?.__eco?.integration;
178
281
  if (!integrationName || integrationName === "html" || integrationName === currentIntegrationName) {
@@ -195,7 +298,7 @@ class ForeignSubtreeExecutionService {
195
298
  input: options.input,
196
299
  rendererCache: options.rendererCache,
197
300
  getOwningRenderer: options.getOwningRenderer,
198
- run: (owningRenderer, delegatedInput) => owningRenderer.renderForeignSubtree(delegatedInput)
301
+ run: async (owningRenderer, delegatedInput) => toForeignSubtreeRenderPayload(await owningRenderer.renderComponentWithForeignChildren(delegatedInput))
199
302
  });
200
303
  }
201
304
  async runInForeignOwningRenderer(options) {
@@ -227,7 +330,33 @@ class ForeignSubtreeExecutionService {
227
330
  }
228
331
  return resolvedHtml;
229
332
  }
333
+ createForeignSubtreeToken(tokenPrefix, runtimeContext, foreignSubtreeId) {
334
+ return `${tokenPrefix}${runtimeContext.componentInstanceScope ?? "root"}__${foreignSubtreeId}__`;
335
+ }
336
+ ensureRuntimeContext(options) {
337
+ let integrationContext;
338
+ if (typeof options.renderInput.integrationContext === "object" && options.renderInput.integrationContext !== null) {
339
+ integrationContext = options.renderInput.integrationContext;
340
+ } else {
341
+ integrationContext = {};
342
+ }
343
+ const existingRuntimeContext = integrationContext[options.runtimeContextKey];
344
+ if (typeof existingRuntimeContext !== "object" || existingRuntimeContext === null) {
345
+ integrationContext[options.runtimeContextKey] = options.createRuntimeContext?.(integrationContext, options.rendererCache) ?? {
346
+ rendererCache: options.rendererCache,
347
+ componentInstanceScope: integrationContext.componentInstanceId,
348
+ nextForeignSubtreeId: 0,
349
+ queuedResolutions: []
350
+ };
351
+ } else {
352
+ existingRuntimeContext.rendererCache = options.rendererCache;
353
+ }
354
+ integrationContext.rendererCache = options.rendererCache;
355
+ options.renderInput.integrationContext = integrationContext;
356
+ return integrationContext[options.runtimeContextKey];
357
+ }
230
358
  }
231
359
  export {
232
- ForeignSubtreeExecutionService
360
+ ForeignSubtreeExecutionService,
361
+ toForeignSubtreeRenderPayload
233
362
  };
@@ -0,0 +1,7 @@
1
+ import type { EcoPagesAppConfig } from '../../types/internal-types.js';
2
+ import type { ResolvedLazyTrigger } from '../../types/public-types.js';
3
+ import { type AssetProcessingService, type ProcessedAsset } from '../../services/assets/asset-processing-service/index.js';
4
+ /**
5
+ * Builds processed global-injector map and bootstrap assets for resolved lazy triggers.
6
+ */
7
+ export declare function buildGlobalInjectorAssets(appConfig: EcoPagesAppConfig, assetProcessingService: AssetProcessingService, triggers: ResolvedLazyTrigger[], currentIntegrationName: string): Promise<ProcessedAsset[]>;
@@ -0,0 +1,32 @@
1
+ import { createRequire } from "node:module";
2
+ import path from "node:path";
3
+ import {
4
+ AssetFactory
5
+ } from "../../services/assets/asset-processing-service/index.js";
6
+ import { buildGlobalInjectorBootstrapContent, buildGlobalInjectorMapScript } from "../../eco/global-injector-map.js";
7
+ async function buildGlobalInjectorAssets(appConfig, assetProcessingService, triggers, currentIntegrationName) {
8
+ const appProjectDir = appConfig.rootDir ?? appConfig.absolutePaths?.projectDir ?? process.cwd();
9
+ const appPackageRequire = createRequire(path.join(appProjectDir, "package.json"));
10
+ const corePackageEntryPath = appPackageRequire.resolve("@ecopages/core");
11
+ const globalInjectorImportPath = createRequire(corePackageEntryPath).resolve("@ecopages/scripts-injector/global");
12
+ const mapScript = AssetFactory.createInlineContentScript({
13
+ position: "head",
14
+ name: "ecopages-global-injector-map",
15
+ content: buildGlobalInjectorMapScript(triggers),
16
+ attributes: { type: "ecopages/global-injector-map" },
17
+ packageRole: "keep-separate",
18
+ bundle: false
19
+ });
20
+ const bootstrapInlineScript = AssetFactory.createInlineContentScript({
21
+ position: "head",
22
+ name: "ecopages-global-injector-bootstrap",
23
+ content: buildGlobalInjectorBootstrapContent(globalInjectorImportPath),
24
+ attributes: { type: "module" },
25
+ packageRole: "keep-separate",
26
+ bundle: true
27
+ });
28
+ return assetProcessingService.processDependencies([mapScript, bootstrapInlineScript], currentIntegrationName);
29
+ }
30
+ export {
31
+ buildGlobalInjectorAssets
32
+ };
@@ -4,17 +4,16 @@
4
4
  * @module
5
5
  */
6
6
  import type { EcoPagesAppConfig, IHmrManager } from '../../types/internal-types.js';
7
- import type { ComponentRenderInput, ComponentRenderResult, ForeignSubtreeRenderPayload, EcoComponent, EcoComponentDependencies, EcoPageFile, EcoPagesElement, BaseIntegrationContext, HtmlTemplateProps, IntegrationRendererRenderOptions, PageBrowserGraphContribution, PageBrowserGraphContributionContext, PageBrowserGraphResult, PageMetadataProps, RouteRendererBody, RouteRendererOptions, RouteRenderResult } from '../../types/public-types.js';
7
+ import type { ComponentRenderInput, ComponentRenderResult, EcoComponent, EcoComponentDependencies, EcoPageFile, EcoPagesElement, BaseIntegrationContext, HtmlTemplateProps, IntegrationRendererRenderOptions, PageBrowserGraphContribution, PageBrowserGraphContributionContext, PageBrowserGraphResult, PageMetadataProps, PagePackageResult, RouteRendererBody, RouteRendererOptions, RouteRenderResult } from '../../types/public-types.js';
8
8
  import { type AssetProcessingService, type ProcessedAsset } from '../../services/assets/asset-processing-service/index.js';
9
9
  import { HtmlTransformerService } from '../../services/html/html-transformer.service.js';
10
10
  import type { HtmlDocumentContribution } from '../../services/html/html-transformer.service.js';
11
11
  import { HttpError } from '../../errors/http-error.js';
12
12
  import { DependencyResolverService } from '../page-loading/dependency-resolver.js';
13
13
  import { PageModuleLoaderService } from '../page-loading/page-module-loader.js';
14
- import { type RouteHtmlFinalization, RouteRenderOrchestrator, type RouteRenderOrchestratorAdapter, type RouteRenderOrchestratorResolvedInputs } from './route-render-orchestrator.js';
14
+ import { RouteRenderOrchestrator, type RouteRenderOrchestratorAdapter, type RouteRenderOrchestratorResolvedInputs } from './route-render-orchestrator.js';
15
15
  import type { ForeignChildRuntime } from './component-render-context.js';
16
- import { ForeignSubtreeExecutionService, type ForeignSubtreeExecutionOwningRenderer } from './foreign-subtree-execution.service.js';
17
- import { type QueuedForeignSubtreeResolutionContext } from './queued-foreign-subtree-resolution.service.js';
16
+ import { ForeignSubtreeExecutionService, type ForeignSubtreeExecutionOwningRenderer, type ForeignSubtreeQueuedHtmlOptions, type QueuedForeignSubtreeResolutionContext } from './foreign-subtree-execution.service.js';
18
17
  /**
19
18
  * Controls how one route module is loaded outside the normal render path.
20
19
  *
@@ -59,7 +58,15 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
59
58
  protected pageModuleLoaderService: PageModuleLoaderService;
60
59
  protected routeRenderOrchestrator: RouteRenderOrchestrator;
61
60
  protected readonly foreignSubtreeExecutionService: ForeignSubtreeExecutionService;
61
+ /**
62
+ * Serializes route and view renders that mutate `htmlTransformer` state.
63
+ *
64
+ * Integration renderers are cached per integration, so concurrent static builds
65
+ * and overlapping SSR requests must not share one transformer page package.
66
+ */
67
+ private renderExclusiveChain;
62
68
  protected DOC_TYPE: string;
69
+ private runRenderExclusive;
63
70
  /**
64
71
  * Loads one route module through the owning renderer's import path.
65
72
  *
@@ -69,34 +76,6 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
69
76
  * with raw transpiler access.
70
77
  */
71
78
  loadPageModule(file: string, options?: RouteModuleLoadOptions): Promise<EcoPageFile>;
72
- /**
73
- * Reads the execution-scoped owning-renderer cache from one render input.
74
- *
75
- * Shared page/layout/document shell helpers pass one cache through
76
- * `integrationContext` so repeated delegation to the same foreign integration
77
- * can reuse a single initialized renderer instance during one render flow.
78
- * The cache is deliberately scoped to the current render execution rather than
79
- * stored on the renderer, which avoids leaking mutable integration state across
80
- * requests while still preventing redundant renderer initialization.
81
- *
82
- * @param integrationContext - Optional render context carried with one render input.
83
- * @returns The current execution cache when present.
84
- */
85
- private getOwningRendererCache;
86
- private getForeignOwnerIntegrationName;
87
- /**
88
- * Attaches an execution-scoped owning-renderer cache to one render input.
89
- *
90
- * Foreign-owned page, layout, or document shells may delegate several times in
91
- * the same render flow. Threading the cache through `integrationContext`
92
- * preserves renderer reuse without changing the public render input contract.
93
- * Existing integration-specific context is preserved and augmented.
94
- *
95
- * @param input - Original render input.
96
- * @param rendererCache - Execution-scoped renderer cache to propagate.
97
- * @returns Render input augmented with the shared renderer cache.
98
- */
99
- private withOwningRendererCache;
100
79
  protected getRendererModuleValue(key: string): unknown;
101
80
  protected getRendererModuleString(key: string): string | undefined;
102
81
  protected getRendererBootstrapDependencies(partial?: boolean): ProcessedAsset[];
@@ -219,20 +198,6 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
219
198
  documentProps?: Record<string, unknown>;
220
199
  transformDocumentHtml?: (html: string) => string;
221
200
  }): Promise<string>;
222
- private composeDocumentShell;
223
- /**
224
- * Renders one string-first component with serialized children and collects its assets.
225
- *
226
- * String-oriented integrations frequently share the same component contract:
227
- * pass serialized children through props, coerce the render result to HTML, and
228
- * attach any component-scoped dependencies. This helper centralizes that flow
229
- * so integrations can opt into shared orchestration without repeating the same
230
- * string-render boilerplate.
231
- *
232
- * @param input - Component render input.
233
- * @param component - String-oriented component implementation to execute.
234
- * @returns Structured component render result for orchestration paths.
235
- */
236
201
  protected renderStringComponentWithSerializedChildren(input: ComponentRenderInput, component: (props: Record<string, unknown>) => Promise<EcoPagesElement> | EcoPagesElement): Promise<ComponentRenderResult>;
237
202
  protected getForeignSubtreeTokenPrefix(): string;
238
203
  protected getForeignSubtreeResolutionContextKey(): string;
@@ -244,6 +209,10 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
244
209
  createRuntimeContext?: (integrationContext: BaseIntegrationContext & Record<string, unknown>, rendererCache: Map<string, unknown>) => TContext;
245
210
  }): ForeignChildRuntime;
246
211
  protected getQueuedForeignSubtreeResolutionContext<TContext extends QueuedForeignSubtreeResolutionContext>(input: ComponentRenderInput): TContext | undefined;
212
+ protected resolveQueuedForeignSubtreeHtml<TContext extends QueuedForeignSubtreeResolutionContext>(html: string, runtimeContext: TContext | undefined, renderQueuedChildren: ForeignSubtreeQueuedHtmlOptions<TContext>['renderQueuedChildren'], queueLabel?: string): Promise<{
213
+ assets: ProcessedAsset[];
214
+ html: string;
215
+ }>;
247
216
  /**
248
217
  * Renders a string-first component, then resolves any queued foreign
249
218
  * boundaries before returning final component HTML.
@@ -350,8 +319,7 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
350
319
  routeOptions: RouteRendererOptions;
351
320
  }): Promise<ComponentRenderResult | undefined>;
352
321
  protected renderRouteBody(renderOptions: IntegrationRendererRenderOptions<C>): Promise<RouteRendererBody>;
353
- protected getRouteHtmlFinalization(renderOptions: IntegrationRendererRenderOptions<C>): RouteHtmlFinalization;
354
- protected transformRouteResponse(response: Response, htmlContributions?: HtmlDocumentContribution[]): Promise<RouteRendererBody>;
322
+ protected transformRouteResponse(response: Response, htmlContributions?: HtmlDocumentContribution[], pagePackage?: PagePackageResult): Promise<RouteRendererBody>;
355
323
  /**
356
324
  * Prepares the render options for the integration renderer.
357
325
  * It imports the page file, collects dependencies, and prepares the render options.
@@ -413,6 +381,8 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
413
381
  * other runtime coordination markers without relying on script sniffing.
414
382
  */
415
383
  protected getDocumentAttributes(_renderOptions: IntegrationRendererRenderOptions<C>): Record<string, string> | undefined;
384
+ protected applyAttributesToFirstBodyElement(html: string, attributes: Record<string, string>): string;
385
+ protected applyAttributesToHtmlElement(html: string, attributes: Record<string, string>): string;
416
386
  /**
417
387
  * Returns declarative HTML fragments that core should inject into the final document.
418
388
  *
@@ -451,12 +421,6 @@ export declare abstract class IntegrationRenderer<C = EcoPagesElement> {
451
421
  * renderer's nested foreign-child handoff.
452
422
  */
453
423
  renderComponentWithForeignChildren(input: ComponentRenderInput): Promise<ComponentRenderResult>;
454
- /**
455
- * Compatibility foreign-subtree contract that exposes a narrower payload shape for
456
- * future route-composition work while preserving the current
457
- * `renderComponentWithForeignChildren()` runtime semantics.
458
- */
459
- renderForeignSubtree(input: ComponentRenderInput): Promise<ForeignSubtreeRenderPayload>;
460
424
  private normalizeComponentRenderOutput;
461
425
  protected normalizeUnresolvedMarkerArtifactHtml(html: string): string;
462
426
  /**