@ecopages/kitajs 0.2.0-alpha.8 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -4,20 +4,16 @@ All notable changes to `@ecopages/kitajs` are documented here.
4
4
 
5
5
  > **Note:** Changelog tracking begins at version `0.2.0`. Changes prior to this release are not recorded here but are available in the git history.
6
6
 
7
- ## [UNRELEASED] — TBD
7
+ ## [0.2.1] — 2026-04-16
8
8
 
9
9
  ### Bug Fixes
10
10
 
11
- - Fixed explicit `ctx.render()` flows so deferred cross-integration layout components resolve through the marker pipeline instead of crashing during direct server rendering.
11
+ - Fixed Kita full-route and direct `ctx.render()` rendering to stay on the renderer-owned page/layout/document path while resolving mixed boundaries inside the owning renderer.
12
12
 
13
- ### Features
13
+ ### Documentation
14
14
 
15
- - Aligned KitaJS with the unified orchestration pipeline.
16
-
17
- ### Refactoring
18
-
19
- - Tightened Kita component typing and cleaned up ambient module declarations.
15
+ - Updated the README to document `.kita.tsx` route ownership and Kita's role as an outer shell in mixed-renderer apps.
20
16
 
21
17
  ### Tests
22
18
 
23
- - Updated integration coverage for the orchestration pipeline and Node and esbuild compatibility.
19
+ - Updated integration coverage for explicit boundary composition and Node and esbuild compatibility.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ecopages/kitajs
2
2
 
