@ecopages/core 0.2.0-alpha.12 → 0.2.0-alpha.13

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 (51) hide show
  1. package/CHANGELOG.md +7 -28
  2. package/README.md +5 -4
  3. package/package.json +2 -2
  4. package/src/adapters/bun/hmr-manager.js +2 -2
  5. package/src/adapters/node/node-hmr-manager.js +2 -2
  6. package/src/adapters/node/server-adapter.d.ts +2 -2
  7. package/src/adapters/node/server-adapter.js +5 -5
  8. package/src/build/build-adapter.d.ts +7 -6
  9. package/src/build/build-adapter.js +6 -7
  10. package/src/eco/eco.js +15 -6
  11. package/src/eco/eco.utils.d.ts +1 -1
  12. package/src/eco/eco.utils.js +5 -1
  13. package/src/hmr/hmr-strategy.d.ts +2 -2
  14. package/src/integrations/ghtml/ghtml-renderer.d.ts +6 -1
  15. package/src/integrations/ghtml/ghtml-renderer.js +29 -28
  16. package/src/plugins/integration-plugin.d.ts +1 -24
  17. package/src/plugins/integration-plugin.js +0 -14
  18. package/src/route-renderer/GRAPH.md +54 -84
  19. package/src/route-renderer/README.md +11 -22
  20. package/src/route-renderer/orchestration/component-render-context.d.ts +33 -84
  21. package/src/route-renderer/orchestration/component-render-context.js +30 -108
  22. package/src/route-renderer/orchestration/integration-renderer.d.ts +219 -96
  23. package/src/route-renderer/orchestration/integration-renderer.js +416 -236
  24. package/src/route-renderer/orchestration/queued-boundary-runtime.service.d.ts +93 -0
  25. package/src/route-renderer/orchestration/queued-boundary-runtime.service.js +155 -0
  26. package/src/route-renderer/orchestration/render-execution.service.d.ts +8 -71
  27. package/src/route-renderer/orchestration/render-execution.service.js +28 -115
  28. package/src/route-renderer/orchestration/render-output.utils.d.ts +6 -0
  29. package/src/route-renderer/orchestration/render-output.utils.js +25 -0
  30. package/src/route-renderer/orchestration/render-preparation.service.d.ts +0 -9
  31. package/src/route-renderer/orchestration/render-preparation.service.js +3 -34
  32. package/src/route-renderer/page-loading/dependency-resolver.js +6 -1
  33. package/src/route-renderer/page-loading/page-module-loader.d.ts +1 -2
  34. package/src/route-renderer/page-loading/page-module-loader.js +0 -2
  35. package/src/router/client/navigation-coordinator.js +2 -2
  36. package/src/router/server/fs-router-scanner.js +6 -1
  37. package/src/services/runtime-state/dev-graph.service.d.ts +5 -5
  38. package/src/services/runtime-state/dev-graph.service.js +10 -10
  39. package/src/types/public-types.d.ts +2 -5
  40. package/src/eco/component-render-context.d.ts +0 -2
  41. package/src/eco/component-render-context.js +0 -12
  42. package/src/route-renderer/component-graph/component-graph-executor.d.ts +0 -33
  43. package/src/route-renderer/component-graph/component-graph-executor.js +0 -30
  44. package/src/route-renderer/component-graph/component-graph.d.ts +0 -53
  45. package/src/route-renderer/component-graph/component-graph.js +0 -94
  46. package/src/route-renderer/component-graph/component-marker.d.ts +0 -52
  47. package/src/route-renderer/component-graph/component-marker.js +0 -44
  48. package/src/route-renderer/component-graph/component-reference.d.ts +0 -10
  49. package/src/route-renderer/component-graph/component-reference.js +0 -34
  50. package/src/route-renderer/component-graph/marker-graph-resolver.d.ts +0 -79
  51. package/src/route-renderer/component-graph/marker-graph-resolver.js +0 -117
package/CHANGELOG.md CHANGED
@@ -8,39 +8,18 @@ All notable changes to `@ecopages/core` are documented here.
8
8
 
