@flightdev/core 0.6.7
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/LICENSE +21 -0
- package/README.md +541 -0
- package/dist/actions/index.d.ts +743 -0
- package/dist/actions/index.js +3 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/adapters/index.d.ts +502 -0
- package/dist/adapters/index.js +3 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/cache/index.d.ts +191 -0
- package/dist/cache/index.js +3 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/chunk-62HISNA3.js +354 -0
- package/dist/chunk-62HISNA3.js.map +1 -0
- package/dist/chunk-63LWTEDQ.js +341 -0
- package/dist/chunk-63LWTEDQ.js.map +1 -0
- package/dist/chunk-63SCEXD7.js +3 -0
- package/dist/chunk-63SCEXD7.js.map +1 -0
- package/dist/chunk-72MYOTUB.js +667 -0
- package/dist/chunk-72MYOTUB.js.map +1 -0
- package/dist/chunk-7CNW24MQ.js +257 -0
- package/dist/chunk-7CNW24MQ.js.map +1 -0
- package/dist/chunk-7WIEAUJT.js +300 -0
- package/dist/chunk-7WIEAUJT.js.map +1 -0
- package/dist/chunk-7ZZF4ULK.js +259 -0
- package/dist/chunk-7ZZF4ULK.js.map +1 -0
- package/dist/chunk-AE3JTS73.js +222 -0
- package/dist/chunk-AE3JTS73.js.map +1 -0
- package/dist/chunk-AP5NLUSB.js +258 -0
- package/dist/chunk-AP5NLUSB.js.map +1 -0
- package/dist/chunk-C37YQQI7.js +221 -0
- package/dist/chunk-C37YQQI7.js.map +1 -0
- package/dist/chunk-DCLVXFVH.js +225 -0
- package/dist/chunk-DCLVXFVH.js.map +1 -0
- package/dist/chunk-DZMWWDFD.js +223 -0
- package/dist/chunk-DZMWWDFD.js.map +1 -0
- package/dist/chunk-GCQZ4FHI.js +245 -0
- package/dist/chunk-GCQZ4FHI.js.map +1 -0
- package/dist/chunk-IPP44XY6.js +47 -0
- package/dist/chunk-IPP44XY6.js.map +1 -0
- package/dist/chunk-IW7FTQQX.js +267 -0
- package/dist/chunk-IW7FTQQX.js.map +1 -0
- package/dist/chunk-JX4YSCBH.js +428 -0
- package/dist/chunk-JX4YSCBH.js.map +1 -0
- package/dist/chunk-KX6UYWWR.js +229 -0
- package/dist/chunk-KX6UYWWR.js.map +1 -0
- package/dist/chunk-LWVETFJV.js +46 -0
- package/dist/chunk-LWVETFJV.js.map +1 -0
- package/dist/chunk-MCL2MCA2.js +285 -0
- package/dist/chunk-MCL2MCA2.js.map +1 -0
- package/dist/chunk-MZXCF35B.js +205 -0
- package/dist/chunk-MZXCF35B.js.map +1 -0
- package/dist/chunk-NCGPUFWV.js +96 -0
- package/dist/chunk-NCGPUFWV.js.map +1 -0
- package/dist/chunk-OEJMIE2Q.js +351 -0
- package/dist/chunk-OEJMIE2Q.js.map +1 -0
- package/dist/chunk-OYF2OAKS.js +394 -0
- package/dist/chunk-OYF2OAKS.js.map +1 -0
- package/dist/chunk-P6S43FYZ.js +316 -0
- package/dist/chunk-P6S43FYZ.js.map +1 -0
- package/dist/chunk-PL37KFRJ.js +3 -0
- package/dist/chunk-PL37KFRJ.js.map +1 -0
- package/dist/chunk-Q7BS5QC5.js +197 -0
- package/dist/chunk-Q7BS5QC5.js.map +1 -0
- package/dist/chunk-SDYPG3JD.js +288 -0
- package/dist/chunk-SDYPG3JD.js.map +1 -0
- package/dist/chunk-SUG56SZO.js +256 -0
- package/dist/chunk-SUG56SZO.js.map +1 -0
- package/dist/chunk-UVH5XJRP.js +164 -0
- package/dist/chunk-UVH5XJRP.js.map +1 -0
- package/dist/chunk-WZIJKCL3.js +282 -0
- package/dist/chunk-WZIJKCL3.js.map +1 -0
- package/dist/chunk-Y22AMGTM.js +3 -0
- package/dist/chunk-Y22AMGTM.js.map +1 -0
- package/dist/chunk-Z7G23XWU.js +200 -0
- package/dist/chunk-Z7G23XWU.js.map +1 -0
- package/dist/chunk-ZJU5M4IB.js +125 -0
- package/dist/chunk-ZJU5M4IB.js.map +1 -0
- package/dist/chunk-ZVC3ZWLM.js +52 -0
- package/dist/chunk-ZVC3ZWLM.js.map +1 -0
- package/dist/chunk-ZZZML7Y3.js +310 -0
- package/dist/chunk-ZZZML7Y3.js.map +1 -0
- package/dist/client.d.ts +25 -0
- package/dist/client.js +16 -0
- package/dist/client.js.map +1 -0
- package/dist/config/index.d.ts +170 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/errors/index.d.ts +267 -0
- package/dist/errors/index.js +4 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/file-router/index.d.ts +184 -0
- package/dist/file-router/index.js +3 -0
- package/dist/file-router/index.js.map +1 -0
- package/dist/file-router/streaming-hints.d.ts +129 -0
- package/dist/file-router/streaming-hints.js +3 -0
- package/dist/file-router/streaming-hints.js.map +1 -0
- package/dist/handlers/index.d.ts +59 -0
- package/dist/handlers/index.js +3 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/index.d.ts +588 -0
- package/dist/index.js +886 -0
- package/dist/index.js.map +1 -0
- package/dist/islands/index.d.ts +234 -0
- package/dist/islands/index.js +3 -0
- package/dist/islands/index.js.map +1 -0
- package/dist/middleware/index.d.ts +305 -0
- package/dist/middleware/index.js +3 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/react/index.d.ts +73 -0
- package/dist/react/index.js +52 -0
- package/dist/react/index.js.map +1 -0
- package/dist/render/index.d.ts +131 -0
- package/dist/render/index.js +3 -0
- package/dist/render/index.js.map +1 -0
- package/dist/router/index.d.ts +65 -0
- package/dist/router/index.js +3 -0
- package/dist/router/index.js.map +1 -0
- package/dist/rsc/adapters/index.d.ts +8 -0
- package/dist/rsc/adapters/index.js +7 -0
- package/dist/rsc/adapters/index.js.map +1 -0
- package/dist/rsc/adapters/preact.d.ts +97 -0
- package/dist/rsc/adapters/preact.js +3 -0
- package/dist/rsc/adapters/preact.js.map +1 -0
- package/dist/rsc/adapters/react.d.ts +82 -0
- package/dist/rsc/adapters/react.js +3 -0
- package/dist/rsc/adapters/react.js.map +1 -0
- package/dist/rsc/adapters/solid.d.ts +84 -0
- package/dist/rsc/adapters/solid.js +3 -0
- package/dist/rsc/adapters/solid.js.map +1 -0
- package/dist/rsc/adapters/vue.d.ts +80 -0
- package/dist/rsc/adapters/vue.js +3 -0
- package/dist/rsc/adapters/vue.js.map +1 -0
- package/dist/rsc/boundaries.d.ts +182 -0
- package/dist/rsc/boundaries.js +3 -0
- package/dist/rsc/boundaries.js.map +1 -0
- package/dist/rsc/context.d.ts +201 -0
- package/dist/rsc/context.js +3 -0
- package/dist/rsc/context.js.map +1 -0
- package/dist/rsc/index.d.ts +232 -0
- package/dist/rsc/index.js +15 -0
- package/dist/rsc/index.js.map +1 -0
- package/dist/rsc/legacy.d.ts +155 -0
- package/dist/rsc/legacy.js +3 -0
- package/dist/rsc/legacy.js.map +1 -0
- package/dist/rsc/payload.d.ts +262 -0
- package/dist/rsc/payload.js +3 -0
- package/dist/rsc/payload.js.map +1 -0
- package/dist/rsc/plugins/esbuild.d.ts +124 -0
- package/dist/rsc/plugins/esbuild.js +4 -0
- package/dist/rsc/plugins/esbuild.js.map +1 -0
- package/dist/rsc/plugins/index.d.ts +4 -0
- package/dist/rsc/plugins/index.js +6 -0
- package/dist/rsc/plugins/index.js.map +1 -0
- package/dist/rsc/plugins/rollup.d.ts +103 -0
- package/dist/rsc/plugins/rollup.js +4 -0
- package/dist/rsc/plugins/rollup.js.map +1 -0
- package/dist/rsc/renderer.d.ts +162 -0
- package/dist/rsc/renderer.js +5 -0
- package/dist/rsc/renderer.js.map +1 -0
- package/dist/rsc/stream.d.ts +129 -0
- package/dist/rsc/stream.js +3 -0
- package/dist/rsc/stream.js.map +1 -0
- package/dist/rsc/vite-plugin.d.ts +78 -0
- package/dist/rsc/vite-plugin.js +4 -0
- package/dist/rsc/vite-plugin.js.map +1 -0
- package/dist/server/index.d.ts +135 -0
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -0
- package/dist/streaming/adapters/index.d.ts +223 -0
- package/dist/streaming/adapters/index.js +3 -0
- package/dist/streaming/adapters/index.js.map +1 -0
- package/dist/streaming/conditional.d.ts +130 -0
- package/dist/streaming/conditional.js +3 -0
- package/dist/streaming/conditional.js.map +1 -0
- package/dist/streaming/index.d.ts +177 -0
- package/dist/streaming/index.js +3 -0
- package/dist/streaming/index.js.map +1 -0
- package/dist/streaming/observability.d.ts +201 -0
- package/dist/streaming/observability.js +4 -0
- package/dist/streaming/observability.js.map +1 -0
- package/dist/streaming/priority.d.ts +103 -0
- package/dist/streaming/priority.js +3 -0
- package/dist/streaming/priority.js.map +1 -0
- package/dist/utils/index.d.ts +42 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +228 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
// src/streaming/adapters/index.ts
|
|
2
|
+
function createReactStreamAdapter(options) {
|
|
3
|
+
if (!options.renderToReadableStream) {
|
|
4
|
+
throw new Error(
|
|
5
|
+
"[Flight] createReactStreamAdapter requires renderToReadableStream. Import it from react-dom/server and pass it in options."
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
return {
|
|
9
|
+
name: "react",
|
|
10
|
+
framework: "react@18+",
|
|
11
|
+
runtime: "edge",
|
|
12
|
+
async stream(component, streamOptions = {}) {
|
|
13
|
+
const mergedOptions = { ...options, ...streamOptions };
|
|
14
|
+
let resolveShell;
|
|
15
|
+
let resolveAll;
|
|
16
|
+
const shellReady = new Promise((r) => {
|
|
17
|
+
resolveShell = r;
|
|
18
|
+
});
|
|
19
|
+
const allReady = new Promise((r) => {
|
|
20
|
+
resolveAll = r;
|
|
21
|
+
});
|
|
22
|
+
const stream = await options.renderToReadableStream(component, {
|
|
23
|
+
bootstrapScripts: mergedOptions.bootstrapScripts,
|
|
24
|
+
bootstrapModules: mergedOptions.bootstrapModules,
|
|
25
|
+
identifierPrefix: mergedOptions.identifierPrefix,
|
|
26
|
+
signal: mergedOptions.signal,
|
|
27
|
+
onError: (error) => {
|
|
28
|
+
mergedOptions.onError?.(error);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
resolveShell();
|
|
32
|
+
mergedOptions.onShellReady?.();
|
|
33
|
+
stream.allReady.then(() => {
|
|
34
|
+
resolveAll();
|
|
35
|
+
mergedOptions.onAllReady?.();
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
stream,
|
|
39
|
+
abort: () => {
|
|
40
|
+
},
|
|
41
|
+
shellReady,
|
|
42
|
+
allReady
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
async renderToString(component) {
|
|
46
|
+
if (!options.renderToString) {
|
|
47
|
+
throw new Error("[Flight] renderToString not provided to adapter");
|
|
48
|
+
}
|
|
49
|
+
return options.renderToString(component);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function createVueStreamAdapter(options) {
|
|
54
|
+
if (!options.renderToWebStream) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"[Flight] createVueStreamAdapter requires renderToWebStream. Import it from vue/server-renderer and pass it in options."
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
name: "vue",
|
|
61
|
+
framework: "vue@3+",
|
|
62
|
+
runtime: "universal",
|
|
63
|
+
async stream(app, streamOptions = {}) {
|
|
64
|
+
const mergedOptions = { ...options, ...streamOptions };
|
|
65
|
+
let resolveShell;
|
|
66
|
+
let resolveAll;
|
|
67
|
+
const shellReady = new Promise((r) => {
|
|
68
|
+
resolveShell = r;
|
|
69
|
+
});
|
|
70
|
+
const allReady = new Promise((r) => {
|
|
71
|
+
resolveAll = r;
|
|
72
|
+
});
|
|
73
|
+
try {
|
|
74
|
+
const stream = options.renderToWebStream(app, mergedOptions.context);
|
|
75
|
+
resolveShell();
|
|
76
|
+
mergedOptions.onShellReady?.();
|
|
77
|
+
const reader = stream.getReader();
|
|
78
|
+
const wrappedStream = new ReadableStream({
|
|
79
|
+
async pull(controller) {
|
|
80
|
+
const { done, value } = await reader.read();
|
|
81
|
+
if (done) {
|
|
82
|
+
resolveAll();
|
|
83
|
+
mergedOptions.onAllReady?.();
|
|
84
|
+
controller.close();
|
|
85
|
+
} else {
|
|
86
|
+
controller.enqueue(value);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
stream: wrappedStream,
|
|
92
|
+
abort: () => reader.cancel(),
|
|
93
|
+
shellReady,
|
|
94
|
+
allReady
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
mergedOptions.onError?.(error);
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
async renderToString(app) {
|
|
102
|
+
if (!options.renderToString) {
|
|
103
|
+
throw new Error("[Flight] renderToString not provided to adapter");
|
|
104
|
+
}
|
|
105
|
+
return options.renderToString(app);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function createSolidStreamAdapter(options) {
|
|
110
|
+
if (!options.renderToStream) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
"[Flight] createSolidStreamAdapter requires renderToStream. Import it from solid-js/web and pass it in options."
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
name: "solid",
|
|
117
|
+
framework: "solid-js@1+",
|
|
118
|
+
runtime: "universal",
|
|
119
|
+
async stream(component, streamOptions = {}) {
|
|
120
|
+
const mergedOptions = { ...options, ...streamOptions };
|
|
121
|
+
let resolveShell;
|
|
122
|
+
let resolveAll;
|
|
123
|
+
const shellReady = new Promise((r) => {
|
|
124
|
+
resolveShell = r;
|
|
125
|
+
});
|
|
126
|
+
const allReady = new Promise((r) => {
|
|
127
|
+
resolveAll = r;
|
|
128
|
+
});
|
|
129
|
+
try {
|
|
130
|
+
const { readable, writable } = new TransformStream();
|
|
131
|
+
const result = options.renderToStream(component, {
|
|
132
|
+
nonce: mergedOptions.nonce,
|
|
133
|
+
onCompleteShell: () => {
|
|
134
|
+
resolveShell();
|
|
135
|
+
mergedOptions.onShellReady?.();
|
|
136
|
+
},
|
|
137
|
+
onCompleteAll: () => {
|
|
138
|
+
resolveAll();
|
|
139
|
+
mergedOptions.onAllReady?.();
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
result.pipeTo(writable);
|
|
143
|
+
return {
|
|
144
|
+
stream: readable,
|
|
145
|
+
abort: () => writable.abort(),
|
|
146
|
+
shellReady,
|
|
147
|
+
allReady
|
|
148
|
+
};
|
|
149
|
+
} catch (error) {
|
|
150
|
+
mergedOptions.onError?.(error);
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
async renderToString(component) {
|
|
155
|
+
if (!options.renderToString) {
|
|
156
|
+
throw new Error("[Flight] renderToString not provided to adapter");
|
|
157
|
+
}
|
|
158
|
+
return options.renderToString(component);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function createSvelteStreamAdapter(options) {
|
|
163
|
+
if (!options.render) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
"[Flight] createSvelteStreamAdapter requires render. Import it from svelte/server and pass it in options."
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
name: "svelte",
|
|
170
|
+
framework: "svelte@5+",
|
|
171
|
+
runtime: "universal",
|
|
172
|
+
async stream(component, streamOptions = {}) {
|
|
173
|
+
const mergedOptions = { ...options, ...streamOptions };
|
|
174
|
+
let resolveShell;
|
|
175
|
+
let resolveAll;
|
|
176
|
+
const shellReady = new Promise((r) => {
|
|
177
|
+
resolveShell = r;
|
|
178
|
+
});
|
|
179
|
+
const allReady = new Promise((r) => {
|
|
180
|
+
resolveAll = r;
|
|
181
|
+
});
|
|
182
|
+
try {
|
|
183
|
+
const result = options.render(component, { props: mergedOptions.props || {} });
|
|
184
|
+
const html = result.body;
|
|
185
|
+
const encoder = new TextEncoder();
|
|
186
|
+
const stream = new ReadableStream({
|
|
187
|
+
start(controller) {
|
|
188
|
+
if (result.head) {
|
|
189
|
+
controller.enqueue(encoder.encode(result.head));
|
|
190
|
+
}
|
|
191
|
+
resolveShell();
|
|
192
|
+
mergedOptions.onShellReady?.();
|
|
193
|
+
controller.enqueue(encoder.encode(html));
|
|
194
|
+
resolveAll();
|
|
195
|
+
mergedOptions.onAllReady?.();
|
|
196
|
+
controller.close();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return {
|
|
200
|
+
stream,
|
|
201
|
+
abort: () => {
|
|
202
|
+
},
|
|
203
|
+
shellReady,
|
|
204
|
+
allReady
|
|
205
|
+
};
|
|
206
|
+
} catch (error) {
|
|
207
|
+
mergedOptions.onError?.(error);
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
async renderToString(component) {
|
|
212
|
+
const result = options.render(component, { props: options?.props || {} });
|
|
213
|
+
return result.body;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function createHTMXStreamAdapter(options) {
|
|
218
|
+
return {
|
|
219
|
+
name: "htmx",
|
|
220
|
+
framework: "htmx@2+",
|
|
221
|
+
runtime: "universal",
|
|
222
|
+
async stream(htmlChunks, streamOptions = {}) {
|
|
223
|
+
const mergedOptions = { ...options, ...streamOptions };
|
|
224
|
+
const eventName = mergedOptions.eventName || "message";
|
|
225
|
+
const retryMs = mergedOptions.retryMs || 3e3;
|
|
226
|
+
let resolveShell;
|
|
227
|
+
let resolveAll;
|
|
228
|
+
const shellReady = new Promise((r) => {
|
|
229
|
+
resolveShell = r;
|
|
230
|
+
});
|
|
231
|
+
const allReady = new Promise((r) => {
|
|
232
|
+
resolveAll = r;
|
|
233
|
+
});
|
|
234
|
+
const encoder = new TextEncoder();
|
|
235
|
+
let chunkIndex = 0;
|
|
236
|
+
const stream = new ReadableStream({
|
|
237
|
+
start(controller) {
|
|
238
|
+
controller.enqueue(encoder.encode(`retry: ${retryMs}
|
|
239
|
+
|
|
240
|
+
`));
|
|
241
|
+
resolveShell();
|
|
242
|
+
mergedOptions.onShellReady?.();
|
|
243
|
+
},
|
|
244
|
+
async pull(controller) {
|
|
245
|
+
if (chunkIndex >= htmlChunks.length) {
|
|
246
|
+
resolveAll();
|
|
247
|
+
mergedOptions.onAllReady?.();
|
|
248
|
+
controller.close();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const chunk = htmlChunks[chunkIndex++];
|
|
252
|
+
const sseData = `event: ${eventName}
|
|
253
|
+
data: ${JSON.stringify(chunk)}
|
|
254
|
+
|
|
255
|
+
`;
|
|
256
|
+
controller.enqueue(encoder.encode(sseData));
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
return {
|
|
260
|
+
stream,
|
|
261
|
+
abort: () => {
|
|
262
|
+
},
|
|
263
|
+
shellReady,
|
|
264
|
+
allReady
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function createStreamAdapter(framework, options) {
|
|
270
|
+
switch (framework) {
|
|
271
|
+
case "react":
|
|
272
|
+
return createReactStreamAdapter(options);
|
|
273
|
+
case "vue":
|
|
274
|
+
return createVueStreamAdapter(options);
|
|
275
|
+
case "solid":
|
|
276
|
+
return createSolidStreamAdapter(options);
|
|
277
|
+
case "svelte":
|
|
278
|
+
return createSvelteStreamAdapter(options);
|
|
279
|
+
case "htmx":
|
|
280
|
+
return createHTMXStreamAdapter(options);
|
|
281
|
+
default:
|
|
282
|
+
throw new Error(`[Flight] Unknown framework: ${framework}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export { createHTMXStreamAdapter, createReactStreamAdapter, createSolidStreamAdapter, createStreamAdapter, createSvelteStreamAdapter, createVueStreamAdapter };
|
|
287
|
+
//# sourceMappingURL=chunk-SDYPG3JD.js.map
|
|
288
|
+
//# sourceMappingURL=chunk-SDYPG3JD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/streaming/adapters/index.ts"],"names":[],"mappings":"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","file":"chunk-SDYPG3JD.js","sourcesContent":["/**\r\n * @flightdev/core - Multi-Framework Streaming Adapters\r\n * \r\n * Streaming SSR adapters for React, Vue, Svelte, Solid, and HTMX.\r\n * Uses dependency injection pattern for optional framework dependencies.\r\n * \r\n * Best Practices 2026:\r\n * - Dependency injection for optional peer dependencies\r\n * - Support both Node.js and Edge runtimes \r\n * - Progressive hydration support\r\n * - Error boundary integration\r\n * \r\n * @example\r\n * ```typescript\r\n * // React adapter with your imports\r\n * import { renderToReadableStream } from 'react-dom/server';\r\n * \r\n * const adapter = createReactStreamAdapter({\r\n * renderToReadableStream,\r\n * bootstrapModules: ['/client.js'],\r\n * });\r\n * ```\r\n */\r\n\r\nimport type { StreamingRenderOptions, StreamingRenderResult } from '../index.js';\r\n\r\n// ============================================================================\r\n// Common Types\r\n// ============================================================================\r\n\r\n/**\r\n * Framework-specific streaming adapter\r\n */\r\nexport interface StreamingAdapter<TComponent = unknown> {\r\n /** Adapter name */\r\n readonly name: string;\r\n /** Framework version support */\r\n readonly framework: string;\r\n /** Runtime support */\r\n readonly runtime: 'universal' | 'node' | 'edge';\r\n\r\n /**\r\n * Create a streaming response from a component\r\n */\r\n stream(\r\n component: TComponent,\r\n options?: StreamingRenderOptions\r\n ): Promise<StreamingRenderResult>;\r\n\r\n /**\r\n * Render to static string (for comparison/fallback)\r\n */\r\n renderToString?(component: TComponent): Promise<string>;\r\n}\r\n\r\n/**\r\n * Common adapter options\r\n */\r\nexport interface AdapterOptions {\r\n /** Enable streaming (default: true) */\r\n streaming?: boolean;\r\n /** Scripts to bootstrap on client */\r\n bootstrapScripts?: string[];\r\n /** Modules to bootstrap on client */\r\n bootstrapModules?: string[];\r\n /** Error handling strategy */\r\n onError?: (error: Error) => void;\r\n /** Shell ready callback */\r\n onShellReady?: () => void;\r\n /** All content ready callback */\r\n onAllReady?: () => void;\r\n}\r\n\r\n// ============================================================================\r\n// React Adapter (Dependency Injection Pattern)\r\n// ============================================================================\r\n\r\n/**\r\n * React streaming adapter options with required dependencies\r\n */\r\nexport interface ReactAdapterOptions extends AdapterOptions {\r\n /** React's renderToReadableStream (for Edge) */\r\n renderToReadableStream?: (\r\n element: unknown,\r\n options?: {\r\n bootstrapScripts?: string[];\r\n bootstrapModules?: string[];\r\n identifierPrefix?: string;\r\n signal?: AbortSignal;\r\n onError?: (error: unknown) => void;\r\n }\r\n ) => Promise<ReadableStream<Uint8Array> & { allReady: Promise<void> }>;\r\n\r\n /** React's renderToString (for static fallback) */\r\n renderToString?: (element: unknown) => string;\r\n\r\n /** Custom identifier prefix */\r\n identifierPrefix?: string;\r\n /** Abort signal */\r\n signal?: AbortSignal;\r\n}\r\n\r\n/**\r\n * Create a React streaming adapter\r\n * \r\n * @example\r\n * ```typescript\r\n * import { renderToReadableStream, renderToString } from 'react-dom/server';\r\n * \r\n * const adapter = createReactStreamAdapter({\r\n * renderToReadableStream,\r\n * renderToString,\r\n * bootstrapModules: ['/client.js'],\r\n * });\r\n * \r\n * const result = await adapter.stream(<App />);\r\n * ```\r\n */\r\nexport function createReactStreamAdapter(options: ReactAdapterOptions): StreamingAdapter {\r\n if (!options.renderToReadableStream) {\r\n throw new Error(\r\n '[Flight] createReactStreamAdapter requires renderToReadableStream. ' +\r\n 'Import it from react-dom/server and pass it in options.'\r\n );\r\n }\r\n\r\n return {\r\n name: 'react',\r\n framework: 'react@18+',\r\n runtime: 'edge',\r\n\r\n async stream(component, streamOptions = {}) {\r\n const mergedOptions = { ...options, ...streamOptions };\r\n\r\n let resolveShell: () => void;\r\n let resolveAll: () => void;\r\n const shellReady = new Promise<void>((r) => { resolveShell = r; });\r\n const allReady = new Promise<void>((r) => { resolveAll = r; });\r\n\r\n const stream = await options.renderToReadableStream!(component, {\r\n bootstrapScripts: mergedOptions.bootstrapScripts,\r\n bootstrapModules: mergedOptions.bootstrapModules,\r\n identifierPrefix: mergedOptions.identifierPrefix,\r\n signal: mergedOptions.signal,\r\n onError: (error: unknown) => {\r\n mergedOptions.onError?.(error as Error);\r\n },\r\n });\r\n\r\n // Shell is ready when stream is created\r\n resolveShell!();\r\n mergedOptions.onShellReady?.();\r\n\r\n // Track all ready via stream completion\r\n stream.allReady.then(() => {\r\n resolveAll!();\r\n mergedOptions.onAllReady?.();\r\n });\r\n\r\n return {\r\n stream,\r\n abort: () => { /* stream handles abort via signal */ },\r\n shellReady,\r\n allReady,\r\n };\r\n },\r\n\r\n async renderToString(component) {\r\n if (!options.renderToString) {\r\n throw new Error('[Flight] renderToString not provided to adapter');\r\n }\r\n return options.renderToString(component);\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Vue Adapter (Dependency Injection Pattern)\r\n// ============================================================================\r\n\r\n/**\r\n * Vue streaming adapter options\r\n */\r\nexport interface VueAdapterOptions extends AdapterOptions {\r\n /** Vue's renderToWebStream */\r\n renderToWebStream?: (app: unknown, context?: Record<string, unknown>) => ReadableStream;\r\n /** Vue's renderToString */\r\n renderToString?: (app: unknown) => Promise<string>;\r\n /** Vue app context */\r\n context?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Create a Vue 3 streaming adapter\r\n * \r\n * @example\r\n * ```typescript\r\n * import { renderToWebStream, renderToString } from 'vue/server-renderer';\r\n * \r\n * const adapter = createVueStreamAdapter({\r\n * renderToWebStream,\r\n * renderToString,\r\n * });\r\n * \r\n * const result = await adapter.stream(createSSRApp(App));\r\n * ```\r\n */\r\nexport function createVueStreamAdapter(options: VueAdapterOptions): StreamingAdapter {\r\n if (!options.renderToWebStream) {\r\n throw new Error(\r\n '[Flight] createVueStreamAdapter requires renderToWebStream. ' +\r\n 'Import it from vue/server-renderer and pass it in options.'\r\n );\r\n }\r\n\r\n return {\r\n name: 'vue',\r\n framework: 'vue@3+',\r\n runtime: 'universal',\r\n\r\n async stream(app, streamOptions = {}) {\r\n const mergedOptions = { ...options, ...streamOptions };\r\n\r\n let resolveShell: () => void;\r\n let resolveAll: () => void;\r\n const shellReady = new Promise<void>((r) => { resolveShell = r; });\r\n const allReady = new Promise<void>((r) => { resolveAll = r; });\r\n\r\n try {\r\n const stream = options.renderToWebStream!(app, mergedOptions.context);\r\n\r\n // Vue streams shell immediately\r\n resolveShell!();\r\n mergedOptions.onShellReady?.();\r\n\r\n // Wrap to detect completion\r\n const reader = stream.getReader();\r\n\r\n const wrappedStream = new ReadableStream<Uint8Array>({\r\n async pull(controller) {\r\n const { done, value } = await reader.read();\r\n if (done) {\r\n resolveAll!();\r\n mergedOptions.onAllReady?.();\r\n controller.close();\r\n } else {\r\n controller.enqueue(value);\r\n }\r\n },\r\n });\r\n\r\n return {\r\n stream: wrappedStream,\r\n abort: () => reader.cancel(),\r\n shellReady,\r\n allReady,\r\n };\r\n } catch (error) {\r\n mergedOptions.onError?.(error as Error);\r\n throw error;\r\n }\r\n },\r\n\r\n async renderToString(app) {\r\n if (!options.renderToString) {\r\n throw new Error('[Flight] renderToString not provided to adapter');\r\n }\r\n return options.renderToString(app);\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Solid Adapter (Dependency Injection Pattern)\r\n// ============================================================================\r\n\r\n/**\r\n * Solid streaming adapter options\r\n */\r\nexport interface SolidAdapterOptions extends AdapterOptions {\r\n /** Solid's renderToStream */\r\n renderToStream?: (\r\n fn: () => unknown,\r\n options?: {\r\n nonce?: string;\r\n onCompleteShell?: () => void;\r\n onCompleteAll?: () => void;\r\n }\r\n ) => { pipeTo: (writable: WritableStream) => void };\r\n /** Solid's renderToString */\r\n renderToString?: (fn: () => unknown) => string;\r\n /** Nonce for CSP */\r\n nonce?: string;\r\n}\r\n\r\n/**\r\n * Create a Solid.js streaming adapter\r\n * \r\n * @example\r\n * ```typescript\r\n * import { renderToStream, renderToString } from 'solid-js/web';\r\n * \r\n * const adapter = createSolidStreamAdapter({\r\n * renderToStream,\r\n * renderToString,\r\n * });\r\n * \r\n * const result = await adapter.stream(() => <App />);\r\n * ```\r\n */\r\nexport function createSolidStreamAdapter(options: SolidAdapterOptions): StreamingAdapter {\r\n if (!options.renderToStream) {\r\n throw new Error(\r\n '[Flight] createSolidStreamAdapter requires renderToStream. ' +\r\n 'Import it from solid-js/web and pass it in options.'\r\n );\r\n }\r\n\r\n return {\r\n name: 'solid',\r\n framework: 'solid-js@1+',\r\n runtime: 'universal',\r\n\r\n async stream(component, streamOptions = {}) {\r\n const mergedOptions = { ...options, ...streamOptions };\r\n\r\n let resolveShell: () => void;\r\n let resolveAll: () => void;\r\n const shellReady = new Promise<void>((r) => { resolveShell = r; });\r\n const allReady = new Promise<void>((r) => { resolveAll = r; });\r\n\r\n try {\r\n const { readable, writable } = new TransformStream<Uint8Array, Uint8Array>();\r\n\r\n // Solid's renderToStream with async options\r\n const result = options.renderToStream!(component as () => unknown, {\r\n nonce: mergedOptions.nonce,\r\n onCompleteShell: () => {\r\n resolveShell!();\r\n mergedOptions.onShellReady?.();\r\n },\r\n onCompleteAll: () => {\r\n resolveAll!();\r\n mergedOptions.onAllReady?.();\r\n },\r\n });\r\n\r\n // Pipe to transform stream\r\n result.pipeTo(writable);\r\n\r\n return {\r\n stream: readable,\r\n abort: () => writable.abort(),\r\n shellReady,\r\n allReady,\r\n };\r\n } catch (error) {\r\n mergedOptions.onError?.(error as Error);\r\n throw error;\r\n }\r\n },\r\n\r\n async renderToString(component) {\r\n if (!options.renderToString) {\r\n throw new Error('[Flight] renderToString not provided to adapter');\r\n }\r\n return options.renderToString(component as () => unknown);\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Svelte Adapter (Dependency Injection Pattern)\r\n// ============================================================================\r\n\r\n/**\r\n * Svelte streaming adapter options\r\n */\r\nexport interface SvelteAdapterOptions extends AdapterOptions {\r\n /** Svelte's render function */\r\n render?: (\r\n component: unknown,\r\n options?: { props?: Record<string, unknown> }\r\n ) => { body: string; head?: string };\r\n /** Props for the component */\r\n props?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Create a Svelte 5 streaming adapter\r\n * Note: Svelte's SSR is primarily string-based, streaming is simulated\r\n * \r\n * @example\r\n * ```typescript\r\n * import { render } from 'svelte/server';\r\n * \r\n * const adapter = createSvelteStreamAdapter({\r\n * render,\r\n * props: { name: 'World' },\r\n * });\r\n * \r\n * const result = await adapter.stream(App);\r\n * ```\r\n */\r\nexport function createSvelteStreamAdapter(options: SvelteAdapterOptions): StreamingAdapter {\r\n if (!options.render) {\r\n throw new Error(\r\n '[Flight] createSvelteStreamAdapter requires render. ' +\r\n 'Import it from svelte/server and pass it in options.'\r\n );\r\n }\r\n\r\n return {\r\n name: 'svelte',\r\n framework: 'svelte@5+',\r\n runtime: 'universal',\r\n\r\n async stream(component, streamOptions = {}) {\r\n const mergedOptions = { ...options, ...streamOptions };\r\n\r\n let resolveShell: () => void;\r\n let resolveAll: () => void;\r\n const shellReady = new Promise<void>((r) => { resolveShell = r; });\r\n const allReady = new Promise<void>((r) => { resolveAll = r; });\r\n\r\n try {\r\n // Render to string first\r\n const result = options.render!(component, { props: mergedOptions.props || {} });\r\n const html = result.body;\r\n\r\n // Convert to stream\r\n const encoder = new TextEncoder();\r\n const stream = new ReadableStream<Uint8Array>({\r\n start(controller) {\r\n // Send head/css first\r\n if (result.head) {\r\n controller.enqueue(encoder.encode(result.head));\r\n }\r\n\r\n resolveShell!();\r\n mergedOptions.onShellReady?.();\r\n\r\n // Send body\r\n controller.enqueue(encoder.encode(html));\r\n\r\n resolveAll!();\r\n mergedOptions.onAllReady?.();\r\n controller.close();\r\n },\r\n });\r\n\r\n return {\r\n stream,\r\n abort: () => { },\r\n shellReady,\r\n allReady,\r\n };\r\n } catch (error) {\r\n mergedOptions.onError?.(error as Error);\r\n throw error;\r\n }\r\n },\r\n\r\n async renderToString(component) {\r\n const result = options.render!(component, { props: options?.props || {} });\r\n return result.body;\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// HTMX Streaming Adapter (SSE-based)\r\n// ============================================================================\r\n\r\n/**\r\n * HTMX streaming adapter options\r\n */\r\nexport interface HTMXAdapterOptions extends AdapterOptions {\r\n /** Event name for SSE */\r\n eventName?: string;\r\n /** Retry interval for SSE */\r\n retryMs?: number;\r\n}\r\n\r\n/**\r\n * Create an HTMX SSE streaming adapter\r\n * Uses Server-Sent Events for progressive updates\r\n * \r\n * @example\r\n * ```typescript\r\n * const adapter = createHTMXStreamAdapter({\r\n * eventName: 'update',\r\n * retryMs: 3000,\r\n * });\r\n * \r\n * const result = await adapter.stream(['<div>Part 1</div>', '<div>Part 2</div>']);\r\n * ```\r\n */\r\nexport function createHTMXStreamAdapter(options?: HTMXAdapterOptions): StreamingAdapter<string[]> {\r\n return {\r\n name: 'htmx',\r\n framework: 'htmx@2+',\r\n runtime: 'universal',\r\n\r\n async stream(htmlChunks, streamOptions = {}) {\r\n const mergedOptions = { ...options, ...streamOptions };\r\n const eventName = mergedOptions.eventName || 'message';\r\n const retryMs = mergedOptions.retryMs || 3000;\r\n\r\n let resolveShell: () => void;\r\n let resolveAll: () => void;\r\n const shellReady = new Promise<void>((r) => { resolveShell = r; });\r\n const allReady = new Promise<void>((r) => { resolveAll = r; });\r\n\r\n const encoder = new TextEncoder();\r\n let chunkIndex = 0;\r\n\r\n const stream = new ReadableStream<Uint8Array>({\r\n start(controller) {\r\n // Send retry configuration\r\n controller.enqueue(encoder.encode(`retry: ${retryMs}\\n\\n`));\r\n resolveShell!();\r\n mergedOptions.onShellReady?.();\r\n },\r\n\r\n async pull(controller) {\r\n if (chunkIndex >= htmlChunks.length) {\r\n resolveAll!();\r\n mergedOptions.onAllReady?.();\r\n controller.close();\r\n return;\r\n }\r\n\r\n const chunk = htmlChunks[chunkIndex++];\r\n const sseData = `event: ${eventName}\\ndata: ${JSON.stringify(chunk)}\\n\\n`;\r\n controller.enqueue(encoder.encode(sseData));\r\n },\r\n });\r\n\r\n return {\r\n stream,\r\n abort: () => { },\r\n shellReady,\r\n allReady,\r\n };\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Adapter Factory\r\n// ============================================================================\r\n\r\nexport type FrameworkType = 'react' | 'vue' | 'solid' | 'svelte' | 'htmx';\r\n\r\n/**\r\n * Create a streaming adapter for any supported framework\r\n * Note: For react, vue, solid, svelte you need to pass the required dependencies\r\n */\r\nexport function createStreamAdapter(\r\n framework: FrameworkType,\r\n options?: AdapterOptions & Record<string, unknown>\r\n): StreamingAdapter {\r\n switch (framework) {\r\n case 'react':\r\n return createReactStreamAdapter(options as ReactAdapterOptions);\r\n case 'vue':\r\n return createVueStreamAdapter(options as VueAdapterOptions);\r\n case 'solid':\r\n return createSolidStreamAdapter(options as SolidAdapterOptions);\r\n case 'svelte':\r\n return createSvelteStreamAdapter(options as SvelteAdapterOptions);\r\n case 'htmx':\r\n return createHTMXStreamAdapter(options as HTMXAdapterOptions);\r\n default:\r\n throw new Error(`[Flight] Unknown framework: ${framework}`);\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// src/rsc/stream.ts
|
|
2
|
+
function createFlightStream(chunks, options = {}) {
|
|
3
|
+
const { onChunk, onComplete, onError } = options;
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
return new ReadableStream({
|
|
6
|
+
async start(controller) {
|
|
7
|
+
try {
|
|
8
|
+
for await (const chunk of chunks) {
|
|
9
|
+
const line = JSON.stringify(chunk) + "\n";
|
|
10
|
+
controller.enqueue(encoder.encode(line));
|
|
11
|
+
onChunk?.(chunk);
|
|
12
|
+
}
|
|
13
|
+
controller.close();
|
|
14
|
+
onComplete?.();
|
|
15
|
+
} catch (error) {
|
|
16
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
17
|
+
onError?.(err);
|
|
18
|
+
controller.error(err);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function createFlightStreamFromArray(chunks, options = {}) {
|
|
24
|
+
async function* generator() {
|
|
25
|
+
for (const chunk of chunks) {
|
|
26
|
+
yield chunk;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return createFlightStream(generator(), options);
|
|
30
|
+
}
|
|
31
|
+
async function* parseFlightStream(stream) {
|
|
32
|
+
const reader = stream.getReader();
|
|
33
|
+
const decoder = new TextDecoder();
|
|
34
|
+
let buffer = "";
|
|
35
|
+
try {
|
|
36
|
+
while (true) {
|
|
37
|
+
const { done, value } = await reader.read();
|
|
38
|
+
if (done) {
|
|
39
|
+
if (buffer.trim()) {
|
|
40
|
+
yield parseChunk(buffer);
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
buffer += decoder.decode(value, { stream: true });
|
|
45
|
+
const lines = buffer.split("\n");
|
|
46
|
+
buffer = lines.pop() ?? "";
|
|
47
|
+
for (const line of lines) {
|
|
48
|
+
if (line.trim()) {
|
|
49
|
+
yield parseChunk(line);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} finally {
|
|
54
|
+
reader.releaseLock();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function parseFlightStreamSync(data) {
|
|
58
|
+
const chunks = [];
|
|
59
|
+
for (const line of data.split("\n")) {
|
|
60
|
+
if (line.trim()) {
|
|
61
|
+
chunks.push(parseChunk(line));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return chunks;
|
|
65
|
+
}
|
|
66
|
+
function parseChunk(line) {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(line);
|
|
69
|
+
} catch {
|
|
70
|
+
throw new FlightStreamError(
|
|
71
|
+
`Failed to parse Flight chunk: ${line.slice(0, 100)}${line.length > 100 ? "..." : ""}`,
|
|
72
|
+
line
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function consumeFlightStream(stream) {
|
|
77
|
+
const startTime = Date.now();
|
|
78
|
+
const chunks = [];
|
|
79
|
+
const errors = [];
|
|
80
|
+
let root;
|
|
81
|
+
for await (const chunk of parseFlightStream(stream)) {
|
|
82
|
+
chunks.push(chunk);
|
|
83
|
+
if (chunk.type === "S" && chunk.id === "root") {
|
|
84
|
+
root = chunk;
|
|
85
|
+
}
|
|
86
|
+
if (chunk.type === "E") {
|
|
87
|
+
errors.push(chunk);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
chunks,
|
|
92
|
+
root,
|
|
93
|
+
errors,
|
|
94
|
+
duration: Date.now() - startTime
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function createFlightResponse(chunks, options = {}) {
|
|
98
|
+
const { status = 200, headers = {} } = options;
|
|
99
|
+
return new Response(createFlightStream(chunks), {
|
|
100
|
+
status,
|
|
101
|
+
headers: {
|
|
102
|
+
"Content-Type": "text/x-flight",
|
|
103
|
+
"Transfer-Encoding": "chunked",
|
|
104
|
+
"Cache-Control": "no-cache, no-store",
|
|
105
|
+
"X-Content-Type-Options": "nosniff",
|
|
106
|
+
...headers
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function createHybridResponse(htmlStream, flightChunks, options = {}) {
|
|
111
|
+
const { status = 200, headers = {} } = options;
|
|
112
|
+
const encoder = new TextEncoder();
|
|
113
|
+
const flightPayload = JSON.stringify(flightChunks);
|
|
114
|
+
const inlineScript = `<script type="text/x-flight">${escapeScript(flightPayload)}</script>`;
|
|
115
|
+
const transform = new TransformStream({
|
|
116
|
+
transform(chunk, controller) {
|
|
117
|
+
controller.enqueue(chunk);
|
|
118
|
+
},
|
|
119
|
+
flush(controller) {
|
|
120
|
+
controller.enqueue(encoder.encode(inlineScript));
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
const combinedStream = htmlStream.pipeThrough(transform);
|
|
124
|
+
return new Response(combinedStream, {
|
|
125
|
+
status,
|
|
126
|
+
headers: {
|
|
127
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
128
|
+
"Transfer-Encoding": "chunked",
|
|
129
|
+
"X-Content-Type-Options": "nosniff",
|
|
130
|
+
...headers
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function escapeScript(content) {
|
|
135
|
+
return content.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
|
|
136
|
+
}
|
|
137
|
+
function createStreamController() {
|
|
138
|
+
const encoder = new TextEncoder();
|
|
139
|
+
let controller;
|
|
140
|
+
const stream = new ReadableStream({
|
|
141
|
+
start(ctrl) {
|
|
142
|
+
controller = ctrl;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
stream,
|
|
147
|
+
enqueue(chunk) {
|
|
148
|
+
const line = JSON.stringify(chunk) + "\n";
|
|
149
|
+
controller.enqueue(encoder.encode(line));
|
|
150
|
+
},
|
|
151
|
+
error(err) {
|
|
152
|
+
controller.error(err);
|
|
153
|
+
},
|
|
154
|
+
close() {
|
|
155
|
+
controller.close();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function mergeFlightStreams(...streams) {
|
|
160
|
+
const readers = streams.map((s) => s.getReader());
|
|
161
|
+
return new ReadableStream({
|
|
162
|
+
async pull(controller) {
|
|
163
|
+
const promises = readers.map(async (reader, index2) => {
|
|
164
|
+
const result2 = await reader.read();
|
|
165
|
+
return { result: result2, index: index2 };
|
|
166
|
+
});
|
|
167
|
+
const { result, index } = await Promise.race(promises);
|
|
168
|
+
if (result.done) {
|
|
169
|
+
readers.splice(index, 1);
|
|
170
|
+
if (readers.length === 0) {
|
|
171
|
+
controller.close();
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
controller.enqueue(result.value);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function transformFlightStream(stream, transform) {
|
|
180
|
+
const encoder = new TextEncoder();
|
|
181
|
+
return new ReadableStream({
|
|
182
|
+
async start(controller) {
|
|
183
|
+
try {
|
|
184
|
+
for await (const chunk of parseFlightStream(stream)) {
|
|
185
|
+
const transformed = await transform(chunk);
|
|
186
|
+
if (transformed) {
|
|
187
|
+
const line = JSON.stringify(transformed) + "\n";
|
|
188
|
+
controller.enqueue(encoder.encode(line));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
controller.close();
|
|
192
|
+
} catch (error) {
|
|
193
|
+
controller.error(error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
function prettyPrintChunks(chunks) {
|
|
199
|
+
const lines = [];
|
|
200
|
+
for (const chunk of chunks) {
|
|
201
|
+
const prefix = getChunkTypeLabel(chunk.type);
|
|
202
|
+
const id = "id" in chunk ? chunk.id : "boundary" in chunk ? chunk.boundary : "?";
|
|
203
|
+
lines.push(`[${prefix}] ${id}`);
|
|
204
|
+
if (chunk.type === "S" && chunk.tree) {
|
|
205
|
+
lines.push(` \u2514\u2500 Tree: ${prettyPrintElement(chunk.tree)}`);
|
|
206
|
+
}
|
|
207
|
+
if (chunk.type === "C") {
|
|
208
|
+
lines.push(` \u2514\u2500 Module: ${chunk.module}#${chunk.export}`);
|
|
209
|
+
}
|
|
210
|
+
if (chunk.type === "E") {
|
|
211
|
+
lines.push(` \u2514\u2500 Error: ${chunk.message}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return lines.join("\n");
|
|
215
|
+
}
|
|
216
|
+
function getChunkTypeLabel(type) {
|
|
217
|
+
switch (type) {
|
|
218
|
+
case "S":
|
|
219
|
+
return "SERVER";
|
|
220
|
+
case "C":
|
|
221
|
+
return "CLIENT";
|
|
222
|
+
case "A":
|
|
223
|
+
return "ACTION";
|
|
224
|
+
case "E":
|
|
225
|
+
return "ERROR ";
|
|
226
|
+
case "H":
|
|
227
|
+
return "HINT ";
|
|
228
|
+
case "M":
|
|
229
|
+
return "META ";
|
|
230
|
+
default:
|
|
231
|
+
return "UNKNWN";
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function prettyPrintElement(element) {
|
|
235
|
+
if (!element || typeof element !== "object") return String(element);
|
|
236
|
+
const el = element;
|
|
237
|
+
if (el.$$type === "host") return `<${el.tag}>...`;
|
|
238
|
+
if (el.$$type === "text") return '"text"';
|
|
239
|
+
if (el.$$type === "fragment") return "<>...</>";
|
|
240
|
+
if (el.$$type === "suspense") return "<Suspense>...</Suspense>";
|
|
241
|
+
if (el.$$type === "client") return `<ClientRef:${el.ref}>`;
|
|
242
|
+
if (el.$$type === "lazy") return "<Lazy...>";
|
|
243
|
+
if (el.$$type === "null") return "null";
|
|
244
|
+
return JSON.stringify(element).slice(0, 50);
|
|
245
|
+
}
|
|
246
|
+
var FlightStreamError = class extends Error {
|
|
247
|
+
constructor(message, rawData) {
|
|
248
|
+
super(message);
|
|
249
|
+
this.rawData = rawData;
|
|
250
|
+
this.name = "FlightStreamError";
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
export { FlightStreamError, consumeFlightStream, createFlightResponse, createFlightStream, createFlightStreamFromArray, createHybridResponse, createStreamController, mergeFlightStreams, parseFlightStream, parseFlightStreamSync, prettyPrintChunks, transformFlightStream };
|
|
255
|
+
//# sourceMappingURL=chunk-SUG56SZO.js.map
|
|
256
|
+
//# sourceMappingURL=chunk-SUG56SZO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rsc/stream.ts"],"names":["index","result"],"mappings":"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","file":"chunk-SUG56SZO.js","sourcesContent":["/**\r\n * @flightdev/core - Flight Stream\r\n * \r\n * Protocolo de streaming para Server Components.\r\n * Usa NDJSON (Newline Delimited JSON) para máxima debuggabilidad.\r\n * \r\n * Filosofía Flight:\r\n * - Formato abierto y documentado\r\n * - Works con cualquier runtime (Node, Deno, Bun, Edge)\r\n * - Fácil de debuggear (text-based)\r\n * - Sin dependencias\r\n * \r\n * @module @flightdev/core/rsc/stream\r\n */\r\n\r\nimport type {\r\n FlightChunk,\r\n ServerComponentChunk,\r\n ErrorBoundaryChunk,\r\n} from './payload.js';\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Opciones para crear un FlightStream\r\n */\r\nexport interface FlightStreamOptions {\r\n /** Incluir timestamps en chunks */\r\n timestamps?: boolean;\r\n /** Prefix para IDs generados */\r\n idPrefix?: string;\r\n /** Callback cuando un chunk es enviado */\r\n onChunk?: (chunk: FlightChunk) => void;\r\n /** Callback cuando el stream termina */\r\n onComplete?: () => void;\r\n /** Callback en caso de error */\r\n onError?: (error: Error) => void;\r\n}\r\n\r\n/**\r\n * Resultado del parsing de un FlightStream\r\n */\r\nexport interface FlightStreamResult {\r\n /** Chunks recibidos */\r\n chunks: FlightChunk[];\r\n /** Componente raíz */\r\n root?: ServerComponentChunk;\r\n /** Errores encontrados */\r\n errors: ErrorBoundaryChunk[];\r\n /** Tiempo total de streaming en ms */\r\n duration: number;\r\n}\r\n\r\n// ============================================================================\r\n// Stream Creation\r\n// ============================================================================\r\n\r\n/**\r\n * Crea un ReadableStream desde un AsyncIterable de chunks\r\n * \r\n * @example\r\n * ```typescript\r\n * async function* renderApp() {\r\n * yield createServerChunk('root', tree);\r\n * yield createClientChunk('counter', './Counter', 'default', { initial: 0 });\r\n * }\r\n * \r\n * const stream = createFlightStream(renderApp());\r\n * return new Response(stream, { headers: { 'Content-Type': 'text/x-flight' } });\r\n * ```\r\n */\r\nexport function createFlightStream(\r\n chunks: AsyncIterable<FlightChunk>,\r\n options: FlightStreamOptions = {}\r\n): ReadableStream<Uint8Array> {\r\n const { onChunk, onComplete, onError } = options;\r\n const encoder = new TextEncoder();\r\n\r\n return new ReadableStream({\r\n async start(controller) {\r\n try {\r\n for await (const chunk of chunks) {\r\n // Serialize chunk to NDJSON line\r\n const line = JSON.stringify(chunk) + '\\n';\r\n controller.enqueue(encoder.encode(line));\r\n\r\n onChunk?.(chunk);\r\n }\r\n\r\n controller.close();\r\n onComplete?.();\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n onError?.(err);\r\n controller.error(err);\r\n }\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Crea un FlightStream desde un array de chunks\r\n */\r\nexport function createFlightStreamFromArray(\r\n chunks: FlightChunk[],\r\n options: FlightStreamOptions = {}\r\n): ReadableStream<Uint8Array> {\r\n async function* generator() {\r\n for (const chunk of chunks) {\r\n yield chunk;\r\n }\r\n }\r\n return createFlightStream(generator(), options);\r\n}\r\n\r\n// ============================================================================\r\n// Stream Parsing\r\n// ============================================================================\r\n\r\n/**\r\n * Parsea un FlightStream a chunks individuales\r\n * \r\n * @example\r\n * ```typescript\r\n * // En el cliente\r\n * const response = await fetch('/page');\r\n * const chunks = parseFlightStream(response.body!);\r\n * \r\n * for await (const chunk of chunks) {\r\n * handleChunk(chunk);\r\n * }\r\n * ```\r\n */\r\nexport async function* parseFlightStream(\r\n stream: ReadableStream<Uint8Array>\r\n): AsyncGenerator<FlightChunk> {\r\n const reader = stream.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n\r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n\r\n if (done) {\r\n // Process remaining buffer\r\n if (buffer.trim()) {\r\n yield parseChunk(buffer);\r\n }\r\n break;\r\n }\r\n\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n // Split by newlines and process complete lines\r\n const lines = buffer.split('\\n');\r\n buffer = lines.pop() ?? '';\r\n\r\n for (const line of lines) {\r\n if (line.trim()) {\r\n yield parseChunk(line);\r\n }\r\n }\r\n }\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n}\r\n\r\n/**\r\n * Parsea un string completo de FlightStream\r\n */\r\nexport function parseFlightStreamSync(data: string): FlightChunk[] {\r\n const chunks: FlightChunk[] = [];\r\n\r\n for (const line of data.split('\\n')) {\r\n if (line.trim()) {\r\n chunks.push(parseChunk(line));\r\n }\r\n }\r\n\r\n return chunks;\r\n}\r\n\r\n/**\r\n * Parsea una línea individual a un chunk\r\n */\r\nfunction parseChunk(line: string): FlightChunk {\r\n try {\r\n return JSON.parse(line) as FlightChunk;\r\n } catch {\r\n throw new FlightStreamError(\r\n `Failed to parse Flight chunk: ${line.slice(0, 100)}${line.length > 100 ? '...' : ''}`,\r\n line\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Consume un FlightStream y retorna todos los chunks\r\n */\r\nexport async function consumeFlightStream(\r\n stream: ReadableStream<Uint8Array>\r\n): Promise<FlightStreamResult> {\r\n const startTime = Date.now();\r\n const chunks: FlightChunk[] = [];\r\n const errors: ErrorBoundaryChunk[] = [];\r\n let root: ServerComponentChunk | undefined;\r\n\r\n for await (const chunk of parseFlightStream(stream)) {\r\n chunks.push(chunk);\r\n\r\n if (chunk.type === 'S' && chunk.id === 'root') {\r\n root = chunk;\r\n }\r\n\r\n if (chunk.type === 'E') {\r\n errors.push(chunk);\r\n }\r\n }\r\n\r\n return {\r\n chunks,\r\n root,\r\n errors,\r\n duration: Date.now() - startTime,\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Response Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Crea una Response con Flight payload\r\n */\r\nexport function createFlightResponse(\r\n chunks: AsyncIterable<FlightChunk>,\r\n options: FlightResponseOptions = {}\r\n): Response {\r\n const { status = 200, headers = {} } = options;\r\n\r\n return new Response(createFlightStream(chunks), {\r\n status,\r\n headers: {\r\n 'Content-Type': 'text/x-flight',\r\n 'Transfer-Encoding': 'chunked',\r\n 'Cache-Control': 'no-cache, no-store',\r\n 'X-Content-Type-Options': 'nosniff',\r\n ...headers,\r\n },\r\n });\r\n}\r\n\r\nexport interface FlightResponseOptions {\r\n status?: number;\r\n headers?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Crea una Response HTML con streaming SSR + Flight payload embebido\r\n */\r\nexport function createHybridResponse(\r\n htmlStream: ReadableStream<Uint8Array>,\r\n flightChunks: FlightChunk[],\r\n options: FlightResponseOptions = {}\r\n): Response {\r\n const { status = 200, headers = {} } = options;\r\n\r\n // Combine HTML stream with Flight payload as inline script\r\n const encoder = new TextEncoder();\r\n const flightPayload = JSON.stringify(flightChunks);\r\n const inlineScript = `<script type=\"text/x-flight\">${escapeScript(flightPayload)}</script>`;\r\n\r\n // Create a TransformStream to inject Flight payload before closing body\r\n const transform = new TransformStream<Uint8Array, Uint8Array>({\r\n transform(chunk, controller) {\r\n controller.enqueue(chunk);\r\n },\r\n flush(controller) {\r\n controller.enqueue(encoder.encode(inlineScript));\r\n },\r\n });\r\n\r\n const combinedStream = htmlStream.pipeThrough(transform);\r\n\r\n return new Response(combinedStream, {\r\n status,\r\n headers: {\r\n 'Content-Type': 'text/html; charset=utf-8',\r\n 'Transfer-Encoding': 'chunked',\r\n 'X-Content-Type-Options': 'nosniff',\r\n ...headers,\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Escapa contenido para uso seguro en script tags\r\n */\r\nfunction escapeScript(content: string): string {\r\n return content\r\n .replace(/</g, '\\\\u003c')\r\n .replace(/>/g, '\\\\u003e')\r\n .replace(/&/g, '\\\\u0026');\r\n}\r\n\r\n// ============================================================================\r\n// Streaming Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Crea un stream controller para enviar chunks progresivamente\r\n */\r\nexport function createStreamController(): {\r\n stream: ReadableStream<Uint8Array>;\r\n enqueue: (chunk: FlightChunk) => void;\r\n error: (error: Error) => void;\r\n close: () => void;\r\n} {\r\n const encoder = new TextEncoder();\r\n let controller: ReadableStreamDefaultController<Uint8Array>;\r\n\r\n const stream = new ReadableStream<Uint8Array>({\r\n start(ctrl) {\r\n controller = ctrl;\r\n },\r\n });\r\n\r\n return {\r\n stream,\r\n enqueue(chunk: FlightChunk) {\r\n const line = JSON.stringify(chunk) + '\\n';\r\n controller.enqueue(encoder.encode(line));\r\n },\r\n error(err: Error) {\r\n controller.error(err);\r\n },\r\n close() {\r\n controller.close();\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Merge múltiples streams en uno solo (para rendering paralelo)\r\n */\r\nexport function mergeFlightStreams(\r\n ...streams: ReadableStream<Uint8Array>[]\r\n): ReadableStream<Uint8Array> {\r\n const readers = streams.map(s => s.getReader());\r\n\r\n return new ReadableStream({\r\n async pull(controller) {\r\n // Race all readers\r\n const promises = readers.map(async (reader, index) => {\r\n const result = await reader.read();\r\n return { result, index };\r\n });\r\n\r\n const { result, index } = await Promise.race(promises);\r\n\r\n if (result.done) {\r\n // Remove completed reader\r\n readers.splice(index, 1);\r\n\r\n if (readers.length === 0) {\r\n controller.close();\r\n }\r\n } else {\r\n controller.enqueue(result.value);\r\n }\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Pipe a flight stream through a transform\r\n */\r\nexport function transformFlightStream(\r\n stream: ReadableStream<Uint8Array>,\r\n transform: (chunk: FlightChunk) => FlightChunk | null | Promise<FlightChunk | null>\r\n): ReadableStream<Uint8Array> {\r\n const encoder = new TextEncoder();\r\n\r\n return new ReadableStream({\r\n async start(controller) {\r\n try {\r\n for await (const chunk of parseFlightStream(stream)) {\r\n const transformed = await transform(chunk);\r\n if (transformed) {\r\n const line = JSON.stringify(transformed) + '\\n';\r\n controller.enqueue(encoder.encode(line));\r\n }\r\n }\r\n controller.close();\r\n } catch (error) {\r\n controller.error(error);\r\n }\r\n },\r\n });\r\n}\r\n\r\n// ============================================================================\r\n// Debug Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Pretty print Flight chunks para debugging\r\n */\r\nexport function prettyPrintChunks(chunks: FlightChunk[]): string {\r\n const lines: string[] = [];\r\n\r\n for (const chunk of chunks) {\r\n const prefix = getChunkTypeLabel(chunk.type);\r\n const id = 'id' in chunk ? chunk.id : 'boundary' in chunk ? chunk.boundary : '?';\r\n\r\n lines.push(`[${prefix}] ${id}`);\r\n\r\n if (chunk.type === 'S' && chunk.tree) {\r\n lines.push(` └─ Tree: ${prettyPrintElement(chunk.tree)}`);\r\n }\r\n if (chunk.type === 'C') {\r\n lines.push(` └─ Module: ${chunk.module}#${chunk.export}`);\r\n }\r\n if (chunk.type === 'E') {\r\n lines.push(` └─ Error: ${chunk.message}`);\r\n }\r\n }\r\n\r\n return lines.join('\\n');\r\n}\r\n\r\nfunction getChunkTypeLabel(type: FlightChunk['type']): string {\r\n switch (type) {\r\n case 'S': return 'SERVER';\r\n case 'C': return 'CLIENT';\r\n case 'A': return 'ACTION';\r\n case 'E': return 'ERROR ';\r\n case 'H': return 'HINT ';\r\n case 'M': return 'META ';\r\n default: return 'UNKNWN';\r\n }\r\n}\r\n\r\nfunction prettyPrintElement(element: unknown): string {\r\n if (!element || typeof element !== 'object') return String(element);\r\n\r\n const el = element as { $$type?: string; tag?: string; ref?: string };\r\n\r\n if (el.$$type === 'host') return `<${el.tag}>...`;\r\n if (el.$$type === 'text') return '\"text\"';\r\n if (el.$$type === 'fragment') return '<>...</>';\r\n if (el.$$type === 'suspense') return '<Suspense>...</Suspense>';\r\n if (el.$$type === 'client') return `<ClientRef:${el.ref}>`;\r\n if (el.$$type === 'lazy') return '<Lazy...>';\r\n if (el.$$type === 'null') return 'null';\r\n\r\n return JSON.stringify(element).slice(0, 50);\r\n}\r\n\r\n// ============================================================================\r\n// Custom Errors\r\n// ============================================================================\r\n\r\n/**\r\n * Error durante parsing de FlightStream\r\n */\r\nexport class FlightStreamError extends Error {\r\n constructor(\r\n message: string,\r\n public readonly rawData?: string\r\n ) {\r\n super(message);\r\n this.name = 'FlightStreamError';\r\n }\r\n}\r\n"]}
|