3
- Integration plugin for [KitaJS](https://kitajs.org/html/) HTML within the Ecopages framework. It enables the rendering of standard JSX templates for multi-page applications.
3
+ Integration plugin for [KitaJS](https://kitajs.org/html/) HTML in Ecopages. Use it when Kita should own `.kita.tsx` routes, page shells, and document shells in HTML-first apps.
4
4
 
5
5
  ## Installation
6
6
 
@@ -23,3 +23,13 @@ const config = await new ConfigBuilder()
23
23
 
24
24
  export default config;
25
25
  ```
26
+
27
+ ## What This Integration Owns
28
+
29
+ - `.kita.tsx` route files.
30
+ - Page, layout, and document shells rendered by `@kitajs/html`.
31
+ - HTML-first outer shells that host nested component boundaries from other integrations.
32
+
33
+ ## Mixed Rendering
34
+
35
+ Kita works well as the outer renderer in mixed apps. When a Kita-owned page encounters a nested boundary from another integration, Ecopages resolves that boundary with its owning renderer and inserts the resulting HTML back into the Kita shell.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopages/kitajs",
3
- "version": "0.2.0-alpha.8",
3
+ "version": "0.2.1",
4
4
  "description": "Kitajs plugin for Ecopages",
5
5
  "keywords": [
6
6
  "ecopages",
@@ -17,7 +17,7 @@
17
17
  "directory": "packages/integrations/kitajs"
18
18
  },
19
19
  "peerDependencies": {
20
- "@ecopages/core": "0.2.0-alpha.8",
20
+ "@ecopages/core": "0.2.1",
21
21
  "@kitajs/html": "^4.1.0",
22
22
  "@kitajs/ts-html-plugin": "^4.0.1"
23
23
  }
@@ -16,6 +16,10 @@ export declare class KitaRenderer extends IntegrationRenderer<EcoPagesElement> {
16
16
  * Includes component-scoped dependency assets when declared.
17
17
  */
18
18
  renderComponent(input: ComponentRenderInput): Promise<ComponentRenderResult>;
19
+ protected createComponentBoundaryRuntime(options: {
20
+ boundaryInput: ComponentRenderInput;
21
+ rendererCache: Map<string, IntegrationRenderer<any>>;
22
+ }): import("@ecopages/core").ComponentBoundaryRuntime;
19
23
  render({ params, query, props, locals, pageLocals, metadata, Page, Layout, HtmlTemplate, }: IntegrationRendererRenderOptions): Promise<RouteRendererBody>;
20
24
  renderToResponse<P = Record<string, unknown>>(view: EcoComponent<P>, props: P, ctx: RenderToResponseContext): Promise<Response>;
21
25
  }
@@ -8,20 +8,16 @@ class KitaRenderer extends IntegrationRenderer {
8
8
  * Includes component-scoped dependency assets when declared.
9
9
  */
10
10
  async renderComponent(input) {
11
- const component = input.component;
12
- const props = input.children === void 0 ? input.props : { ...input.props, children: input.children };
13
- const content = await component(props);
14
- const html = String(content);
15
- const hasDependencies = Boolean(input.component.config?.dependencies);
16
- const canResolveAssets = typeof this.assetProcessingService?.processDependencies === "function";
17
- const assets = hasDependencies && canResolveAssets ? await this.processComponentDependencies([input.component]) : void 0;
18
- return {
19
- html,
20
- canAttachAttributes: true,
21
- rootTag: this.getRootTagName(html),
22
- integrationName: this.name,
23
- assets
24
- };
11
+ return this.renderStringComponentBoundaryWithQueuedForeignBoundaries(
12
+ input,
13
+ input.component
14
+ );
15
+ }
16
+ createComponentBoundaryRuntime(options) {
17
+ return this.createQueuedBoundaryRuntime({
18
+ boundaryInput: options.boundaryInput,
19
+ rendererCache: options.rendererCache
20
+ });
25
21
  }
26
22
  async render({
27
23
  params,
@@ -35,52 +31,31 @@ class KitaRenderer extends IntegrationRenderer {
35
31
  HtmlTemplate
36
32
  }) {
37
33
  try {
38
- const pageContent = await Page({ params, query, ...props, locals: pageLocals });
39
- const children = Layout && typeof Layout === "function" ? await Layout({ children: pageContent, locals }) : pageContent;
40
- const body = await HtmlTemplate({
34
+ return await this.renderPageWithDocumentShell({
35
+ page: {
36
+ component: Page,
37
+ props: { params, query, ...props, locals: pageLocals }
38
+ },
39
+ layout: Layout ? {
40
+ component: Layout,
41
+ props: locals ? { locals } : {}
42
+ } : void 0,
43
+ htmlTemplate: HtmlTemplate,
41
44
  metadata,
42
- pageProps: props ?? {},
43
- children
45
+ pageProps: props ?? {}
44
46
  });
45
- return this.DOC_TYPE + body;
46
47
  } catch (error) {
47
48
  throw this.createRenderError("Error rendering page", error);
48
49
  }
49
50
  }
50
51
  async renderToResponse(view, props, ctx) {
51
52
  try {
52
- const Layout = view.config?.layout;
53
- const HtmlTemplate = ctx.partial ? void 0 : await this.getHtmlTemplate();
54
- const metadata = ctx.partial || !HtmlTemplate ? void 0 : view.metadata ? await view.metadata({
55
- params: {},
56
- query: {},
53
+ return await this.renderViewWithDocumentShell({
54
+ view,
57
55
  props,
58
- appConfig: this.appConfig
59
- }) : this.appConfig.defaultMetadata;
60
- if (!ctx.partial) {
61
- await this.prepareViewDependencies(view, Layout);
62
- }
63
- const viewFn = view;
64
- const renderExecution = await this.captureHtmlRender(async () => {
65
- const pageContent = await viewFn(props);
66
- if (ctx.partial) {
67
- return pageContent;
68
- }
69
- const children = Layout ? await Layout({ children: pageContent }) : pageContent;
70
- return this.DOC_TYPE + await HtmlTemplate({
71
- metadata: metadata ?? this.appConfig.defaultMetadata,
72
- pageProps: props ?? {},
73
- children: children ?? ""
74
- });
75
- });
76
- const componentsToResolve = ctx.partial ? [view] : [HtmlTemplate, Layout, view].filter(Boolean);
77
- const body = await this.finalizeCapturedHtmlRender({
78
- html: renderExecution.html,
79
- componentsToResolve,
80
- graphContext: renderExecution.graphContext,
81
- partial: ctx.partial
56
+ ctx,
57
+ layout: view.config?.layout
82
58
  });
83
- return this.createHtmlResponse(body, ctx);
84
59
  } catch (error) {
85
60
  throw this.createRenderError("Error rendering view", error);
86
61
  }
@@ -7,6 +7,7 @@ class KitaHtmlPlugin extends IntegrationPlugin {
7
7
  super({
8
8
  name: PLUGIN_NAME,
9
9
  extensions: [".kita.tsx"],
10
+ jsxImportSource: "@kitajs/html",
10
11
  ...options
11
12
  });
12
13
  }
@@ -1,141 +0,0 @@
1
- /**
2
- * This module contains the Kita.js renderer
3
- * @module
4
- */
5
-
6
- import type {
7
- ComponentRenderInput,
8
- ComponentRenderResult,
9
- EcoComponent,
10
- EcoPagesElement,
11
- IntegrationRendererRenderOptions,
12
- RouteRendererBody,
13
- } from '@ecopages/core';
14
- import { IntegrationRenderer, type RenderToResponseContext } from '@ecopages/core/route-renderer/integration-renderer';
15
- import { PLUGIN_NAME } from './kitajs.plugin.ts';
16
-
17
- /** Narrows an EcoComponent to its KitaJS callable signature. */
18
- type KitaViewFn<P> = (props: P) => Promise<EcoPagesElement> | EcoPagesElement;
19
-
20
- /** KitaJS layout function signature. */
21
- type KitaLayoutFn = (props: { children: EcoPagesElement } & Record<string, unknown>) => Promise<EcoPagesElement>;
22
-
23
- /**
24
- * A renderer for the Kita.js integration.
25
- * It renders a page using the HtmlTemplate and Page components.
26
- */
27
- export class KitaRenderer extends IntegrationRenderer<EcoPagesElement> {
28
- name = PLUGIN_NAME;
29
-
30
- /**
31
- * Renders a Kita component boundary for component-level orchestration.
32
- *
33
- * Includes component-scoped dependency assets when declared.
34
- */
35
- override async renderComponent(input: ComponentRenderInput): Promise<ComponentRenderResult> {
36
- const component = input.component as KitaViewFn<Record<string, unknown>>;
37
- const props = input.children === undefined ? input.props : { ...input.props, children: input.children };
38
- const content = await component(props);
39
- const html = String(content);
40
- const hasDependencies = Boolean(input.component.config?.dependencies);
41
- const canResolveAssets = typeof this.assetProcessingService?.processDependencies === 'function';
42
- const assets =
43
- hasDependencies && canResolveAssets
44
- ? await this.processComponentDependencies([input.component])
45
- : undefined;
46
-
47
- return {
48
- html,
49
- canAttachAttributes: true,
50
- rootTag: this.getRootTagName(html),
51
- integrationName: this.name,
52
- assets,
53
- };
54
- }
55
-
56
- async render({
57
- params,
58
- query,
59
- props,
60
- locals,
61
- pageLocals,
62
- metadata,
63
- Page,
64
- Layout,
65
- HtmlTemplate,
66
- }: IntegrationRendererRenderOptions): Promise<RouteRendererBody> {
67
- try {
68
- const pageContent = await Page({ params, query, ...props, locals: pageLocals });
69
- const children =
70
- Layout && typeof Layout === 'function' ? await Layout({ children: pageContent, locals }) : pageContent;
71
- const body = await HtmlTemplate({
72
- metadata,
73
- pageProps: props ?? {},
74
- children,
75
- });
76
-
77
- return this.DOC_TYPE + body;
78
- } catch (error) {
79
- throw this.createRenderError('Error rendering page', error);
80
- }
81
- }
82
-
83
- async renderToResponse<P = Record<string, unknown>>(
84
- view: EcoComponent<P>,
85
- props: P,
86
- ctx: RenderToResponseContext,
87
- ): Promise<Response> {
88
- try {
89
- const Layout = view.config?.layout as KitaLayoutFn | undefined;
90
- const HtmlTemplate = ctx.partial ? undefined : await this.getHtmlTemplate();
91
- const metadata =
92
- ctx.partial || !HtmlTemplate
93
- ? undefined
94
- : view.metadata
95
- ? await view.metadata({
96
- params: {},
97
- query: {},
98
- props: props as Record<string, unknown>,
99
- appConfig: this.appConfig,
100
- })
101
- : this.appConfig.defaultMetadata;
102
-
103
- if (!ctx.partial) {
104
- await this.prepareViewDependencies(view, Layout as EcoComponent | undefined);
105
- }
106
-
107
- const viewFn = view as KitaViewFn<P>;
108
- const renderExecution = await this.captureHtmlRender(async () => {
109
- const pageContent = await viewFn(props);
110
-
111
- if (ctx.partial) {
112
- return pageContent;
113
- }
114
-
115
- const children = Layout ? await Layout({ children: pageContent }) : pageContent;
116
- return (
117
- this.DOC_TYPE +
118
- (await HtmlTemplate!({
119
- metadata: metadata ?? this.appConfig.defaultMetadata,
120
- pageProps: (props as Record<string, unknown>) ?? {},
121
- children: children ?? '',
122
- }))
123
- );
124
- });
125
-
126
- const componentsToResolve = ctx.partial
127
- ? [view]
128
- : ([HtmlTemplate, Layout, view].filter(Boolean) as EcoComponent[]);
129
- const body = await this.finalizeCapturedHtmlRender({
130
- html: renderExecution.html,
131
- componentsToResolve,
132
- graphContext: renderExecution.graphContext,
133
- partial: ctx.partial,
134
- });
135
-
136
- return this.createHtmlResponse(body, ctx);
137
- } catch (error) {
138
- throw this.createRenderError('Error rendering view', error);
139
- }
140
- }
141
- }
@@ -1,32 +0,0 @@
1
- import { IntegrationPlugin, type IntegrationPluginConfig } from '@ecopages/core/plugins/integration-plugin';
2
- import { KitaRenderer } from './kitajs-renderer.ts';
3
-
4
- /**
5
- * The name of the Kita.js plugin
6
- */
7
- export const PLUGIN_NAME = 'kitajs';
8
-
9
- /**
10
- * The Kita.js plugin class
11
- * This plugin provides support for Kita.js components in Ecopages
12
- */
13
- export class KitaHtmlPlugin extends IntegrationPlugin {
14
- renderer = KitaRenderer;
15
-
16
- constructor(options?: Omit<IntegrationPluginConfig, 'name'>) {
17
- super({
18
- name: PLUGIN_NAME,
19
- extensions: ['.kita.tsx'],
20
- ...options,
21
- });
22
- }
23
- }
24
-
25
- /**
26
- * Factory function to create a Kita.js plugin instance.
27
- * @param options Configuration options for the Kita.js plugin
28
- * @returns A new KitaHtmlPlugin instance
29
- */
30
- export function kitajsPlugin(options?: Omit<IntegrationPluginConfig, 'name'>): KitaHtmlPlugin {
31
- return new KitaHtmlPlugin(options);
32
- }