@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
package/package.json ADDED
@@ -0,0 +1,229 @@
1
+ {
2
+ "name": "@flightdev/ui",
3
+ "version": "2.0.0",
4
+ "description": "Flight Universal UI Adapters - SSR/hydration for 18+ frameworks: React, Vue, Angular, Svelte, Solid, Qwik, Marko, Lit, HTMX, Alpine.js, Stencil, and more",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ },
14
+ "./core": {
15
+ "types": "./dist/core/index.d.ts",
16
+ "import": "./dist/core/index.js"
17
+ },
18
+ "./react": {
19
+ "types": "./dist/adapters/tier-1/react.d.ts",
20
+ "import": "./dist/adapters/tier-1/react.js"
21
+ },
22
+ "./vue": {
23
+ "types": "./dist/adapters/tier-1/vue.d.ts",
24
+ "import": "./dist/adapters/tier-1/vue.js"
25
+ },
26
+ "./angular": {
27
+ "types": "./dist/adapters/tier-1/angular.d.ts",
28
+ "import": "./dist/adapters/tier-1/angular.js"
29
+ },
30
+ "./svelte": {
31
+ "types": "./dist/adapters/tier-1/svelte.d.ts",
32
+ "import": "./dist/adapters/tier-1/svelte.js"
33
+ },
34
+ "./solid": {
35
+ "types": "./dist/adapters/tier-1/solid.d.ts",
36
+ "import": "./dist/adapters/tier-1/solid.js"
37
+ },
38
+ "./qwik": {
39
+ "types": "./dist/adapters/tier-1/qwik.d.ts",
40
+ "import": "./dist/adapters/tier-1/qwik.js"
41
+ },
42
+ "./preact": {
43
+ "types": "./dist/adapters/tier-2/preact.d.ts",
44
+ "import": "./dist/adapters/tier-2/preact.js"
45
+ },
46
+ "./lit": {
47
+ "types": "./dist/adapters/tier-2/lit.d.ts",
48
+ "import": "./dist/adapters/tier-2/lit.js"
49
+ },
50
+ "./marko": {
51
+ "types": "./dist/adapters/tier-2/marko.d.ts",
52
+ "import": "./dist/adapters/tier-2/marko.js"
53
+ },
54
+ "./stencil": {
55
+ "types": "./dist/adapters/tier-2/stencil.d.ts",
56
+ "import": "./dist/adapters/tier-2/stencil.js"
57
+ },
58
+ "./mithril": {
59
+ "types": "./dist/adapters/tier-2/mithril.d.ts",
60
+ "import": "./dist/adapters/tier-2/mithril.js"
61
+ },
62
+ "./inferno": {
63
+ "types": "./dist/adapters/tier-2/inferno.d.ts",
64
+ "import": "./dist/adapters/tier-2/inferno.js"
65
+ },
66
+ "./htmx": {
67
+ "types": "./dist/adapters/tier-3/htmx.d.ts",
68
+ "import": "./dist/adapters/tier-3/htmx.js"
69
+ },
70
+ "./alpine": {
71
+ "types": "./dist/adapters/tier-3/alpine.d.ts",
72
+ "import": "./dist/adapters/tier-3/alpine.js"
73
+ },
74
+ "./hotwire": {
75
+ "types": "./dist/adapters/tier-3/hotwire.d.ts",
76
+ "import": "./dist/adapters/tier-3/hotwire.js"
77
+ },
78
+ "./stimulus": {
79
+ "types": "./dist/adapters/tier-3/stimulus.d.ts",
80
+ "import": "./dist/adapters/tier-3/stimulus.js"
81
+ },
82
+ "./petite-vue": {
83
+ "types": "./dist/adapters/tier-3/petite-vue.d.ts",
84
+ "import": "./dist/adapters/tier-3/petite-vue.js"
85
+ },
86
+ "./vanilla": {
87
+ "types": "./dist/adapters/tier-3/vanilla.d.ts",
88
+ "import": "./dist/adapters/tier-3/vanilla.js"
89
+ },
90
+ "./tier-1": {
91
+ "types": "./dist/adapters/tier-1/index.d.ts",
92
+ "import": "./dist/adapters/tier-1/index.js"
93
+ },
94
+ "./tier-2": {
95
+ "types": "./dist/adapters/tier-2/index.d.ts",
96
+ "import": "./dist/adapters/tier-2/index.js"
97
+ },
98
+ "./tier-3": {
99
+ "types": "./dist/adapters/tier-3/index.d.ts",
100
+ "import": "./dist/adapters/tier-3/index.js"
101
+ }
102
+ },
103
+ "keywords": [
104
+ "flight",
105
+ "ui",
106
+ "ssr",
107
+ "hydration",
108
+ "streaming",
109
+ "islands",
110
+ "react",
111
+ "vue",
112
+ "angular",
113
+ "svelte",
114
+ "solid",
115
+ "qwik",
116
+ "preact",
117
+ "lit",
118
+ "marko",
119
+ "stencil",
120
+ "htmx",
121
+ "alpine",
122
+ "hotwire",
123
+ "stimulus",
124
+ "web-components",
125
+ "universal",
126
+ "framework-agnostic"
127
+ ],
128
+ "author": "",
129
+ "license": "MIT",
130
+ "devDependencies": {
131
+ "@types/node": "^22.0.0",
132
+ "@vitest/coverage-v8": "^2.0.0",
133
+ "tsup": "^8.0.0",
134
+ "typescript": "^5.7.0",
135
+ "vitest": "^2.0.0"
136
+ },
137
+ "peerDependencies": {
138
+ "react": ">=18.0.0",
139
+ "react-dom": ">=18.0.0",
140
+ "vue": ">=3.0.0",
141
+ "@angular/core": ">=17.0.0",
142
+ "@angular/platform-server": ">=17.0.0",
143
+ "@angular/platform-browser": ">=17.0.0",
144
+ "svelte": ">=4.0.0",
145
+ "solid-js": ">=1.0.0",
146
+ "@builder.io/qwik": ">=1.0.0",
147
+ "preact": ">=10.0.0",
148
+ "lit": ">=3.0.0",
149
+ "@lit-labs/ssr": ">=3.0.0",
150
+ "marko": ">=5.0.0",
151
+ "@stencil/core": ">=4.0.0",
152
+ "mithril": ">=2.0.0",
153
+ "inferno": ">=8.0.0",
154
+ "@hotwired/turbo": ">=8.0.0",
155
+ "@hotwired/stimulus": ">=3.0.0",
156
+ "petite-vue": ">=0.4.0"
157
+ },
158
+ "peerDependenciesMeta": {
159
+ "react": {
160
+ "optional": true
161
+ },
162
+ "react-dom": {
163
+ "optional": true
164
+ },
165
+ "vue": {
166
+ "optional": true
167
+ },
168
+ "@angular/core": {
169
+ "optional": true
170
+ },
171
+ "@angular/platform-server": {
172
+ "optional": true
173
+ },
174
+ "@angular/platform-browser": {
175
+ "optional": true
176
+ },
177
+ "svelte": {
178
+ "optional": true
179
+ },
180
+ "solid-js": {
181
+ "optional": true
182
+ },
183
+ "@builder.io/qwik": {
184
+ "optional": true
185
+ },
186
+ "preact": {
187
+ "optional": true
188
+ },
189
+ "lit": {
190
+ "optional": true
191
+ },
192
+ "@lit-labs/ssr": {
193
+ "optional": true
194
+ },
195
+ "marko": {
196
+ "optional": true
197
+ },
198
+ "@stencil/core": {
199
+ "optional": true
200
+ },
201
+ "mithril": {
202
+ "optional": true
203
+ },
204
+ "inferno": {
205
+ "optional": true
206
+ },
207
+ "@hotwired/turbo": {
208
+ "optional": true
209
+ },
210
+ "@hotwired/stimulus": {
211
+ "optional": true
212
+ },
213
+ "petite-vue": {
214
+ "optional": true
215
+ }
216
+ },
217
+ "engines": {
218
+ "node": ">=20.0.0"
219
+ },
220
+ "scripts": {
221
+ "build": "tsup",
222
+ "dev": "tsup --watch",
223
+ "typecheck": "tsc --noEmit",
224
+ "test": "vitest run",
225
+ "test:watch": "vitest",
226
+ "test:coverage": "vitest run --coverage",
227
+ "lint": "eslint src test"
228
+ }
229
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * @flightdev/ui - Angular Adapter (Tier 1)
3
+ *
4
+ * Full-featured Angular 17+ SSR adapter with hydration and incremental hydration support.
5
+ *
6
+ * @module @flightdev/ui/angular
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
+ /**
23
+ * Angular bootstrap function type
24
+ */
25
+ export type AngularBootstrapFn = (document: string, url: string) => Promise<unknown>;
26
+
27
+ export interface AngularAdapterOptions {
28
+ /** Enable incremental hydration (Angular 17+) */
29
+ incrementalHydration?: boolean;
30
+
31
+ /** Enable event replay during hydration */
32
+ eventReplay?: boolean;
33
+
34
+ /** Document template for SSR */
35
+ documentTemplate?: string;
36
+
37
+ /** Custom providers for SSR */
38
+ providers?: unknown[];
39
+ }
40
+
41
+ // ============================================================================
42
+ // Angular Adapter
43
+ // ============================================================================
44
+
45
+ export class AngularAdapter extends BaseUIAdapter {
46
+ readonly id = 'angular';
47
+ readonly name = 'Angular';
48
+ readonly framework = 'angular';
49
+ readonly frameworkVersion = '17+';
50
+ readonly tier = 'tier-1' as const;
51
+
52
+ override readonly capabilities: AdapterCapabilities = {
53
+ streaming: true,
54
+ partialHydration: true,
55
+ islands: false, // Angular doesn't have traditional islands
56
+ resumable: false,
57
+ ssg: true,
58
+ csr: true,
59
+ serverComponents: false,
60
+ };
61
+
62
+ private documentTemplate: string;
63
+
64
+ constructor(private options: AngularAdapterOptions = {}) {
65
+ super();
66
+ this.documentTemplate = options.documentTemplate ?? this.getDefaultDocumentTemplate();
67
+ }
68
+
69
+ async renderToString(
70
+ component: Component,
71
+ context?: RenderContext
72
+ ): Promise<RenderResult> {
73
+ const startTime = performance.now();
74
+
75
+ try {
76
+ // Dynamic import of Angular platform-server
77
+ const { renderApplication } = await import('@angular/platform-server');
78
+ const { provideClientHydration, withIncrementalHydration, withEventReplay } =
79
+ await import('@angular/platform-browser');
80
+
81
+ // Build hydration providers based on options
82
+ const hydrationFeatures: unknown[] = [];
83
+
84
+ if (this.options.incrementalHydration) {
85
+ hydrationFeatures.push(withIncrementalHydration());
86
+ }
87
+
88
+ if (this.options.eventReplay) {
89
+ hydrationFeatures.push(withEventReplay());
90
+ }
91
+
92
+ // The component should be an Angular bootstrap function
93
+ const bootstrap = component.component as AngularBootstrapFn;
94
+ const url = context?.url ?? '/';
95
+
96
+ // Render the application
97
+ const html = await renderApplication(bootstrap, {
98
+ document: this.documentTemplate,
99
+ url,
100
+ });
101
+
102
+ return {
103
+ html,
104
+ hydrationData: {
105
+ props: component.props,
106
+ url,
107
+ componentId: component.id ?? this.generateId(),
108
+ },
109
+ timing: this.createTiming(startTime),
110
+ };
111
+ } catch (error) {
112
+ // Handle missing Angular dependencies gracefully
113
+ const message = error instanceof Error ? error.message : String(error);
114
+
115
+ if (message.includes("Cannot find module '@angular/platform-server'")) {
116
+ throw new Error(
117
+ '[Flight/Angular] Angular SSR dependencies not found.\n' +
118
+ 'Install required packages:\n' +
119
+ ' npm install @angular/core @angular/platform-server @angular/platform-browser'
120
+ );
121
+ }
122
+
123
+ throw error;
124
+ }
125
+ }
126
+
127
+ override getHydrationScript(result: RenderResult): string {
128
+ const data = this.serializeProps(result.hydrationData);
129
+
130
+ // Angular handles hydration differently - it's built into the render output
131
+ // This script is for passing additional Flight-specific data
132
+ return `
133
+ <script type="module">
134
+ window.__FLIGHT_DATA__ = ${data};
135
+ window.__FLIGHT_ADAPTER__ = 'angular';
136
+ // Angular hydration is automatic when provideClientHydration is configured
137
+ </script>
138
+ `.trim();
139
+ }
140
+
141
+ override getClientEntry(): string {
142
+ return `
143
+ import { bootstrapApplication } from '@angular/platform-browser';
144
+ import { provideClientHydration } from '@angular/platform-browser';
145
+
146
+ export async function hydrate() {
147
+ const App = window.__FLIGHT_APP__;
148
+ const data = window.__FLIGHT_DATA__ ?? {};
149
+
150
+ if (!App) {
151
+ console.warn('[Flight/Angular] No App component found');
152
+ return;
153
+ }
154
+
155
+ try {
156
+ const appRef = await bootstrapApplication(App, {
157
+ providers: [
158
+ provideClientHydration(),
159
+ // Additional providers can be added here
160
+ ],
161
+ });
162
+
163
+ console.log('[Flight/Angular] Application bootstrapped');
164
+ return appRef;
165
+ } catch (error) {
166
+ console.error('[Flight/Angular] Bootstrap failed:', error);
167
+ throw error;
168
+ }
169
+ }
170
+
171
+ export async function render(AppComponent, providers = []) {
172
+ return bootstrapApplication(AppComponent, {
173
+ providers: [
174
+ ...providers,
175
+ ],
176
+ });
177
+ }
178
+ `.trim();
179
+ }
180
+
181
+ /**
182
+ * Get the default document template for SSR
183
+ */
184
+ private getDefaultDocumentTemplate(): string {
185
+ return `
186
+ <!DOCTYPE html>
187
+ <html lang="en">
188
+ <head>
189
+ <meta charset="UTF-8">
190
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
191
+ <title>Flight App</title>
192
+ </head>
193
+ <body>
194
+ <app-root></app-root>
195
+ </body>
196
+ </html>
197
+ `.trim();
198
+ }
199
+ }
200
+
201
+ // ============================================================================
202
+ // Factory Function
203
+ // ============================================================================
204
+
205
+ /**
206
+ * Create an Angular UI adapter.
207
+ *
208
+ * @example
209
+ * ```typescript
210
+ * import { angular } from '@flightdev/ui/angular';
211
+ * import { defineUI } from '@flightdev/ui';
212
+ *
213
+ * export default defineUI(angular({
214
+ * incrementalHydration: true,
215
+ * eventReplay: true,
216
+ * }));
217
+ * ```
218
+ */
219
+ export function angular(options?: AngularAdapterOptions): AngularAdapter {
220
+ return new AngularAdapter(options);
221
+ }
222
+
223
+ export default angular;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @flightdev/ui - Tier 1 Adapters Index
3
+ *
4
+ * Re-exports all Tier 1 (Full Support) adapters.
5
+ */
6
+
7
+ export { react, ReactAdapter, type ReactAdapterOptions } from './react.js';
8
+ export { vue, VueAdapter, type VueAdapterOptions } from './vue.js';
9
+ export { angular, AngularAdapter, type AngularAdapterOptions, type AngularBootstrapFn } from './angular.js';
10
+ export { svelte, SvelteAdapter, type SvelteAdapterOptions } from './svelte.js';
11
+ export { solid, SolidAdapter, type SolidAdapterOptions } from './solid.js';
12
+ export { qwik, QwikAdapter, type QwikAdapterOptions } from './qwik.js';
@@ -0,0 +1,177 @@
1
+ /**
2
+ * @flightdev/ui - Qwik Adapter (Tier 1)
3
+ *
4
+ * Qwik adapter with resumable hydration - zero JavaScript until interaction.
5
+ *
6
+ * @module @flightdev/ui/qwik
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 QwikAdapterOptions {
23
+ /** Enable prefetching */
24
+ prefetch?: boolean;
25
+
26
+ /** Prefetch strategy */
27
+ prefetchStrategy?: 'hover' | 'viewport' | 'idle';
28
+
29
+ /** Container tag name */
30
+ containerTagName?: string;
31
+ }
32
+
33
+ // ============================================================================
34
+ // Qwik Adapter
35
+ // ============================================================================
36
+
37
+ export class QwikAdapter extends BaseUIAdapter {
38
+ readonly id = 'qwik';
39
+ readonly name = 'Qwik';
40
+ readonly framework = 'qwik';
41
+ readonly frameworkVersion = '1.0+';
42
+ readonly tier = 'tier-1' as const;
43
+
44
+ override readonly capabilities: AdapterCapabilities = {
45
+ streaming: true,
46
+ partialHydration: true,
47
+ islands: true,
48
+ resumable: true, // Qwik's killer feature!
49
+ ssg: true,
50
+ csr: true,
51
+ serverComponents: false,
52
+ };
53
+
54
+ constructor(private options: QwikAdapterOptions = {}) {
55
+ super();
56
+ }
57
+
58
+ async renderToString(
59
+ component: Component,
60
+ _context?: RenderContext
61
+ ): Promise<RenderResult> {
62
+ const startTime = performance.now();
63
+
64
+ try {
65
+ const { renderToString } = await import('@builder.io/qwik/server');
66
+
67
+ const QwikComponent = component.component as () => unknown;
68
+ const containerTagName = this.options.containerTagName ?? 'div';
69
+
70
+ const result = await renderToString(QwikComponent, {
71
+ containerTagName,
72
+ // Qwik serializes state automatically
73
+ });
74
+
75
+ return {
76
+ html: result.html,
77
+ hydrationData: {
78
+ // Qwik doesn't need explicit hydration data
79
+ // State is serialized in the HTML
80
+ componentId: component.id ?? this.generateId(),
81
+ },
82
+ timing: this.createTiming(startTime),
83
+ };
84
+ } catch (error) {
85
+ const message = error instanceof Error ? error.message : String(error);
86
+
87
+ if (message.includes("Cannot find module '@builder.io/qwik/server'")) {
88
+ throw new Error(
89
+ '[Flight/Qwik] Qwik dependencies not found.\n' +
90
+ 'Install required packages:\n' +
91
+ ' npm install @builder.io/qwik'
92
+ );
93
+ }
94
+
95
+ throw error;
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Serialize state for resumability (Qwik's specialty)
101
+ */
102
+ override serializeState(state: unknown): string {
103
+ // Qwik handles serialization internally via qwik/serialization
104
+ return JSON.stringify(state);
105
+ }
106
+
107
+ /**
108
+ * Resume from serialized state
109
+ */
110
+ override resumeFromState(_serialized: string): unknown {
111
+ // Qwik automatically resumes from HTML-embedded state
112
+ // This is called by the client-side Qwik runtime
113
+ return null;
114
+ }
115
+
116
+ override getHydrationScript(_result: RenderResult): string {
117
+ // Qwik doesn't need traditional hydration scripts
118
+ // It uses resumability - the state is in the HTML
119
+ const prefetchStrategy = this.options.prefetchStrategy ?? 'idle';
120
+
121
+ return `
122
+ <script type="module">
123
+ window.__FLIGHT_ADAPTER__ = 'qwik';
124
+ // Qwik handles resumability automatically
125
+ // No hydration script needed - Qwik resumes from HTML state
126
+ // Prefetch strategy: ${prefetchStrategy}
127
+ </script>
128
+ `.trim();
129
+ }
130
+
131
+ override getClientEntry(): string {
132
+ return `
133
+ // Qwik Client Entry
134
+ // Qwik uses resumability - no traditional hydration needed
135
+
136
+ export function hydrate() {
137
+ // Qwik automatically resumes from HTML-serialized state
138
+ // This function is a no-op for Qwik
139
+ console.log('[Flight/Qwik] Resumability enabled - no hydration needed');
140
+ }
141
+
142
+ export function prefetch() {
143
+ // Trigger Qwik prefetching
144
+ if ('requestIdleCallback' in window) {
145
+ requestIdleCallback(() => {
146
+ const qwikLoader = document.querySelector('[q\\\\:container]');
147
+ if (qwikLoader) {
148
+ // Qwik prefetches automatically based on container attributes
149
+ }
150
+ });
151
+ }
152
+ }
153
+ `.trim();
154
+ }
155
+ }
156
+
157
+ // ============================================================================
158
+ // Factory Function
159
+ // ============================================================================
160
+
161
+ /**
162
+ * Create a Qwik UI adapter.
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * import { qwik } from '@flightdev/ui/qwik';
167
+ * import { defineUI } from '@flightdev/ui';
168
+ *
169
+ * // Qwik's resumability means zero JS until interaction!
170
+ * export default defineUI(qwik({ prefetchStrategy: 'idle' }));
171
+ * ```
172
+ */
173
+ export function qwik(options?: QwikAdapterOptions): QwikAdapter {
174
+ return new QwikAdapter(options);
175
+ }
176
+
177
+ export default qwik;