9
9
  ### Features
10
10
 
11
- - Added a shared runtime boundary around `createApp()`, host module loading, and explicit build ownership for Bun-native execution, Node fallback support, and Vite or Nitro hosts.
12
- - Added the browser-safe `eco` export, semantic `eco.html()` and `eco.layout()` helpers, and the internal `.eco` work directory.
13
- - Added the public `EcoPagesAppConfig` export for published integration packages.
11
+ - Added app-owned runtime and build ownership around `createApp()`, host module loading, the browser-safe `eco` export, `eco.html()`, `eco.layout()`, and the published `EcoPagesAppConfig` surface.
14
12
 
15
13
  ### Refactoring
16
14
 
17
15
  - Consolidated runtime state around shared module-loading services, app-owned build execution, and the universal `createApp()` boundary.
18
- - Removed the deprecated `@ecopages/core/node*` public escape hatches and the old thin-host bootstrap internals from core.
19
- - Added renderer-owned deferred-template serializers so integration-specific template-shape adapters live on `IntegrationRenderer` subclasses instead of global registration state.
20
- - Refactored `eco` component factories to delegate deferred-boundary and lazy-output runtime behavior through component render context instead of coupling `eco.ts` directly to marker-graph internals.
21
- - Moved component render-context implementation under route-renderer orchestration and left `eco` with a thin compatibility re-export.
22
- - Moved lazy render-output helpers under route-renderer orchestration and left `eco/eco.utils` as a thin compatibility re-export so orchestration no longer depends on the `eco` implementation folder.
16
+ - Simplified route-renderer orchestration around renderer-owned boundary runtimes, shared string-boundary queue helpers, and a smaller component render context.
17
+ - Removed marker-era compatibility capture, the shared route-level fallback resolver, deprecated `@ecopages/core/node*` escape hatches, and other dead route-renderer internals.
23
18
 
24
19
  ### Bug Fixes
25
20
 
26
- - Fixed request-time module loading, host-runner interop, and include or layout HMR across Bun, Vite, and Nitro development flows.
27
- - Fixed published core build helpers to expose runtime specifier alias rewriting through the package export surface so integrations do not couple to core source-file paths.
28
- - Fixed Bun-backed browser asset output normalization to preserve concrete hashed filenames instead of leaking literal `[hash]` placeholders into emitted script URLs.
29
- - Fixed generated module wrapper scripts to emit canonical named-import order so identical logical wrappers reuse the same bundled asset across routes.
30
- - Fixed preview, static-generation, and browser bundle stability for esbuild-backed production paths.
31
- - Fixed deep marker-graph resolution, watch-mode route refreshes, and duplicate-core fallback references in mixed-runtime rendering.
32
- - Fixed deferred boundary child serialization to accept explicit template-shape payloads while ignoring unrelated plain-object props unless a renderer-specific serializer or node-like shape supports them.
33
- - Fixed page-root and marker-graph rendering to preserve captured component graph context and render deferred foreign components under the correct integration context.
34
- - Fixed npm package output to rewrite workspace dependency versions and publish built JavaScript and declaration artifacts.
35
- - Fixed app build manifest collection to let integrations contribute browser-only build plugins without rewriting server static-page modules.
36
- - Fixed Node-side page-module transpilation to target ES2022 so decorator-based server imports preserve modern ESM semantics during development and MDX loading.
37
- - Fixed the public `EcoPageFile` type to include explicit `componentGraphContext` exports used by marker-graph page loading.
38
- - Fixed cross-integration shell authoring to expose a shared public `EcoChildren` type instead of forcing local boundary-cast patterns in mixed JSX demos.
39
- - Fixed object-form `dependencies.scripts` entries with `content` (no `src`) to emit as blocking inline script tags instead of being bundled into hashed external files.
40
- - Fixed the shared foreign-JSX override build plugin to preserve JSX versus TSX loader behavior and relative-import resolution in host-owned browser bundles.
41
- - Fixed deferred child serialization to preserve JSX node-like payloads without leaking `nodeType` digits into mixed-integration SSR output.
42
- - Fixed deferred template-child serialization to preserve quoted Ecopages JSX attribute values when mixed-integration boundaries pass JSX output through foreign shells.
43
- - Fixed fallback component references to prefer injected `__eco` metadata and share process-wide runtime ids across duplicate module instances without eager stack-based hint registration.
21
+ - Fixed mixed-integration page, layout, document, and component rendering to resolve foreign boundaries inside their owning renderer across the built-in integrations.
22
+ - Fixed host/runtime module loading, published build-helper exports, asset output normalization, explicit render flows, and static or preview build stability across Bun, Node, Vite, and Nitro.
44
23
 
