@flightdev/ui 2.0.0

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 (118) hide show
  1. package/.turbo/turbo-build.log +81 -0
  2. package/.turbo/turbo-lint.log +40 -0
  3. package/.turbo/turbo-typecheck.log +4 -0
  4. package/LICENSE +21 -0
  5. package/README.md +92 -0
  6. package/TESTING.md +124 -0
  7. package/dist/adapter-MMD-iHNx.d.ts +424 -0
  8. package/dist/adapters/tier-1/angular.d.ts +60 -0
  9. package/dist/adapters/tier-1/angular.js +2 -0
  10. package/dist/adapters/tier-1/index.d.ts +7 -0
  11. package/dist/adapters/tier-1/index.js +7 -0
  12. package/dist/adapters/tier-1/qwik.d.ts +55 -0
  13. package/dist/adapters/tier-1/qwik.js +2 -0
  14. package/dist/adapters/tier-1/react.d.ts +67 -0
  15. package/dist/adapters/tier-1/react.js +2 -0
  16. package/dist/adapters/tier-1/solid.d.ts +45 -0
  17. package/dist/adapters/tier-1/solid.js +2 -0
  18. package/dist/adapters/tier-1/svelte.d.ts +48 -0
  19. package/dist/adapters/tier-1/svelte.js +2 -0
  20. package/dist/adapters/tier-1/vue.d.ts +47 -0
  21. package/dist/adapters/tier-1/vue.js +2 -0
  22. package/dist/adapters/tier-2/index.d.ts +7 -0
  23. package/dist/adapters/tier-2/index.js +7 -0
  24. package/dist/adapters/tier-2/inferno.d.ts +31 -0
  25. package/dist/adapters/tier-2/inferno.js +2 -0
  26. package/dist/adapters/tier-2/lit.d.ts +34 -0
  27. package/dist/adapters/tier-2/lit.js +2 -0
  28. package/dist/adapters/tier-2/marko.d.ts +59 -0
  29. package/dist/adapters/tier-2/marko.js +2 -0
  30. package/dist/adapters/tier-2/mithril.d.ts +31 -0
  31. package/dist/adapters/tier-2/mithril.js +2 -0
  32. package/dist/adapters/tier-2/preact.d.ts +33 -0
  33. package/dist/adapters/tier-2/preact.js +2 -0
  34. package/dist/adapters/tier-2/stencil.d.ts +52 -0
  35. package/dist/adapters/tier-2/stencil.js +2 -0
  36. package/dist/adapters/tier-3/alpine.d.ts +73 -0
  37. package/dist/adapters/tier-3/alpine.js +2 -0
  38. package/dist/adapters/tier-3/hotwire.d.ts +71 -0
  39. package/dist/adapters/tier-3/hotwire.js +2 -0
  40. package/dist/adapters/tier-3/htmx.d.ts +88 -0
  41. package/dist/adapters/tier-3/htmx.js +2 -0
  42. package/dist/adapters/tier-3/index.d.ts +7 -0
  43. package/dist/adapters/tier-3/index.js +7 -0
  44. package/dist/adapters/tier-3/petite-vue.d.ts +56 -0
  45. package/dist/adapters/tier-3/petite-vue.js +2 -0
  46. package/dist/adapters/tier-3/stimulus.d.ts +63 -0
  47. package/dist/adapters/tier-3/stimulus.js +2 -0
  48. package/dist/adapters/tier-3/vanilla.d.ts +63 -0
  49. package/dist/adapters/tier-3/vanilla.js +2 -0
  50. package/dist/chunk-2SNQ6PTM.js +217 -0
  51. package/dist/chunk-3D4XMIZI.js +136 -0
  52. package/dist/chunk-3HU6GSQ4.js +125 -0
  53. package/dist/chunk-4PZDNFL7.js +148 -0
  54. package/dist/chunk-5IBLFTYL.js +114 -0
  55. package/dist/chunk-64JZJ7OK.js +142 -0
  56. package/dist/chunk-7ZJI3QU2.js +132 -0
  57. package/dist/chunk-CE4FJHQJ.js +133 -0
  58. package/dist/chunk-DTCAUBH5.js +87 -0
  59. package/dist/chunk-NTASPOHG.js +106 -0
  60. package/dist/chunk-OI2AMQLG.js +152 -0
  61. package/dist/chunk-Q7HUE44H.js +106 -0
  62. package/dist/chunk-QH3LOWXU.js +155 -0
  63. package/dist/chunk-QIVAK6BH.js +103 -0
  64. package/dist/chunk-V34XPVGK.js +103 -0
  65. package/dist/chunk-VK7ZPMO7.js +221 -0
  66. package/dist/chunk-X6CNUW6T.js +136 -0
  67. package/dist/chunk-XTDK7ME5.js +382 -0
  68. package/dist/chunk-YFGSHW5S.js +121 -0
  69. package/dist/chunk-ZAJVSE7J.js +90 -0
  70. package/dist/core/index.d.ts +161 -0
  71. package/dist/core/index.js +2 -0
  72. package/dist/index.d.ts +103 -0
  73. package/dist/index.js +71 -0
  74. package/docs/ADAPTERS.md +946 -0
  75. package/docs/PATTERNS.md +836 -0
  76. package/package.json +229 -0
  77. package/src/adapters/tier-1/angular.ts +223 -0
  78. package/src/adapters/tier-1/index.ts +12 -0
  79. package/src/adapters/tier-1/qwik.ts +177 -0
  80. package/src/adapters/tier-1/react.ts +330 -0
  81. package/src/adapters/tier-1/solid.ts +222 -0
  82. package/src/adapters/tier-1/svelte.ts +211 -0
  83. package/src/adapters/tier-1/vue.ts +234 -0
  84. package/src/adapters/tier-2/index.ts +12 -0
  85. package/src/adapters/tier-2/inferno.ts +149 -0
  86. package/src/adapters/tier-2/lit.ts +191 -0
  87. package/src/adapters/tier-2/marko.ts +199 -0
  88. package/src/adapters/tier-2/mithril.ts +152 -0
  89. package/src/adapters/tier-2/preact.ts +133 -0
  90. package/src/adapters/tier-2/stencil.ts +214 -0
  91. package/src/adapters/tier-3/alpine.ts +218 -0
  92. package/src/adapters/tier-3/hotwire.ts +254 -0
  93. package/src/adapters/tier-3/htmx.ts +263 -0
  94. package/src/adapters/tier-3/index.ts +12 -0
  95. package/src/adapters/tier-3/petite-vue.ts +163 -0
  96. package/src/adapters/tier-3/stimulus.ts +233 -0
  97. package/src/adapters/tier-3/vanilla.ts +252 -0
  98. package/src/ambient.d.ts +310 -0
  99. package/src/core/adapter.ts +366 -0
  100. package/src/core/index.ts +56 -0
  101. package/src/core/registry.ts +518 -0
  102. package/src/core/types.ts +461 -0
  103. package/src/htmx.ts +134 -0
  104. package/src/index.ts +263 -0
  105. package/test/__mocks__/stencil-core.ts +19 -0
  106. package/test/__mocks__/stencil-hydrate.ts +15 -0
  107. package/test/adapters/tier-1.test.ts +206 -0
  108. package/test/adapters/tier-2.test.ts +175 -0
  109. package/test/adapters/tier-3.test.ts +284 -0
  110. package/test/contracts/adapter.contract.ts +293 -0
  111. package/test/core/core.test.ts +310 -0
  112. package/test/errors/error-handling.test.ts +454 -0
  113. package/test/integration/htmx.integration.test.ts +246 -0
  114. package/test/integration/react.integration.test.ts +271 -0
  115. package/test/integration/registry.integration.test.ts +308 -0
  116. package/tsconfig.json +22 -0
  117. package/tsup.config.ts +93 -0
  118. package/vitest.config.ts +101 -0
