@flight-framework/core 0.1.0 → 0.2.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.
- package/LICENSE +21 -0
- package/dist/{chunk-5KF3QQWZ.js → chunk-3AY23FZP.js} +5 -19
- package/dist/chunk-3AY23FZP.js.map +1 -0
- package/dist/chunk-4F77J5TY.js +324 -0
- package/dist/chunk-4F77J5TY.js.map +1 -0
- package/dist/chunk-5GUCB2CG.js +300 -0
- package/dist/chunk-5GUCB2CG.js.map +1 -0
- package/dist/chunk-62C7LX2E.js +205 -0
- package/dist/chunk-62C7LX2E.js.map +1 -0
- package/dist/chunk-63SCEXD7.js +3 -0
- package/dist/chunk-63SCEXD7.js.map +1 -0
- package/dist/{chunk-YIOQC3DC.js → chunk-6BDCTUQY.js} +3 -3
- package/dist/{chunk-YIOQC3DC.js.map → chunk-6BDCTUQY.js.map} +1 -1
- package/dist/chunk-6CD5FIYI.js +252 -0
- package/dist/chunk-6CD5FIYI.js.map +1 -0
- package/dist/chunk-6XZQPPYC.js +285 -0
- package/dist/chunk-6XZQPPYC.js.map +1 -0
- package/dist/chunk-BJIMTO2I.js +213 -0
- package/dist/chunk-BJIMTO2I.js.map +1 -0
- package/dist/chunk-CLZSB5QD.js +258 -0
- package/dist/chunk-CLZSB5QD.js.map +1 -0
- package/dist/chunk-K2CQZPCG.js +257 -0
- package/dist/chunk-K2CQZPCG.js.map +1 -0
- package/dist/chunk-MRLCNFSD.js +341 -0
- package/dist/chunk-MRLCNFSD.js.map +1 -0
- package/dist/chunk-PSJPMEQK.js +212 -0
- package/dist/chunk-PSJPMEQK.js.map +1 -0
- package/dist/chunk-Q62ZQ6FM.js +218 -0
- package/dist/chunk-Q62ZQ6FM.js.map +1 -0
- package/dist/{chunk-6WSPUG5L.js → chunk-RSVA2EYO.js} +2 -2
- package/dist/chunk-RSVA2EYO.js.map +1 -0
- package/dist/chunk-T3S5YC7L.js +256 -0
- package/dist/chunk-T3S5YC7L.js.map +1 -0
- package/dist/{chunk-OBNYNJB5.js → chunk-WOEIJWGJ.js} +6 -8
- package/dist/chunk-WOEIJWGJ.js.map +1 -0
- package/dist/{chunk-I2B4WSHC.js → chunk-XSY5AAXT.js} +3 -4
- package/dist/chunk-XSY5AAXT.js.map +1 -0
- package/dist/chunk-Y22AMGTM.js +3 -0
- package/dist/chunk-Y22AMGTM.js.map +1 -0
- package/dist/file-router/streaming-hints.d.ts +1 -1
- package/dist/file-router/streaming-hints.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +19 -7
- package/dist/index.js.map +1 -1
- 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 +20 -124
- package/dist/rsc/index.js +13 -1
- package/dist/rsc/legacy.d.ts +131 -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 +160 -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/streaming/index.js +1 -1
- package/dist/streaming/observability.js +2 -2
- package/dist/streaming/priority.js +1 -1
- package/package.json +180 -124
- package/dist/chunk-5KF3QQWZ.js.map +0 -1
- package/dist/chunk-6WSPUG5L.js.map +0 -1
- package/dist/chunk-I2B4WSHC.js.map +0 -1
- package/dist/chunk-OBNYNJB5.js.map +0 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// src/rsc/adapters/preact.ts
|
|
2
|
+
var CLIENT_REFERENCE = /* @__PURE__ */ Symbol.for("flight.client.reference");
|
|
3
|
+
function createPreactAdapter(deps) {
|
|
4
|
+
const { preact, renderToString } = deps || {};
|
|
5
|
+
return {
|
|
6
|
+
name: "preact",
|
|
7
|
+
isElement(value) {
|
|
8
|
+
if (preact?.isValidElement) {
|
|
9
|
+
return preact.isValidElement(value);
|
|
10
|
+
}
|
|
11
|
+
return typeof value === "object" && value !== null && "type" in value && "props" in value;
|
|
12
|
+
},
|
|
13
|
+
getElementType(element) {
|
|
14
|
+
const vnode = element;
|
|
15
|
+
const type = vnode.type;
|
|
16
|
+
if (type === null) {
|
|
17
|
+
const props = vnode.props;
|
|
18
|
+
if (typeof props === "string" || typeof props === "number") {
|
|
19
|
+
return { kind: "text", value: String(props) };
|
|
20
|
+
}
|
|
21
|
+
return { kind: "null" };
|
|
22
|
+
}
|
|
23
|
+
if (typeof type === "string") {
|
|
24
|
+
return { kind: "host", tag: type };
|
|
25
|
+
}
|
|
26
|
+
if (type === preact?.Fragment) {
|
|
27
|
+
return { kind: "fragment" };
|
|
28
|
+
}
|
|
29
|
+
if (typeof type === "function") {
|
|
30
|
+
const fn = type;
|
|
31
|
+
if (preact?.Component && type.prototype instanceof preact.Component) {
|
|
32
|
+
return {
|
|
33
|
+
kind: "component",
|
|
34
|
+
fn: (props) => {
|
|
35
|
+
const Component = type;
|
|
36
|
+
const instance = new Component(props);
|
|
37
|
+
return instance.render();
|
|
38
|
+
},
|
|
39
|
+
name: fn.displayName || fn.name || "PreactComponent"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
kind: "component",
|
|
44
|
+
fn,
|
|
45
|
+
name: fn.displayName || fn.name || "Component"
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return { kind: "null" };
|
|
49
|
+
},
|
|
50
|
+
getProps(element) {
|
|
51
|
+
return element.props || {};
|
|
52
|
+
},
|
|
53
|
+
getChildren(element) {
|
|
54
|
+
const props = element.props;
|
|
55
|
+
const children = props?.children;
|
|
56
|
+
if (children === void 0 || children === null) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
if (Array.isArray(children)) {
|
|
60
|
+
return children.flat();
|
|
61
|
+
}
|
|
62
|
+
return [children];
|
|
63
|
+
},
|
|
64
|
+
getKey(element) {
|
|
65
|
+
const key = element.key;
|
|
66
|
+
return key !== null ? key : void 0;
|
|
67
|
+
},
|
|
68
|
+
isClientBoundary(component) {
|
|
69
|
+
if (typeof component !== "function") return false;
|
|
70
|
+
const comp = component;
|
|
71
|
+
if (comp.__flight_client === true) return true;
|
|
72
|
+
if (comp.$$typeof === CLIENT_REFERENCE) return true;
|
|
73
|
+
return false;
|
|
74
|
+
},
|
|
75
|
+
async renderToString(element) {
|
|
76
|
+
if (renderToString) {
|
|
77
|
+
return renderToString(element);
|
|
78
|
+
}
|
|
79
|
+
throw new Error(
|
|
80
|
+
"renderToString not provided. Pass preact-render-to-string when creating the adapter: createPreactAdapter({ preact, renderToString })"
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function createPreactConsumer(deps, options = {}) {
|
|
86
|
+
const { preact } = deps;
|
|
87
|
+
const { registry = /* @__PURE__ */ new Map() } = options;
|
|
88
|
+
return {
|
|
89
|
+
/**
|
|
90
|
+
* Register a client component
|
|
91
|
+
*/
|
|
92
|
+
register(id, loader) {
|
|
93
|
+
registry.set(id, loader);
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* Convert Flight elements to Preact VNodes
|
|
97
|
+
*/
|
|
98
|
+
toPreactElement(element) {
|
|
99
|
+
switch (element.$$type) {
|
|
100
|
+
case "null":
|
|
101
|
+
return null;
|
|
102
|
+
case "text":
|
|
103
|
+
return element.value;
|
|
104
|
+
case "host": {
|
|
105
|
+
const children = element.children.map((c) => this.toPreactElement(c));
|
|
106
|
+
return preact.h(
|
|
107
|
+
element.tag,
|
|
108
|
+
{ ...element.props, key: element.key },
|
|
109
|
+
...children
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
case "fragment": {
|
|
113
|
+
const children = element.children.map((c) => this.toPreactElement(c));
|
|
114
|
+
return preact.h(preact.Fragment, null, ...children);
|
|
115
|
+
}
|
|
116
|
+
case "suspense": {
|
|
117
|
+
const children = element.children.map((c) => this.toPreactElement(c));
|
|
118
|
+
return preact.h(preact.Fragment, null, ...children);
|
|
119
|
+
}
|
|
120
|
+
case "client": {
|
|
121
|
+
const loader = registry.get(element.ref);
|
|
122
|
+
if (!loader) {
|
|
123
|
+
console.warn(`[Flight] Client component not registered: ${element.ref}`);
|
|
124
|
+
if (element.ssr) {
|
|
125
|
+
return preact.h("div", {
|
|
126
|
+
dangerouslySetInnerHTML: { __html: element.ssr }
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const LazyWrapper = (props) => {
|
|
132
|
+
const loadedRef = { current: null };
|
|
133
|
+
loader().then((mod) => {
|
|
134
|
+
loadedRef.current = mod.default ?? mod;
|
|
135
|
+
});
|
|
136
|
+
if (loadedRef.current) {
|
|
137
|
+
return preact.h(loadedRef.current, props);
|
|
138
|
+
}
|
|
139
|
+
if (element.ssr) {
|
|
140
|
+
return preact.h("div", {
|
|
141
|
+
dangerouslySetInnerHTML: { __html: element.ssr }
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
return preact.h("div", { "data-flight-loading": element.ref });
|
|
145
|
+
};
|
|
146
|
+
return preact.h(LazyWrapper, {});
|
|
147
|
+
}
|
|
148
|
+
case "lazy": {
|
|
149
|
+
if (element.fallback) {
|
|
150
|
+
return this.toPreactElement(element.fallback);
|
|
151
|
+
}
|
|
152
|
+
return preact.h("div", { "data-flight-pending": element.id });
|
|
153
|
+
}
|
|
154
|
+
default:
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
/**
|
|
159
|
+
* Hydrate Flight payload into DOM
|
|
160
|
+
*/
|
|
161
|
+
hydrate(chunks, container, hydrateFn) {
|
|
162
|
+
const rootChunk = chunks.find((c) => c.type === "S" && c.id === "root");
|
|
163
|
+
if (!rootChunk || rootChunk.type !== "S") {
|
|
164
|
+
throw new Error("[Flight] No root chunk found");
|
|
165
|
+
}
|
|
166
|
+
for (const chunk of chunks) {
|
|
167
|
+
if (chunk.type === "C") {
|
|
168
|
+
if (!registry.has(chunk.id)) {
|
|
169
|
+
registry.set(chunk.id, () => import(
|
|
170
|
+
/* webpackIgnore: true */
|
|
171
|
+
chunk.module
|
|
172
|
+
));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const element = this.toPreactElement(rootChunk.tree);
|
|
177
|
+
if (hydrateFn) {
|
|
178
|
+
hydrateFn(element, container);
|
|
179
|
+
} else {
|
|
180
|
+
const { render } = deps?.preact || {};
|
|
181
|
+
if (render) {
|
|
182
|
+
render(element, container);
|
|
183
|
+
} else {
|
|
184
|
+
throw new Error("[Flight] No hydrate or render function provided");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function markAsPreactClientComponent(component, moduleId, exportName = "default") {
|
|
191
|
+
const marked = component;
|
|
192
|
+
marked.$$typeof = CLIENT_REFERENCE;
|
|
193
|
+
marked.__flight_client = true;
|
|
194
|
+
marked.__flight_module = moduleId;
|
|
195
|
+
marked.__flight_export = exportName;
|
|
196
|
+
return marked;
|
|
197
|
+
}
|
|
198
|
+
function lazy(loader) {
|
|
199
|
+
let Component = null;
|
|
200
|
+
let promise = null;
|
|
201
|
+
const LazyComponent = ((props) => {
|
|
202
|
+
if (Component) {
|
|
203
|
+
return Component(props);
|
|
204
|
+
}
|
|
205
|
+
if (!promise) {
|
|
206
|
+
promise = loader().then((mod) => {
|
|
207
|
+
Component = mod.default;
|
|
208
|
+
return mod;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
throw promise;
|
|
212
|
+
});
|
|
213
|
+
return LazyComponent;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export { createPreactAdapter, createPreactConsumer, lazy, markAsPreactClientComponent };
|
|
217
|
+
//# sourceMappingURL=chunk-Q62ZQ6FM.js.map
|
|
218
|
+
//# sourceMappingURL=chunk-Q62ZQ6FM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rsc/adapters/preact.ts"],"names":[],"mappings":"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","file":"chunk-Q62ZQ6FM.js","sourcesContent":["/**\r\n * @flight-framework/core - Preact UI Adapter\r\n * \r\n * Adapter for using Preact with Flight Server Components.\r\n * Enables Flight to render Preact components without tight coupling.\r\n * \r\n * Philosophy: Zero lock-in - Preact is optional, user decides.\r\n * \r\n * @module @flight-framework/core/rsc/adapters/preact\r\n */\r\n\r\nimport type { UIAdapter, ElementTypeInfo } from '../renderer.js';\r\n\r\n// ============================================================================\r\n// Preact Symbols (shared with React for compat)\r\n// ============================================================================\r\n\r\nconst PREACT_VNODE_TYPE = Symbol.for('preact-vnode');\r\n\r\n// Flight reference symbols\r\nconst CLIENT_REFERENCE = Symbol.for('flight.client.reference');\r\nconst SERVER_REFERENCE = Symbol.for('flight.server.reference');\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Minimal Preact VNode interface\r\n */\r\ninterface PreactVNode {\r\n type: unknown;\r\n props: Record<string, unknown>;\r\n key: string | number | null;\r\n ref: unknown;\r\n __?: unknown; // parent\r\n __k?: unknown[]; // children\r\n __b?: number; // depth\r\n __e?: unknown; // dom\r\n __c?: unknown; // component\r\n}\r\n\r\n/**\r\n * Preact dependencies (user provides these)\r\n */\r\nexport interface PreactDependencies {\r\n /** preact module */\r\n preact: {\r\n h: (type: unknown, props?: unknown, ...children: unknown[]) => PreactVNode;\r\n Fragment?: unknown;\r\n Component?: unknown;\r\n isValidElement?: (value: unknown) => boolean;\r\n cloneElement?: (vnode: PreactVNode, props?: unknown) => PreactVNode;\r\n };\r\n /** preact-render-to-string module (optional - for SSR) */\r\n renderToString?: (vnode: PreactVNode) => string;\r\n /** preact/hooks module (optional) */\r\n hooks?: {\r\n useState: <T>(initial: T) => [T, (v: T) => void];\r\n useEffect: (fn: () => void | (() => void), deps?: unknown[]) => void;\r\n useMemo: <T>(fn: () => T, deps: unknown[]) => T;\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Adapter Implementation\r\n// ============================================================================\r\n\r\n/**\r\n * Create Preact UI Adapter\r\n * \r\n * @example\r\n * ```typescript\r\n * import { createPreactAdapter } from '@flight-framework/core/rsc/adapters/preact';\r\n * import * as preact from 'preact';\r\n * import renderToString from 'preact-render-to-string';\r\n * \r\n * const adapter = createPreactAdapter({\r\n * preact,\r\n * renderToString,\r\n * });\r\n * \r\n * const renderer = createRenderer(adapter);\r\n * ```\r\n */\r\nexport function createPreactAdapter(deps?: PreactDependencies): UIAdapter {\r\n const { preact, renderToString } = deps || {};\r\n\r\n return {\r\n name: 'preact',\r\n\r\n isElement(value: unknown): boolean {\r\n if (preact?.isValidElement) {\r\n return preact.isValidElement(value);\r\n }\r\n // Fallback: check for VNode structure\r\n return (\r\n typeof value === 'object' &&\r\n value !== null &&\r\n 'type' in value &&\r\n 'props' in value\r\n );\r\n },\r\n\r\n getElementType(element: unknown): ElementTypeInfo {\r\n const vnode = element as PreactVNode;\r\n const type = vnode.type;\r\n\r\n // Null type (text or null node)\r\n if (type === null) {\r\n const props = vnode.props;\r\n if (typeof props === 'string' || typeof props === 'number') {\r\n return { kind: 'text', value: String(props) };\r\n }\r\n return { kind: 'null' };\r\n }\r\n\r\n // String = host element (div, span, etc.)\r\n if (typeof type === 'string') {\r\n return { kind: 'host', tag: type };\r\n }\r\n\r\n // Fragment\r\n if (type === preact?.Fragment) {\r\n return { kind: 'fragment' };\r\n }\r\n\r\n // Function component\r\n if (typeof type === 'function') {\r\n const fn = type as ((props: Record<string, unknown>) => unknown) & {\r\n displayName?: string;\r\n name?: string;\r\n };\r\n\r\n // Check for class component (extends Component)\r\n if (preact?.Component && type.prototype instanceof (preact.Component as unknown as Function)) {\r\n return {\r\n kind: 'component',\r\n fn: (props) => {\r\n // Class components need instantiation\r\n const Component = type as new (props: unknown) => { render: () => unknown };\r\n const instance = new Component(props);\r\n return instance.render();\r\n },\r\n name: fn.displayName || fn.name || 'PreactComponent',\r\n };\r\n }\r\n\r\n return {\r\n kind: 'component',\r\n fn,\r\n name: fn.displayName || fn.name || 'Component'\r\n };\r\n }\r\n\r\n return { kind: 'null' };\r\n },\r\n\r\n getProps(element: unknown): Record<string, unknown> {\r\n return (element as PreactVNode).props || {};\r\n },\r\n\r\n getChildren(element: unknown): unknown[] {\r\n const props = (element as PreactVNode).props;\r\n const children = props?.children;\r\n\r\n if (children === undefined || children === null) {\r\n return [];\r\n }\r\n\r\n if (Array.isArray(children)) {\r\n return children.flat();\r\n }\r\n\r\n return [children];\r\n },\r\n\r\n getKey(element: unknown): string | number | undefined {\r\n const key = (element as PreactVNode).key;\r\n return key !== null ? key : undefined;\r\n },\r\n\r\n isClientBoundary(component: unknown): boolean {\r\n if (typeof component !== 'function') return false;\r\n\r\n const comp = component as {\r\n $$typeof?: symbol;\r\n __flight_client?: boolean;\r\n };\r\n\r\n // Check for Flight client marker\r\n if (comp.__flight_client === true) return true;\r\n\r\n // Check for client reference symbol\r\n if (comp.$$typeof === CLIENT_REFERENCE) return true;\r\n\r\n return false;\r\n },\r\n\r\n async renderToString(element: unknown): Promise<string> {\r\n if (renderToString) {\r\n return renderToString(element as PreactVNode);\r\n }\r\n throw new Error(\r\n 'renderToString not provided. Pass preact-render-to-string when creating the adapter: ' +\r\n 'createPreactAdapter({ preact, renderToString })'\r\n );\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Preact Client Consumer\r\n// ============================================================================\r\n\r\n/**\r\n * Options for Preact consumer\r\n */\r\nexport interface PreactConsumerOptions {\r\n /** Registry of client components */\r\n registry?: Map<string, () => Promise<unknown>>;\r\n}\r\n\r\n/**\r\n * Create a Preact client-side consumer for Flight payloads\r\n */\r\nexport function createPreactConsumer(\r\n deps: PreactDependencies,\r\n options: PreactConsumerOptions = {}\r\n) {\r\n const { preact } = deps;\r\n const { registry = new Map() } = options;\r\n\r\n return {\r\n /**\r\n * Register a client component\r\n */\r\n register(id: string, loader: () => Promise<unknown>): void {\r\n registry.set(id, loader);\r\n },\r\n\r\n /**\r\n * Convert Flight elements to Preact VNodes\r\n */\r\n toPreactElement(element: import('../payload.js').FlightElement): unknown {\r\n switch (element.$$type) {\r\n case 'null':\r\n return null;\r\n\r\n case 'text':\r\n return element.value;\r\n\r\n case 'host': {\r\n const children = element.children.map(c => this.toPreactElement(c));\r\n return preact.h(\r\n element.tag,\r\n { ...element.props, key: element.key },\r\n ...children\r\n );\r\n }\r\n\r\n case 'fragment': {\r\n const children = element.children.map(c => this.toPreactElement(c));\r\n return preact.h(preact.Fragment!, null, ...children);\r\n }\r\n\r\n case 'suspense': {\r\n // Preact doesn't have built-in Suspense, use fragment\r\n const children = element.children.map(c => this.toPreactElement(c));\r\n return preact.h(preact.Fragment!, null, ...children);\r\n }\r\n\r\n case 'client': {\r\n const loader = registry.get(element.ref);\r\n if (!loader) {\r\n console.warn(`[Flight] Client component not registered: ${element.ref}`);\r\n if (element.ssr) {\r\n return preact.h('div', {\r\n dangerouslySetInnerHTML: { __html: element.ssr }\r\n });\r\n }\r\n return null;\r\n }\r\n\r\n // Create lazy loading wrapper\r\n // Preact doesn't have React.lazy, so we create a simple async loader\r\n const LazyWrapper = (props: Record<string, unknown>) => {\r\n // This is a simplified version - in production use @preact/signals\r\n // or a state management solution\r\n const loadedRef = { current: null as unknown };\r\n\r\n loader().then((mod: { default?: unknown }) => {\r\n loadedRef.current = mod.default ?? mod;\r\n });\r\n\r\n if (loadedRef.current) {\r\n return preact.h(loadedRef.current as string, props);\r\n }\r\n\r\n // Return SSR placeholder\r\n if (element.ssr) {\r\n return preact.h('div', {\r\n dangerouslySetInnerHTML: { __html: element.ssr }\r\n });\r\n }\r\n\r\n return preact.h('div', { 'data-flight-loading': element.ref });\r\n };\r\n\r\n return preact.h(LazyWrapper, {});\r\n }\r\n\r\n case 'lazy': {\r\n if (element.fallback) {\r\n return this.toPreactElement(element.fallback);\r\n }\r\n return preact.h('div', { 'data-flight-pending': element.id });\r\n }\r\n\r\n default:\r\n return null;\r\n }\r\n },\r\n\r\n /**\r\n * Hydrate Flight payload into DOM\r\n */\r\n hydrate(\r\n chunks: import('../payload.js').FlightChunk[],\r\n container: Element,\r\n hydrateFn?: (vnode: unknown, container: Element) => void\r\n ): void {\r\n const rootChunk = chunks.find(c => c.type === 'S' && c.id === 'root');\r\n if (!rootChunk || rootChunk.type !== 'S') {\r\n throw new Error('[Flight] No root chunk found');\r\n }\r\n\r\n // Register client components\r\n for (const chunk of chunks) {\r\n if (chunk.type === 'C') {\r\n if (!registry.has(chunk.id)) {\r\n registry.set(chunk.id, () => import(/* webpackIgnore: true */ chunk.module));\r\n }\r\n }\r\n }\r\n\r\n const element = this.toPreactElement(rootChunk.tree);\r\n\r\n if (hydrateFn) {\r\n hydrateFn(element, container);\r\n } else {\r\n // Fallback: use preact.render (not ideal for SSR)\r\n const { render } = deps?.preact as { render?: (vnode: unknown, container: Element) => void } || {};\r\n if (render) {\r\n render(element, container);\r\n } else {\r\n throw new Error('[Flight] No hydrate or render function provided');\r\n }\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ============================================================================\r\n// Utility Types\r\n// ============================================================================\r\n\r\n/**\r\n * Type helper for Preact Server Component\r\n */\r\nexport type PreactServerComponent<P = Record<string, unknown>> = (\r\n props: P,\r\n ctx: import('../context.js').ServerContext\r\n) => Promise<PreactVNode> | PreactVNode;\r\n\r\n/**\r\n * Mark a Preact component as a client component\r\n */\r\nexport function markAsPreactClientComponent<T extends (...args: unknown[]) => unknown>(\r\n component: T,\r\n moduleId: string,\r\n exportName = 'default'\r\n): T {\r\n const marked = component as T & {\r\n $$typeof: symbol;\r\n __flight_client: boolean;\r\n __flight_module: string;\r\n __flight_export: string;\r\n };\r\n\r\n marked.$$typeof = CLIENT_REFERENCE;\r\n marked.__flight_client = true;\r\n marked.__flight_module = moduleId;\r\n marked.__flight_export = exportName;\r\n\r\n return marked;\r\n}\r\n\r\n/**\r\n * Create a lazy-loading component for Preact\r\n */\r\nexport function lazy<T extends (...args: unknown[]) => unknown>(\r\n loader: () => Promise<{ default: T }>\r\n): T {\r\n let Component: T | null = null;\r\n let promise: Promise<{ default: T }> | null = null;\r\n\r\n const LazyComponent = ((props: unknown) => {\r\n if (Component) {\r\n return Component(props);\r\n }\r\n\r\n if (!promise) {\r\n promise = loader().then(mod => {\r\n Component = mod.default;\r\n return mod;\r\n });\r\n }\r\n\r\n throw promise; // Suspense-style\r\n }) as T;\r\n\r\n return LazyComponent;\r\n}\r\n"]}
|
|
@@ -217,5 +217,5 @@ async function streamSequential(boundaries) {
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
export { createLazyContent, createStreamingResponse, createStreamingSSR, renderWithStreaming, streamParallel, streamSequential };
|
|
220
|
-
//# sourceMappingURL=chunk-
|
|
221
|
-
//# sourceMappingURL=chunk-
|
|
220
|
+
//# sourceMappingURL=chunk-RSVA2EYO.js.map
|
|
221
|
+
//# sourceMappingURL=chunk-RSVA2EYO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/streaming/index.ts"],"names":[],"mappings":"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","file":"chunk-RSVA2EYO.js","sourcesContent":["/**\r\n * @flight-framework/core - Streaming SSR\r\n * \r\n * Full streaming server-side rendering implementation following React 18+/19 patterns.\r\n * Supports both Node.js (renderToPipeableStream) and Edge (renderToReadableStream) environments.\r\n * \r\n * Best Practices 2025/2026:\r\n * - Progressive HTML streaming with Suspense boundaries\r\n * - Shell-first rendering for fast TTFB\r\n * - Nested Suspense for granular loading states\r\n * - Error boundaries for graceful degradation\r\n * - Web Streams API for Edge runtime compatibility\r\n */\r\n\r\n// ============================================================================\r\n// Types\r\n// ============================================================================\r\n\r\n/**\r\n * Streaming render options following React's conventions\r\n */\r\nexport interface StreamingRenderOptions {\r\n /** Bootstrap scripts to load on client */\r\n bootstrapScripts?: string[];\r\n /** Bootstrap ES modules */\r\n bootstrapModules?: string[];\r\n /** Inline script content */\r\n bootstrapScriptContent?: string;\r\n /** Prefix for React IDs (useId) */\r\n identifierPrefix?: string;\r\n /** Nonce for CSP */\r\n nonce?: string;\r\n /** Callback when shell is ready (main content before Suspense) */\r\n onShellReady?: () => void;\r\n /** Callback when shell errors */\r\n onShellError?: (error: Error) => void;\r\n /** Callback when all content is ready */\r\n onAllReady?: () => void;\r\n /** Callback for any error */\r\n onError?: (error: Error) => void;\r\n /** Timeout before aborting stream */\r\n timeoutMs?: number;\r\n /** Progressive hydration enabled */\r\n progressiveHydration?: boolean;\r\n}\r\n\r\n/**\r\n * Streaming render result\r\n */\r\nexport interface StreamingRenderResult {\r\n /** The readable stream to pipe to response */\r\n stream: ReadableStream<Uint8Array>;\r\n /** Abort the stream */\r\n abort: () => void;\r\n /** Promise that resolves when shell is ready */\r\n shellReady: Promise<void>;\r\n /** Promise that resolves when all content is ready */\r\n allReady: Promise<void>;\r\n}\r\n\r\n/**\r\n * Suspense boundary configuration\r\n */\r\nexport interface SuspenseBoundaryConfig {\r\n /** Unique ID for this boundary */\r\n id: string;\r\n /** Fallback HTML to show while loading */\r\n fallback: string;\r\n /** Content resolver promise */\r\n contentPromise: Promise<string>;\r\n /** \r\n * IDs of boundaries that must resolve before this one.\r\n * Enables dependency-aware streaming for complex data relationships.\r\n * @example ['user'] - Wait for 'user' boundary before starting\r\n */\r\n dependsOn?: string[];\r\n /** Custom metadata for observability */\r\n meta?: Record<string, unknown>;\r\n}\r\n\r\n// ============================================================================\r\n// Streaming Renderer\r\n// ============================================================================\r\n\r\n/**\r\n * Create a streaming SSR response using Web Streams API.\r\n * Compatible with Edge Runtime (Cloudflare, Vercel Edge, Deno).\r\n * \r\n * @example\r\n * ```typescript\r\n * const result = await createStreamingSSR({\r\n * shell: '<html><body><div id=\"root\">',\r\n * shellEnd: '</div></body></html>',\r\n * suspenseBoundaries: [\r\n * {\r\n * id: 'posts',\r\n * fallback: '<div>Loading posts...</div>',\r\n * contentPromise: fetchAndRenderPosts(),\r\n * }\r\n * ],\r\n * bootstrapScripts: ['/client.js'],\r\n * });\r\n * \r\n * return new Response(result.stream, {\r\n * headers: { 'Content-Type': 'text/html' },\r\n * });\r\n * ```\r\n */\r\nexport async function createStreamingSSR(config: {\r\n /** Initial HTML shell (before suspense content) */\r\n shell: string;\r\n /** Closing HTML shell */\r\n shellEnd: string;\r\n /** Suspense boundaries with async content */\r\n suspenseBoundaries?: SuspenseBoundaryConfig[];\r\n /** Streaming options */\r\n options?: StreamingRenderOptions;\r\n}): Promise<StreamingRenderResult> {\r\n const { shell, shellEnd, suspenseBoundaries = [], options = {} } = config;\r\n\r\n let shellResolved = false;\r\n let allResolved = false;\r\n let abortController: AbortController | null = null;\r\n\r\n // Shell ready promise\r\n let resolveShell: () => void;\r\n const shellReady = new Promise<void>((resolve) => {\r\n resolveShell = resolve;\r\n });\r\n\r\n // All ready promise\r\n let resolveAll: () => void;\r\n const allReady = new Promise<void>((resolve) => {\r\n resolveAll = resolve;\r\n });\r\n\r\n const encoder = new TextEncoder();\r\n\r\n const stream = new ReadableStream<Uint8Array>({\r\n async start(controller) {\r\n try {\r\n // 1. Send the shell immediately (fast TTFB)\r\n const shellWithPlaceholders = buildShellWithPlaceholders(\r\n shell,\r\n suspenseBoundaries,\r\n shellEnd,\r\n options\r\n );\r\n\r\n controller.enqueue(encoder.encode(shellWithPlaceholders));\r\n\r\n shellResolved = true;\r\n options.onShellReady?.();\r\n resolveShell!();\r\n\r\n // 2. Stream Suspense boundary contents as they resolve\r\n if (suspenseBoundaries.length > 0) {\r\n await streamSuspenseContent(controller, encoder, suspenseBoundaries, options);\r\n }\r\n\r\n // 3. Send hydration script if needed\r\n if (options.bootstrapScripts?.length || options.bootstrapModules?.length) {\r\n const hydrationScript = buildHydrationScript(options);\r\n controller.enqueue(encoder.encode(hydrationScript));\r\n }\r\n\r\n allResolved = true;\r\n options.onAllReady?.();\r\n resolveAll!();\r\n\r\n controller.close();\r\n } catch (error) {\r\n if (!shellResolved) {\r\n options.onShellError?.(error as Error);\r\n }\r\n options.onError?.(error as Error);\r\n controller.error(error);\r\n }\r\n },\r\n\r\n cancel() {\r\n abortController?.abort();\r\n },\r\n });\r\n\r\n const abort = () => {\r\n abortController?.abort();\r\n };\r\n\r\n // Timeout handling\r\n if (options.timeoutMs) {\r\n abortController = new AbortController();\r\n setTimeout(() => {\r\n if (!allResolved) {\r\n abort();\r\n }\r\n }, options.timeoutMs);\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 * Build shell HTML with Suspense placeholders\r\n */\r\nfunction buildShellWithPlaceholders(\r\n shell: string,\r\n boundaries: SuspenseBoundaryConfig[],\r\n shellEnd: string,\r\n options: StreamingRenderOptions\r\n): string {\r\n let html = shell;\r\n\r\n // Add inline bootstrap script if provided\r\n if (options.bootstrapScriptContent) {\r\n html += `<script>${options.bootstrapScriptContent}</script>`;\r\n }\r\n\r\n // Add Suspense fallbacks with placeholder markers\r\n for (const boundary of boundaries) {\r\n html += `\r\n<!--$?--><template id=\"B:${boundary.id}\"></template>\r\n${boundary.fallback}\r\n<!--/$-->`;\r\n }\r\n\r\n html += shellEnd;\r\n\r\n return html;\r\n}\r\n\r\n/**\r\n * Stream Suspense content as promises resolve\r\n */\r\nasync function streamSuspenseContent(\r\n controller: ReadableStreamDefaultController<Uint8Array>,\r\n encoder: TextEncoder,\r\n boundaries: SuspenseBoundaryConfig[],\r\n options: StreamingRenderOptions\r\n): Promise<void> {\r\n // Race all boundaries - stream each as it completes\r\n const pending = boundaries.map(async (boundary) => {\r\n try {\r\n const content = await boundary.contentPromise;\r\n return { boundary, content, error: null };\r\n } catch (error) {\r\n return { boundary, content: null, error: error as Error };\r\n }\r\n });\r\n\r\n // Process as each resolves\r\n const results = await Promise.allSettled(pending);\r\n\r\n for (const result of results) {\r\n if (result.status === 'fulfilled') {\r\n const { boundary, content, error } = result.value;\r\n\r\n if (error) {\r\n // Send error replacement\r\n const errorScript = buildErrorReplacement(boundary.id, error.message);\r\n controller.enqueue(encoder.encode(errorScript));\r\n options.onError?.(error);\r\n } else if (content) {\r\n // Send content replacement script\r\n const replacementScript = buildContentReplacement(boundary.id, content);\r\n controller.enqueue(encoder.encode(replacementScript));\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Build script to replace Suspense placeholder with actual content\r\n * This follows React's streaming hydration pattern\r\n */\r\nfunction buildContentReplacement(id: string, content: string): string {\r\n // Escape script-breaking characters\r\n const escaped = content\r\n .replace(/\\\\/g, '\\\\\\\\')\r\n .replace(/</g, '\\\\u003c')\r\n .replace(/>/g, '\\\\u003e')\r\n .replace(/'/g, \"\\\\'\")\r\n .replace(/\"/g, '\\\\\"')\r\n .replace(/\\n/g, '\\\\n')\r\n .replace(/\\r/g, '\\\\r');\r\n\r\n return `\r\n<script>\r\n(function(){\r\n var b=document.getElementById(\"B:${id}\");\r\n if(b){\r\n var p=b.previousSibling;\r\n while(p&&p.nodeType===8&&p.data===\"$?\")p=p.previousSibling;\r\n var n=b.nextSibling;\r\n var f=document.createDocumentFragment();\r\n var t=document.createElement(\"template\");\r\n t.innerHTML=\"${escaped}\";\r\n while(t.content.firstChild)f.appendChild(t.content.firstChild);\r\n if(n&&n.nodeType===8&&n.data===\"/$\"){\r\n var s=n.nextSibling;\r\n while(s&&s!==b){var x=s.nextSibling;s.parentNode.removeChild(s);s=x;}\r\n }\r\n b.parentNode.replaceChild(f,b);\r\n }\r\n})();\r\n</script>`;\r\n}\r\n\r\n/**\r\n * Build script to show error in place of Suspense content\r\n */\r\nfunction buildErrorReplacement(id: string, message: string): string {\r\n const escaped = message.replace(/'/g, \"\\\\'\").replace(/\"/g, '\\\\\"');\r\n\r\n return `\r\n<script>\r\n(function(){\r\n var b=document.getElementById(\"B:${id}\");\r\n if(b){\r\n var t=document.createElement(\"div\");\r\n t.className=\"streaming-error\";\r\n t.textContent=\"Error: ${escaped}\";\r\n b.parentNode.replaceChild(t,b);\r\n }\r\n})();\r\n</script>`;\r\n}\r\n\r\n/**\r\n * Build hydration bootstrap script\r\n */\r\nfunction buildHydrationScript(options: StreamingRenderOptions): string {\r\n let scripts = '';\r\n\r\n if (options.bootstrapScripts?.length) {\r\n for (const src of options.bootstrapScripts) {\r\n const nonceAttr = options.nonce ? ` nonce=\"${options.nonce}\"` : '';\r\n scripts += `<script src=\"${src}\"${nonceAttr} async></script>`;\r\n }\r\n }\r\n\r\n if (options.bootstrapModules?.length) {\r\n for (const src of options.bootstrapModules) {\r\n const nonceAttr = options.nonce ? ` nonce=\"${options.nonce}\"` : '';\r\n scripts += `<script type=\"module\" src=\"${src}\"${nonceAttr}></script>`;\r\n }\r\n }\r\n\r\n return scripts;\r\n}\r\n\r\n// ============================================================================\r\n// Streaming Response Helpers\r\n// ============================================================================\r\n\r\n/**\r\n * Create a streaming HTML Response object\r\n */\r\nexport function createStreamingResponse(\r\n stream: ReadableStream<Uint8Array>,\r\n options: {\r\n status?: number;\r\n headers?: Record<string, string>;\r\n } = {}\r\n): Response {\r\n return new Response(stream, {\r\n status: options.status || 200,\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 ...options.headers,\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Higher-level API: Render page with Suspense boundaries\r\n * \r\n * @example\r\n * ```typescript\r\n * return renderWithStreaming({\r\n * layout: ({ children }) => `\r\n * <html>\r\n * <head><title>My App</title></head>\r\n * <body><div id=\"root\">${children}</div></body>\r\n * </html>\r\n * `,\r\n * page: async () => '<h1>Welcome</h1>',\r\n * suspense: {\r\n * posts: {\r\n * fallback: '<div class=\"skeleton\">Loading...</div>',\r\n * content: fetchPosts().then(renderPosts),\r\n * },\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport async function renderWithStreaming(config: {\r\n /** Layout wrapper */\r\n layout: (props: { children: string }) => string;\r\n /** Main page content (sync part) */\r\n page: () => string | Promise<string>;\r\n /** Suspense boundaries keyed by ID */\r\n suspense?: Record<string, { fallback: string; content: Promise<string> }>;\r\n /** Bootstrap scripts */\r\n bootstrapScripts?: string[];\r\n /** Timeout in ms */\r\n timeoutMs?: number;\r\n}): Promise<Response> {\r\n const { layout, page, suspense = {}, bootstrapScripts, timeoutMs } = config;\r\n\r\n // Get synchronous page content\r\n const pageContent = await page();\r\n\r\n // Build suspense boundaries\r\n const boundaries: SuspenseBoundaryConfig[] = Object.entries(suspense).map(\r\n ([id, { fallback, content }]) => ({\r\n id,\r\n fallback,\r\n contentPromise: content,\r\n })\r\n );\r\n\r\n // Create streaming result\r\n const result = await createStreamingSSR({\r\n shell: layout({ children: pageContent }),\r\n shellEnd: '',\r\n suspenseBoundaries: boundaries,\r\n options: {\r\n bootstrapScripts,\r\n timeoutMs,\r\n },\r\n });\r\n\r\n return createStreamingResponse(result.stream);\r\n}\r\n\r\n// ============================================================================\r\n// Progressive Rendering Utilities\r\n// ============================================================================\r\n\r\n/**\r\n * Create a lazy component that streams its content\r\n */\r\nexport function createLazyContent<T>(\r\n fetcher: () => Promise<T>,\r\n renderer: (data: T) => string,\r\n fallback: string\r\n): { fallback: string; content: Promise<string> } {\r\n return {\r\n fallback,\r\n content: fetcher().then(renderer),\r\n };\r\n}\r\n\r\n/**\r\n * Parallel streaming: resolve multiple boundaries simultaneously\r\n */\r\nexport async function streamParallel(\r\n boundaries: Array<{\r\n id: string;\r\n fallback: string;\r\n content: () => Promise<string>;\r\n }>\r\n): Promise<SuspenseBoundaryConfig[]> {\r\n return boundaries.map((b) => ({\r\n id: b.id,\r\n fallback: b.fallback,\r\n contentPromise: b.content(),\r\n }));\r\n}\r\n\r\n/**\r\n * Sequential streaming: resolve boundaries in order\r\n */\r\nexport async function streamSequential(\r\n boundaries: Array<{\r\n id: string;\r\n fallback: string;\r\n content: () => Promise<string>;\r\n }>\r\n): Promise<SuspenseBoundaryConfig[]> {\r\n const result: SuspenseBoundaryConfig[] = [];\r\n\r\n for (const b of boundaries) {\r\n result.push({\r\n id: b.id,\r\n fallback: b.fallback,\r\n contentPromise: b.content(),\r\n });\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ============================================================================\r\n// Export for use with React\r\n// ============================================================================\r\n\r\n/**\r\n * NOTE: For React-specific streaming with renderToPipeableStream or \r\n * renderToReadableStream, use the dedicated React adapter:\r\n * \r\n * ```typescript\r\n * import { renderToReadableStream } from 'react-dom/server';\r\n * import { createStreamingResponse } from '@flight-framework/core/streaming';\r\n * \r\n * const stream = await renderToReadableStream(<App />, {\r\n * bootstrapScripts: ['/client.js'],\r\n * });\r\n * \r\n * return createStreamingResponse(stream);\r\n * ```\r\n * \r\n * This module provides framework-agnostic streaming primitives that work\r\n * with any UI library or custom HTML generation.\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 (error) {
|
|
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-T3S5YC7L.js.map
|
|
256
|
+
//# sourceMappingURL=chunk-T3S5YC7L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rsc/stream.ts"],"names":["index","result"],"mappings":"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","file":"chunk-T3S5YC7L.js","sourcesContent":["/**\r\n * @flight-framework/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 @flight-framework/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 (error) {\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"]}
|