45
24
  ### Documentation
46
25
 
@@ -48,12 +27,12 @@ All notable changes to `@ecopages/core` are documented here.
48
27
 
49
28
  ### Tests
50
29
 
51
- - Added regression coverage for Node fallback paths, shared runtime services, and cross-runtime invalidation behavior.
30
+ - Added regression coverage for app-owned runtime services, Node fallback paths, and cross-runtime invalidation behavior.
52
31
 
53
32
  ---
54
33
 
55
34
  ## Migration Notes
56
35
 
57
- - `createApp` is now the recommended entrypoint. Import it from `@ecopages/core`.
36
+ - `createApp` is now the recommended entrypoint. Import it from `@ecopages/core/create-app`.
58
37
  - `defineApiHandler` keeps the same call shape, but the handler context is now explicitly runtime-agnostic.
59
38
  - The old explicit `renderingMode` config option has been removed and full orchestration is always active.
package/README.md CHANGED
@@ -134,7 +134,7 @@ export default config;
134
134
  Start the application using `createApp`. It will choose the Bun adapter when Bun is available and fall back to Node otherwise.
135
135
 
136
136
  ```typescript
137
- import { createApp } from '@ecopages/core';
137
+ import { createApp } from '@ecopages/core/create-app';
138
138
  import appConfig from './eco.config';
139
139
 
140
140
  const app = await createApp({ appConfig });
@@ -198,7 +198,7 @@ Attach the handler in your `app.ts` entry:
198
198
 
199
199
  ```typescript
200
200
  // app.ts
201
- import { createApp } from '@ecopages/core';
201
+ import { createApp } from '@ecopages/core/create-app';
202
202
  import { helloWorld } from './handlers/hello';
203
203
  import appConfig from './eco.config';
204
204
 