@@ -0,0 +1,211 @@
1
+ /**
2
+ * @flightdev/ui - Svelte Adapter (Tier 1)
3
+ *
4
+ * Full-featured Svelte 5 SSR adapter with hydration support.
5
+ *
6
+ * @module @flightdev/ui/svelte
7
+ * @version 2.0.0
8
+ */
9
+
10
+ import { BaseUIAdapter } from '../../core/adapter.js';
11
+ import type {
12
+ AdapterCapabilities,
13
+ Component,
14
+ RenderContext,
15
+ RenderResult,
16
+ } from '../../core/types.js';
17
+
18
+ // ============================================================================
19
+ // Types
20
+ // ============================================================================
21
+
22
+ export interface SvelteAdapterOptions {
23
+ /** Svelte compile options */
24
+ compileOptions?: Record<string, unknown>;
25
+
26
+ /** Enable CSS extraction */
27
+ extractCss?: boolean;
28
+ }
29
+
30
+ // ============================================================================
31
+ // Svelte Adapter
32
+ // ============================================================================
33
+
34
+ export class SvelteAdapter extends BaseUIAdapter {
35
+ readonly id = 'svelte';
36
+ readonly name = 'Svelte';
37
+ readonly framework = 'svelte';
38
+ readonly frameworkVersion = '5+';
39
+ readonly tier = 'tier-1' as const;
40
+
41
+ override readonly capabilities: AdapterCapabilities = {
42
+ streaming: false, // Svelte 5 doesn't have streaming SSR yet
43
+ partialHydration: true,
44
+ islands: true,
45
+ resumable: false,
46
+ ssg: true,
47
+ csr: true,
48
+ serverComponents: false,
49
+ };
50
+
51
+ constructor(private options: SvelteAdapterOptions = {}) {
52
+ super();
53
+ }
54
+
55
+ async renderToString(
56
+ component: Component,
57
+ _context?: RenderContext
58
+ ): Promise<RenderResult> {
59
+ const startTime = performance.now();
60
+
61
+ try {
62
+ // Svelte 5 uses the 'svelte/server' module
63
+ const { render } = await import('svelte/server');
64
+
65
+ const SvelteComponent = component.component as new (options: {
66
+ props?: Record<string, unknown>;
67
+ }) => unknown;
68
+
69
+ // Render the component
70
+ const { body, head } = render(SvelteComponent, {
71
+ props: component.props ?? {},
72
+ });
73
+
74
+ return {
75
+ html: body,
76
+ head,
77
+ hydrationData: {
78
+ props: component.props,
79
+ componentId: component.id ?? this.generateId(),
80
+ },
81
+ css: this.options.extractCss ? undefined : undefined, // CSS handled by bundler
82
+ timing: this.createTiming(startTime),
83
+ };
84
+ } catch (error) {
85
+ // Fallback for Svelte 4 compatibility
86
+ const message = error instanceof Error ? error.message : String(error);
87
+
88
+ if (message.includes("Cannot find module 'svelte/server'")) {
89
+ // Try Svelte 4 API
90
+ return this.renderSvelte4(component, startTime);
91
+ }
92
+
93
+ throw error;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Fallback render for Svelte 4
99
+ */
100
+ private async renderSvelte4(
101
+ component: Component,
102
+ startTime: number
103
+ ): Promise<RenderResult> {
104
+ // Svelte 4 component interface
105
+ const SvelteComponent = component.component as {
106
+ render: (props: Record<string, unknown>) => {
107
+ html: string;
108
+ head: string;
109
+ css: { code: string };
110
+ };
111
+ };
112
+
113
+ const result = SvelteComponent.render(component.props ?? {});
114
+
115
+ return {
116
+ html: result.html,
117
+ head: result.head,
118
+ css: result.css?.code,
119
+ hydrationData: {
120
+ props: component.props,
121
+ componentId: component.id ?? this.generateId(),
122
+ },
123
+ timing: this.createTiming(startTime),
124
+ };
125
+ }
126
+
127
+ override getHydrationScript(result: RenderResult): string {
128
+ const data = this.serializeProps(result.hydrationData);
129
+ return `
130
+ <script type="module">
131
+ window.__FLIGHT_DATA__ = ${data};
132
+ window.__FLIGHT_ADAPTER__ = 'svelte';
133
+
134
+ const App = window.__FLIGHT_APP__;
135
+ const container = document.getElementById('app');
136
+
137
+ if (App && container) {
138
+ const { props } = window.__FLIGHT_DATA__;
139
+ // Svelte 5 mount
140
+ import('svelte').then(({ mount, hydrate }) => {
141
+ if (container.innerHTML.trim()) {
142
+ hydrate(App, { target: container, props });
143
+ } else {
144
+ mount(App, { target: container, props });
145
+ }
146
+ });
147
+ }
148
+ </script>
149
+ `.trim();
150
+ }
151
+
152
+ override getClientEntry(): string {
153
+ return `
154
+ // Svelte 5 client entry
155
+ import { mount, hydrate } from 'svelte';
156
+
157
+ export function hydrateApp() {
158
+ const container = document.getElementById('app');
159
+ const App = window.__FLIGHT_APP__;
160
+ const data = window.__FLIGHT_DATA__ ?? {};
161
+
162
+ if (!container || !App) {
163
+ console.warn('[Flight/Svelte] Missing container or App');
164
+ return;
165
+ }
166
+
167
+ // Check if we have SSR content to hydrate
168
+ if (container.innerHTML.trim()) {
169
+ return hydrate(App, {
170
+ target: container,
171
+ props: data.props ?? {},
172
+ });
173
+ } else {
174
+ // Fallback to client-side render
175
+ return mount(App, {
176
+ target: container,
177
+ props: data.props ?? {},
178
+ });
179
+ }
180
+ }
181
+
182
+ export function render(App, container, props = {}) {
183
+ return mount(App, { target: container, props });
184
+ }
185
+
186
+ // Export for Flight
187
+ export { hydrateApp as hydrate };
188
+ `.trim();
189
+ }
190
+ }
191
+
192
+ // ============================================================================
193
+ // Factory Function
194
+ // ============================================================================
195
+
196
+ /**
197
+ * Create a Svelte UI adapter.
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * import { svelte } from '@flightdev/ui/svelte';
202
+ * import { defineUI } from '@flightdev/ui';
203
+ *
204
+ * export default defineUI(svelte());
205
+ * ```
206
+ */
207
+ export function svelte(options?: SvelteAdapterOptions): SvelteAdapter {
208
+ return new SvelteAdapter(options);
209
+ }
210
+
211
+ export default svelte;
@@ -0,0 +1,234 @@
1
+ /**
2
+ * @flightdev/ui - Vue 3 Adapter (Tier 1)
3
+ *
4
+ * Full-featured Vue 3 SSR adapter with streaming and hydration support.
5
+ *
6
+ * @module @flightdev/ui/vue
7
+ * @version 2.0.0
8
+ */
9
+
10
+ import { BaseUIAdapter } from '../../core/adapter.js';
11
+ import type {
12
+ AdapterCapabilities,
13
+ Component,
14
+ RenderContext,
15
+ RenderResult,
16
+ StreamingOptions,
17
+ StreamingRenderResult,
18
+ } from '../../core/types.js';
19
+
20
+ // ============================================================================
21
+ // Types
22
+ // ============================================================================
23
+
24
+ export interface VueAdapterOptions {
25
+ /** Enable streaming SSR with renderToWebStream */
26
+ streaming?: boolean;
27
+
28
+ /** Vue app configuration callback */
29
+ configureApp?: (app: unknown) => void;
30
+
31
+ /** Enable teleports rendering */
32
+ renderTeleports?: boolean;
33
+ }
34
+
35
+ // ============================================================================
36
+ // Vue Adapter
37
+ // ============================================================================
38
+
39
+ export class VueAdapter extends BaseUIAdapter {
40
+ readonly id = 'vue';
41
+ readonly name = 'Vue';
42
+ readonly framework = 'vue';
43
+ readonly frameworkVersion = '3+';
44
+ readonly tier = 'tier-1' as const;
45
+
46
+ override readonly capabilities: AdapterCapabilities = {
47
+ streaming: true,
48
+ partialHydration: true,
49
+ islands: true,
50
+ resumable: false,
51
+ ssg: true,
52
+ csr: true,
53
+ serverComponents: false,
54
+ };
55
+
56
+ constructor(private options: VueAdapterOptions = {}) {
57
+ super();
58
+ }
59
+
60
+ async renderToString(
61
+ component: Component,
62
+ _context?: RenderContext
63
+ ): Promise<RenderResult> {
64
+ const startTime = performance.now();
65
+
66
+ const { createSSRApp } = await import('vue');
67
+ const { renderToString } = await import('vue/server-renderer');
68
+
69
+ // Create Vue SSR app
70
+ const app = createSSRApp(
71
+ component.component as import('vue').Component,
72
+ component.props ?? {}
73
+ );
74
+
75
+ // Apply custom configuration
76
+ if (this.options.configureApp) {
77
+ this.options.configureApp(app);
78
+ }
79
+
80
+ const html = await renderToString(app);
81
+
82
+ return {
83
+ html,
84
+ hydrationData: {
85
+ props: component.props,
86
+ componentId: component.id ?? this.generateId(),
87
+ },
88
+ timing: this.createTiming(startTime),
89
+ };
90
+ }
91
+
92
+ renderToStream(
93
+ component: Component,
94
+ _context?: RenderContext,
95
+ options?: StreamingOptions
96
+ ): StreamingRenderResult {
97
+ let aborted = false;
98
+ let resolvePromise: () => void;
99
+ let rejectPromise: (error: Error) => void;
100
+
101
+ const done = new Promise<void>((resolve, reject) => {
102
+ resolvePromise = resolve;
103
+ rejectPromise = reject;
104
+ });
105
+
106
+ const stream = new ReadableStream<Uint8Array>({
107
+ async start(controller) {
108
+ try {
109
+ const { createSSRApp } = await import('vue');
110
+ const { renderToWebStream } = await import('vue/server-renderer');
111
+
112
+ const app = createSSRApp(
113
+ component.component as import('vue').Component,
114
+ component.props ?? {}
115
+ );
116
+
117
+ const webStream = renderToWebStream(app);
118
+ const reader = webStream.getReader();
119
+
120
+ options?.onShellReady?.();
121
+
122
+ while (true) {
123
+ const { done: readerDone, value } = await reader.read();
124
+
125
+ if (aborted) {
126
+ reader.cancel();
127
+ break;
128
+ }
129
+
130
+ if (readerDone) {
131
+ controller.close();
132
+ resolvePromise();
133
+ options?.onAllReady?.();
134
+ break;
135
+ }
136
+
137
+ controller.enqueue(value);
138
+ }
139
+ } catch (error) {
140
+ const err = error instanceof Error ? error : new Error(String(error));
141
+ options?.onError?.(err);
142
+ controller.error(err);
143
+ rejectPromise(err);
144
+ }
145
+ },
146
+ });
147
+
148
+ return {
149
+ stream,
150
+ done,
151
+ abort() {
152
+ aborted = true;
153
+ resolvePromise();
154
+ },
155
+ };
156
+ }
157
+
158
+ override getHydrationScript(result: RenderResult): string {
159
+ const data = this.serializeProps(result.hydrationData);
160
+ return `
161
+ <script type="module">
162
+ window.__FLIGHT_DATA__ = ${data};
163
+ window.__FLIGHT_ADAPTER__ = 'vue';
164
+
165
+ import { createApp } from 'vue';
166
+
167
+ const container = document.getElementById('app');
168
+ const App = window.__FLIGHT_APP__;
169
+
170
+ if (container && App) {
171
+ const { props } = window.__FLIGHT_DATA__;
172
+ const app = createApp(App, props);
173
+ app.mount(container);
174
+ }
175
+ </script>
176
+ `.trim();
177
+ }
178
+
179
+ override getClientEntry(): string {
180
+ return `
181
+ import { createApp, createSSRApp } from 'vue';
182
+
183
+ export function hydrate() {
184
+ const container = document.getElementById('app');
185
+ const App = window.__FLIGHT_APP__;
186
+ const data = window.__FLIGHT_DATA__ ?? {};
187
+
188
+ if (!container || !App) {
189
+ console.warn('[Flight/Vue] Missing container or App');
190
+ return;
191
+ }
192
+
193
+ // Check if we have SSR content to hydrate
194
+ if (container.innerHTML.trim()) {
195
+ const app = createSSRApp(App, data.props);
196
+ app.mount(container);
197
+ return app;
198
+ } else {
199
+ // Fallback to client-side render
200
+ const app = createApp(App, data.props);
201
+ app.mount(container);
202
+ return app;
203
+ }
204
+ }
205
+
206
+ export function render(App, container, props = {}) {
207
+ const app = createApp(App, props);
208
+ app.mount(container);
209
+ return app;
210
+ }
211
+ `.trim();
212
+ }
213
+ }
214
+
215
+ // ============================================================================
216
+ // Factory Function
217
+ // ============================================================================
218
+
219
+ /**
220
+ * Create a Vue 3 UI adapter.
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * import { vue } from '@flightdev/ui/vue';
225
+ * import { defineUI } from '@flightdev/ui';
226
+ *
227
+ * export default defineUI(vue({ streaming: true }));
228
+ * ```
229
+ */
230
+ export function vue(options?: VueAdapterOptions): VueAdapter {
231
+ return new VueAdapter(options);
232
+ }
233
+
234
+ export default vue;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @flightdev/ui - Tier 2 Adapters Index
3
+ *
4
+ * Re-exports all Tier 2 (Standard Support) adapters.
5
+ */
6
+
7
+ export { marko, MarkoAdapter, type MarkoAdapterOptions, type MarkoTemplate } from './marko.js';
8
+ export { stencil, StencilAdapter, type StencilAdapterOptions } from './stencil.js';
9
+ export { preact, PreactAdapter, type PreactAdapterOptions } from './preact.js';
10
+ export { lit, LitAdapter, type LitAdapterOptions } from './lit.js';
11
+ export { mithril, MithrilAdapter, type MithrilAdapterOptions } from './mithril.js';
12
+ export { inferno, InfernoAdapter, type InfernoAdapterOptions } from './inferno.js';
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @flightdev/ui - Inferno Adapter (Tier 2)
3
+ *
4
+ * Inferno adapter - blazingly fast React-like library.
5
+ *
6
+ * @module @flightdev/ui/inferno
7
+ * @version 2.0.0
8
+ */
9
+
10
+ import { BaseUIAdapter } from '../../core/adapter.js';
11
+ import type {
12
+ AdapterCapabilities,
13
+ Component,
14
+ RenderContext,
15
+ RenderResult,
16
+ } from '../../core/types.js';
17
+
18
+ // ============================================================================
19
+ // Types
20
+ // ============================================================================
21
+
22
+ export interface InfernoAdapterOptions {
23
+ /** Enable JSX compatibility mode */
24
+ jsxCompat?: boolean;
25
+ }
26
+
27
+ // ============================================================================
28
+ // Inferno Adapter
29
+ // ============================================================================
30
+
31
+ export class InfernoAdapter extends BaseUIAdapter {
32
+ readonly id = 'inferno';
33
+ readonly name = 'Inferno';
34
+ readonly framework = 'inferno';
35
+ readonly frameworkVersion = '8+';
36
+ readonly tier = 'tier-2' as const;
37
+
38
+ override readonly capabilities: AdapterCapabilities = {
39
+ streaming: false,
40
+ partialHydration: false,
41
+ islands: false,
42
+ resumable: false,
43
+ ssg: true,
44
+ csr: true,
45
+ serverComponents: false,
46
+ };
47
+
48
+ constructor(private options: InfernoAdapterOptions = {}) {
49
+ super();
50
+ }
51
+
52
+ async renderToString(
53
+ component: Component,
54
+ _context?: RenderContext
55
+ ): Promise<RenderResult> {
56
+ const startTime = performance.now();
57
+
58
+ try {
59
+ const { renderToString } = await import('inferno-server');
60
+ const { createElement } = await import('inferno-create-element');
61
+
62
+ const InfernoComponent = component.component as inferno.Component;
63
+ const element = createElement(InfernoComponent, component.props ?? {});
64
+
65
+ const html = renderToString(element);
66
+
67
+ return {
68
+ html,
69
+ hydrationData: {
70
+ props: component.props,
71
+ componentId: component.id ?? this.generateId(),
72
+ },
73
+ timing: this.createTiming(startTime),
74
+ };
75
+ } catch (error) {
76
+ const message = error instanceof Error ? error.message : String(error);
77
+
78
+ if (message.includes("Cannot find module 'inferno-server'")) {
79
+ throw new Error(
80
+ '[Flight/Inferno] Inferno SSR package not found.\n' +
81
+ 'Install required packages:\n' +
82
+ ' npm install inferno inferno-server inferno-create-element'
83
+ );
84
+ }
85
+
86
+ throw error;
87
+ }
88
+ }
89
+
90
+ override getHydrationScript(result: RenderResult): string {
91
+ const data = this.serializeProps(result.hydrationData);
92
+ return `
93
+ <script type="module">
94
+ window.__FLIGHT_DATA__ = ${data};
95
+ window.__FLIGHT_ADAPTER__ = 'inferno';
96
+
97
+ import { hydrate } from 'inferno-hydrate';
98
+ import { createElement } from 'inferno-create-element';
99
+
100
+ const App = window.__FLIGHT_APP__;
101
+ const container = document.getElementById('app');
102
+
103
+ if (App && container) {
104
+ hydrate(
105
+ createElement(App, window.__FLIGHT_DATA__.props),
106
+ container
107
+ );
108
+ }
109
+ </script>
110
+ `.trim();
111
+ }
112
+
113
+ override getClientEntry(): string {
114
+ return `
115
+ import { hydrate } from 'inferno-hydrate';
116
+ import { render } from 'inferno';
117
+ import { createElement } from 'inferno-create-element';
118
+
119
+ export function hydrateApp() {
120
+ const container = document.getElementById('app');
121
+ const App = window.__FLIGHT_APP__;
122
+ const data = window.__FLIGHT_DATA__ ?? {};
123
+
124
+ if (!container || !App) {
125
+ console.warn('[Flight/Inferno] Missing container or App');
126
+ return;
127
+ }
128
+
129
+ if (container.innerHTML.trim()) {
130
+ hydrate(createElement(App, data.props), container);
131
+ } else {
132
+ render(createElement(App, data.props), container);
133
+ }
134
+ }
135
+
136
+ export { hydrateApp as hydrate };
137
+ `.trim();
138
+ }
139
+ }
140
+
141
+ // ============================================================================
142
+ // Factory Function
143
+ // ============================================================================
144
+
145
+ export function inferno(options?: InfernoAdapterOptions): InfernoAdapter {
146
+ return new InfernoAdapter(options);
147
+ }
148
+
149
+ export default inferno;