@@ -213,10 +213,11 @@ See the [official documentation](https://ecopages.app) for advanced usage, API h
213
213
 
214
214
  ## Import Structure
215
215
 
216
- Use the root package exports for standard authoring in Bun-native flows:
216
+ Use the `create-app` subpath for runtime startup and the root package for standard authoring helpers:
217
217
 
218
218
  ```ts
219
- import { createApp, defineApiHandler, defineGroupHandler, eco } from '@ecopages/core';
219
+ import { createApp } from '@ecopages/core/create-app';
220
+ import { defineApiHandler, defineGroupHandler, eco } from '@ecopages/core';
220
221
  ```
221
222
 
222
223
  > [!NOTE]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/core",
3
- "version": "0.2.0-alpha.12",
3
+ "version": "0.2.0-alpha.13",
4
4
  "description": "Core package for Ecopages",
5
5
  "keywords": [
6
6
  "ecopages",
@@ -17,7 +17,7 @@
17
17
  "directory": "packages/core"
18
18
  },
19
19
  "dependencies": {
20
- "@ecopages/file-system": "0.2.0-alpha.12",
20
+ "@ecopages/file-system": "0.2.0-alpha.13",
21
21
  "@ecopages/logger": "^0.2.3",
22
22
  "@ecopages/scripts-injector": "^0.1.3",
23
23
  "@worker-tools/html-rewriter": "0.1.0-pre.19",
@@ -251,7 +251,7 @@ class HmrManager {
251
251
  */
252
252
  async registerEntrypoint(entrypointPath) {
253
253
  return await this.entrypointRegistrar.registerEntrypoint(entrypointPath, {
254
- emit: async (normalizedEntrypoint, outputPath) => await this.emitStrictEntrypoint(normalizedEntrypoint, outputPath),
254
+ emit: async (normalizedEntrypoint) => await this.emitStrictEntrypoint(normalizedEntrypoint),
255
255
  getMissingOutputError: (normalizedEntrypoint, outputPath) => new Error(
256
256
  `[HMR] Integration failed to emit entrypoint ${normalizedEntrypoint} to ${outputPath}. Page entrypoints must be produced by their owning integration.`
257
257
  )
@@ -278,7 +278,7 @@ class HmrManager {
278
278
  * strategy processing without broadcasting, and then verifies that the owning
279
279
  * integration emitted the expected file.
280
280
  */
281
- async emitStrictEntrypoint(entrypointPath, _outputPath) {
281
+ async emitStrictEntrypoint(entrypointPath) {
282
282
  await this.handleFileChange(entrypointPath, { broadcast: false });
283
283
  }
284
284
  /**
@@ -225,7 +225,7 @@ class NodeHmrManager {
225
225
  */
226
226
  async registerEntrypoint(entrypointPath) {
227
227
  return await this.entrypointRegistrar.registerEntrypoint(entrypointPath, {
228
- emit: async (normalizedEntrypoint, outputPath) => await this.emitStrictEntrypoint(normalizedEntrypoint, outputPath),
228
+ emit: async (normalizedEntrypoint) => await this.emitStrictEntrypoint(normalizedEntrypoint),
229
229
  getMissingOutputError: (normalizedEntrypoint, outputPath) => new Error(
230
230
  `[HMR] Integration failed to emit entrypoint ${normalizedEntrypoint} to ${outputPath}. Page entrypoints must be produced by their owning integration.`
231
231
  )
@@ -255,7 +255,7 @@ class NodeHmrManager {
255
255
  * 3. Let the strategy chain try to emit the entrypoint without broadcasting.
256
256
  * 4. Fail if the owning integration did not emit the expected output.
257
257
  */
258
- async emitStrictEntrypoint(entrypointPath, _outputPath) {
258
+ async emitStrictEntrypoint(entrypointPath) {
259
259
  await this.handleFileChange(entrypointPath, { broadcast: false });
260
260
  }
261
261
  /**
@@ -132,7 +132,7 @@ export declare class NodeServerAdapter extends SharedServerAdapter<NodeServerAda
132
132
  * underlying socket closes early — into a 499 response so it does not
133
133
  * incorrectly surface as a 500 in application logs.
134
134
  */
135
- handleRequest(_request: Request): Promise<Response>;
135
+ handleRequest(request: Request): Promise<Response>;
136
136
  /**
137
137
  * Called once the HTTP server is bound and listening.
138
138
  *
@@ -149,7 +149,7 @@ export declare class NodeServerAdapter extends SharedServerAdapter<NodeServerAda
149
149
  * WebSocket upgrade requests that do not target `/_hmr` are rejected with an
150
150
  * immediate socket destroy to prevent unhandled upgrade leaks.
151
151
  */
152
- completeInitialization(_server: NodeServerInstance): Promise<void>;
152
+ completeInitialization(server: NodeServerInstance): Promise<void>;
153
153
  }
154
154
  /**
155
155
  * Factory function that creates and fully initialises a `NodeServerAdapter`.
@@ -269,12 +269,12 @@ class NodeServerAdapter extends SharedServerAdapter {
269
269
  * underlying socket closes early — into a 499 response so it does not
270
270
  * incorrectly surface as a 500 in application logs.
271
271
  */
272
- async handleRequest(_request) {
272
+ async handleRequest(request) {
273
273
  if (!this.initialized) {
274
274
  throw new Error("Node server adapter is not initialized. Call createAdapter() first.");
275
275
  }
276
276
  try {
277
- return await this.handleSharedRequest(_request, {
277
+ return await this.handleSharedRequest(request, {
278
278
  apiHandlers: this.apiHandlers,
279
279
  errorHandler: this.errorHandler,
280
280
  serverInstance: this.serverInstance,
@@ -303,8 +303,8 @@ class NodeServerAdapter extends SharedServerAdapter {
303
303
  * WebSocket upgrade requests that do not target `/_hmr` are rejected with an
304
304
  * immediate socket destroy to prevent unhandled upgrade leaks.
305
305
  */
306
- async completeInitialization(_server) {
307
- this.serverInstance = _server;
306
+ async completeInitialization(server) {
307
+ this.serverInstance = server;
308
308
  if (this.options?.watch) {
309
309
  const { NodeHmrManager } = await import("./node-hmr-manager.js");
310
310
  const { WebSocketServer } = await import("ws");
@@ -313,7 +313,7 @@ class NodeServerAdapter extends SharedServerAdapter {
313
313
  this.hmrManager = new NodeHmrManager({ appConfig: this.appConfig, bridge: this.bridge });
314
314
  this.hmrManager.setEnabled(true);
315
315
  await this.hmrManager.buildRuntime();
316
- _server.on("upgrade", (req, socket, head) => {
316
+ server.on("upgrade", (req, socket, head) => {
317
317
  const url = new URL(req.url ?? "/", this.runtimeOrigin);
318
318
  if (url.pathname === "/_hmr") {
319
319
  wss.handleUpgrade(req, socket, head, (ws) => {
@@ -130,9 +130,10 @@ export declare function createBuildAdapter(options?: {
130
130
  export declare const defaultBunBuildAdapter: BuildAdapter;
131
131
  export declare const defaultViteHostBuildAdapter: BuildAdapter;
132
132
  /**
133
- * @deprecated Prefer app-owned build state via `getAppBuildAdapter()`.
134
- * This Bun-native fallback remains only for compatibility with older helpers
135
- * and tests that do not yet thread app runtime state explicitly.
133
+ * Bun-native fallback export for callsites that still resolve build state
134
+ * globally.
135
+ *
136
+ * New app-aware code should prefer `getAppBuildAdapter()`.
136
137
  */
137
138
  export declare const defaultBuildAdapter: BuildAdapter;
138
139
  export declare function getDefaultBuildAdapter(ownership?: BuildOwnership): BuildAdapter;
@@ -224,9 +225,9 @@ export declare function setAppBuildExecutor(appConfig: EcoPagesAppConfig, buildE
224
225
  */
225
226
  export declare function build(options: BuildOptions, executor?: BuildExecutor): Promise<BuildResult>;
226
227
  /**
227
- * @deprecated Prefer `getAppTranspileOptions()` for finalized app/runtime work.
228
- * This helper exists only for compatibility with Bun-native callsites that do
229
- * not yet have app context available.
228
+ * Bun-native fallback helper for callsites without app runtime context.
229
+ *
230
+ * New app-aware code should prefer `getAppTranspileOptions()`.
230
231
  */
231
232
  export declare function getTranspileOptions(profile: BuildTranspileProfile): BuildTranspileOptions;
232
233
  export declare function getAppTranspileOptions(appConfig: EcoPagesAppConfig, profile: BuildTranspileProfile): BuildTranspileOptions;
@@ -227,9 +227,7 @@ class BunBuildAdapter {
227
227
  return void 0;
228
228
  }
229
229
  const basenamePattern = path.basename(outputPath);
230
- const matcher = new RegExp(
231
- `^${this.escapeRegExp(basenamePattern).replace(/\\\[hash\\\]/g, "(.+)")}$`
232
- );
230
+ const matcher = new RegExp(`^${this.escapeRegExp(basenamePattern).replace(/\\\[hash\\\]/g, "(.+)")}$`);
233
231
  const matches = fs.readdirSync(directory).filter((candidate) => matcher.test(candidate)).sort();
234
232
  if (matches.length === 0) {
235
233
  return void 0;
@@ -259,9 +257,7 @@ class BunBuildAdapter {
259
257
  return path.join(outdir, resolvedPath);
260
258
  }
261
259
  const concreteRelativePath = path.relative(outdir, concreteOutputPath).split(path.sep).join("/");
262
- const matcher = new RegExp(
263
- `^${this.escapeRegExp(resolvedPath).replace(/\\\[hash\\\]/g, "(.+)")}$`
264
- );
260
+ const matcher = new RegExp(`^${this.escapeRegExp(resolvedPath).replace(/\\\[hash\\\]/g, "(.+)")}$`);
265
261
  const match = concreteRelativePath.match(matcher);
266
262
  if (!match?.[1]) {
267
263
  return concreteOutputPath;
@@ -293,7 +289,10 @@ class BunBuildAdapter {
293
289
  continue;
294
290
  }
295
291
  normalizedOutputs[index] = {
296
- path: this.relocateOutputFile(concreteOutputPath ?? normalizedOutputs[index].path, expectedOutputPath)
292
+ path: this.relocateOutputFile(
293
+ concreteOutputPath ?? normalizedOutputs[index].path,
294
+ expectedOutputPath
295
+ )
297
296
  };
298
297
  }
299
298
  return {
package/src/eco/eco.js CHANGED
@@ -1,18 +1,27 @@
1
- import { finalizeComponentRender, tryRenderDeferredBoundary } from "./component-render-context.js";
1
+ import {
2
+ finalizeComponentRender,
3
+ interceptComponentBoundary
4
+ } from "../route-renderer/orchestration/component-render-context.js";
5
+ import { isThenable } from "../route-renderer/orchestration/render-output.utils.js";
2
6
  function createComponentFactory(options) {
3
7
  const integrationName = options.integration ?? options.__eco?.integration;
4
8
  const comp = ((props) => {
5
9
  const componentProps = props ?? {};
6
- const deferredRender = tryRenderDeferredBoundary({
10
+ const renderInline = () => finalizeComponentRender(comp, options.render(props));
11
+ const boundaryRender = interceptComponentBoundary({
7
12
  component: comp,
8
13
  props: componentProps,
9
14
  targetIntegration: integrationName
10
15
  });
11
- if (deferredRender !== void 0) {
12
- return deferredRender;
16
+ if (isThenable(boundaryRender)) {
17
+ return boundaryRender.then(
18
+ (resolvedBoundaryRender) => resolvedBoundaryRender !== void 0 ? resolvedBoundaryRender : renderInline()
19
+ );
13
20
  }
14
- const content = options.render(props);
15
- return finalizeComponentRender(comp, content);
21
+ if (boundaryRender !== void 0) {
22
+ return boundaryRender;
23
+ }
24
+ return renderInline();
16
25
  });
17
26
  comp.config = {
18
27
  __eco: options.__eco,
@@ -1 +1 @@
1
- export { addTriggerAttribute, isThenable, wrapWithScriptsInjector } from '../route-renderer/orchestration/render-output.utils.js';
1
+ export { addTriggerAttribute, isThenable, wrapWithScriptsInjector, } from '../route-renderer/orchestration/render-output.utils.js';
@@ -1,4 +1,8 @@
1
- import { addTriggerAttribute, isThenable, wrapWithScriptsInjector } from "../route-renderer/orchestration/render-output.utils.js";
1
+ import {
2
+ addTriggerAttribute,
3
+ isThenable,
4
+ wrapWithScriptsInjector
5
+ } from "../route-renderer/orchestration/render-output.utils.js";
2
6
  export {
3
7
  addTriggerAttribute,
4
8
  isThenable,
@@ -77,8 +77,8 @@ export interface HmrAction {
77
77
  * whether they match the changed file path.
78
78
  *
79
79
  * @remarks
80
- * Strategies are expected to be stateless and idempotent. The same file change
81
- * should produce the same result when processed by the same strategy.
80
+ * Strategies are expected to be stateless and idempotent. The same file change
81
+ * should produce the same result when processed by the same strategy.
82
82
  *
83
83
  * @example
84
84
  * ```typescript
@@ -2,7 +2,7 @@
2
2
  * This module contains the ghtml renderer
3
3
  * @module
4
4
  */
5
- import type { EcoComponent, EcoPagesElement, IntegrationRendererRenderOptions, RouteRendererBody } from '../../types/public-types.js';
5
+ import type { ComponentRenderInput, ComponentRenderResult, EcoComponent, EcoPagesElement, IntegrationRendererRenderOptions, RouteRendererBody } from '../../types/public-types.js';
6
6
  import { IntegrationRenderer, type RenderToResponseContext } from '../../route-renderer/orchestration/integration-renderer.js';
7
7
  /**
8
8
  * A renderer for the ghtml integration.
@@ -10,6 +10,11 @@ import { IntegrationRenderer, type RenderToResponseContext } from '../../route-r
10
10
  */
11
11
  export declare class GhtmlRenderer extends IntegrationRenderer<EcoPagesElement> {
12
12
  name: string;
13
+ renderComponent(input: ComponentRenderInput): Promise<ComponentRenderResult>;
14
+ protected createComponentBoundaryRuntime(options: {
15
+ boundaryInput: ComponentRenderInput;
16
+ rendererCache: Map<string, IntegrationRenderer<any>>;
17
+ }): import("../../index.browser.js").ComponentBoundaryRuntime;
13
18
  render({ params, query, props, locals, pageLocals, metadata, Page, Layout, HtmlTemplate, }: IntegrationRendererRenderOptions): Promise<RouteRendererBody>;
14
19
  renderToResponse<P = Record<string, unknown>>(view: EcoComponent<P>, props: P, ctx: RenderToResponseContext): Promise<Response>;
15
20
  }
@@ -4,6 +4,18 @@ import {
4
4
  import { GHTML_PLUGIN_NAME } from "./ghtml.plugin.js";
5
5
  class GhtmlRenderer extends IntegrationRenderer {
6
6
  name = GHTML_PLUGIN_NAME;
7
+ async renderComponent(input) {
8
+ return this.renderStringComponentBoundaryWithQueuedForeignBoundaries(
9
+ input,
10
+ input.component
11
+ );
12
+ }
13
+ createComponentBoundaryRuntime(options) {
14
+ return this.createQueuedBoundaryRuntime({
15
+ boundaryInput: options.boundaryInput,
16
+ rendererCache: options.rendererCache
17
+ });
18
+ }
7
19
  async render({
8
20
  params,
9
21
  query,
@@ -16,42 +28,31 @@ class GhtmlRenderer extends IntegrationRenderer {
16
28
  HtmlTemplate
17
29
  }) {
18
30
  try {
19
- const pageContent = await Page({ params, query, ...props, locals: pageLocals });
20
- const children = Layout && typeof Layout === "function" ? await Layout({ children: pageContent, locals }) : pageContent;
21
- const body = await HtmlTemplate({
31
+ return await this.renderPageWithDocumentShell({
32
+ page: {
33
+ component: Page,
34
+ props: { params, query, ...props, locals: pageLocals }
35
+ },
36
+ layout: Layout ? {
37
+ component: Layout,
38
+ props: locals ? { locals } : {}
39
+ } : void 0,
40
+ htmlTemplate: HtmlTemplate,
22
41
  metadata,
23
- children,
24
- pageProps: props || {}
42
+ pageProps: props ?? {}
25
43
  });
26
- return this.DOC_TYPE + body;
27
44
  } catch (error) {
28
45
  throw this.createRenderError("Error rendering page", error);
29
46
  }
30
47
  }
31
48
  async renderToResponse(view, props, ctx) {
32
49
  try {
33
- const Layout = view.config?.layout;
34
- const viewFn = view;
35
- const pageContent = await viewFn(props);
36
- let body;
37
- if (ctx.partial) {
38
- body = pageContent;
39
- } else {
40
- const children = Layout ? await Layout({ children: pageContent }) : pageContent;
41
- const HtmlTemplate = await this.getHtmlTemplate();
42
- const metadata = view.metadata ? await view.metadata({
43
- params: {},
44
- query: {},
45
- props,
46
- appConfig: this.appConfig
47
- }) : this.appConfig.defaultMetadata;
48
- body = this.DOC_TYPE + await HtmlTemplate({
49
- metadata,
50
- children,
51
- pageProps: props
52
- });
53
- }
54
- return this.createHtmlResponse(body, ctx);
50
+ return await this.renderViewWithDocumentShell({
51
+ view,
52
+ props,
53
+ ctx,
54
+ layout: view.config?.layout
55
+ });
55
56
  } catch (error) {
56
57
  throw this.createRenderError("Error rendering view", error);
57
58
  }
@@ -1,7 +1,7 @@
1
1
  import type { EcoBuildPlugin } from '../build/build-types.js';
2
2
  import type { EcoPagesAppConfig, IHmrManager } from '../types/internal-types.js';
3
3
  import type { HmrStrategy } from '../hmr/hmr-strategy.js';
4
- import type { EcoComponent, EcoPagesElement } from '../types/public-types.js';
4
+ import type { EcoPagesElement } from '../types/public-types.js';
5
5
  import type { IntegrationRenderer } from '../route-renderer/orchestration/integration-renderer.js';
6
6
  import { AssetProcessingService } from '../services/assets/asset-processing-service/asset-processing.service.js';
7
7
  import type { AssetDefinition, ProcessedAsset } from '../services/assets/asset-processing-service/assets.types.js';
@@ -56,17 +56,6 @@ export interface IntegrationPluginConfig {
56
56
  */
57
57
  jsxImportSource?: string;
58
58
  }
59
- /**
60
- * Metadata used by integration-owned boundary policy.
61
- *
62
- * This payload describes the currently active integration pass together with the
63
- * target component boundary being entered.
64
- */
65
- export type ComponentBoundaryPolicyInput = {
66
- currentIntegration: string;
67
- targetIntegration?: string;
68
- component: EcoComponent;
69
- };
70
59
  type RendererClass<C> = new (options: {
71
60
  appConfig: EcoPagesAppConfig;
72
61
  assetProcessingService: AssetProcessingService;
@@ -187,18 +176,6 @@ export declare abstract class IntegrationPlugin<C = EcoPagesElement> {
187
176
  initializeRenderer(options?: {
188
177
  rendererModules?: unknown;
189
178
  }): IntegrationRenderer<C>;
190
- /**
191
- * Declares whether a component boundary targeting this integration should be
192
- * deferred through the marker pipeline.
193
- *
194
- * The default implementation never defers. Integrations that require deferred
195
- * subtree rendering can override this method and return `true` when their
196
- * boundary must be resolved during the marker graph stage.
197
- *
198
- * @param input Boundary metadata for the current render pass.
199
- * @returns `true` when the boundary should be deferred; otherwise `false`.
200
- */
201
- shouldDeferComponentBoundary(_input: ComponentBoundaryPolicyInput): boolean;
202
179
  /**
203
180
  * Prepares build-facing contributions before the app build manifest is sealed.
204
181
  *
@@ -140,20 +140,6 @@ class IntegrationPlugin {
140
140
  }
141
141
  return renderer;
142
142
  }
143
- /**
144
- * Declares whether a component boundary targeting this integration should be
145
- * deferred through the marker pipeline.
146
- *
147
- * The default implementation never defers. Integrations that require deferred
148
- * subtree rendering can override this method and return `true` when their
149
- * boundary must be resolved during the marker graph stage.
150
- *
151
- * @param input Boundary metadata for the current render pass.
152
- * @returns `true` when the boundary should be deferred; otherwise `false`.
153
- */
154
- shouldDeferComponentBoundary(_input) {
155
- return false;
156
- }
157
143
  /**
158
144
  * Prepares build-facing contributions before the app build manifest is sealed.
159
145
  *