@flight-framework/core 0.0.2 → 0.1.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/dist/{chunk-WOMWIW7D.js → chunk-54HPVE7N.js} +77 -6
- package/dist/chunk-54HPVE7N.js.map +1 -0
- package/dist/{chunk-ABNCAPQB.js → chunk-6WSPUG5L.js} +2 -2
- package/dist/chunk-6WSPUG5L.js.map +1 -0
- package/dist/chunk-I2B4WSHC.js +126 -0
- package/dist/chunk-I2B4WSHC.js.map +1 -0
- package/dist/chunk-MQQLYWZZ.js +288 -0
- package/dist/chunk-MQQLYWZZ.js.map +1 -0
- package/dist/chunk-OBNYNJB5.js +353 -0
- package/dist/chunk-OBNYNJB5.js.map +1 -0
- package/dist/chunk-WFAWAHJH.js +267 -0
- package/dist/chunk-WFAWAHJH.js.map +1 -0
- package/dist/chunk-XOIYNY4I.js +164 -0
- package/dist/chunk-XOIYNY4I.js.map +1 -0
- package/dist/chunk-YIOQC3DC.js +282 -0
- package/dist/chunk-YIOQC3DC.js.map +1 -0
- package/dist/file-router/index.d.ts +18 -1
- package/dist/file-router/index.js +1 -1
- 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/index.d.ts +6 -0
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- 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/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 +8 -0
- package/dist/streaming/index.js +1 -1
- 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/package.json +25 -1
- package/dist/chunk-ABNCAPQB.js.map +0 -1
- package/dist/chunk-WOMWIW7D.js.map +0 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flight-framework/core - Islands Architecture
|
|
3
|
+
*
|
|
4
|
+
* Selective hydration with fine-grained control over when and how
|
|
5
|
+
* components become interactive. Framework-agnostic islands primitives.
|
|
6
|
+
*
|
|
7
|
+
* Best Practices 2026:
|
|
8
|
+
* - Minimal JavaScript: Only hydrate what needs interactivity
|
|
9
|
+
* - Lazy hydration: Load JS when actually needed
|
|
10
|
+
* - Progressive enhancement: Works without JS
|
|
11
|
+
* - Performance: Reduce main thread work
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { defineIsland, renderIsland, hydrateIslands } from '@flight-framework/core/islands';
|
|
16
|
+
*
|
|
17
|
+
* // Server: Define an interactive island
|
|
18
|
+
* const Counter = defineIsland({
|
|
19
|
+
* id: 'counter',
|
|
20
|
+
* component: CounterComponent,
|
|
21
|
+
* hydrate: 'visible', // Only hydrate when scrolled into view
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Server: Render to HTML with island markers
|
|
25
|
+
* const html = await renderIsland(Counter, { initial: 0 });
|
|
26
|
+
*
|
|
27
|
+
* // Client: Hydrate all islands on the page
|
|
28
|
+
* hydrateIslands();
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* When to hydrate the island
|
|
33
|
+
*/
|
|
34
|
+
type HydrationTrigger = 'load' | 'idle' | 'visible' | 'interaction' | 'media' | 'never' | CustomHydrationTrigger;
|
|
35
|
+
/**
|
|
36
|
+
* Custom hydration trigger function
|
|
37
|
+
*/
|
|
38
|
+
interface CustomHydrationTrigger {
|
|
39
|
+
type: 'custom';
|
|
40
|
+
/** Name for debugging */
|
|
41
|
+
name: string;
|
|
42
|
+
/** Function that returns a promise resolving when hydration should occur */
|
|
43
|
+
when: (element: HTMLElement) => Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Island configuration
|
|
47
|
+
*/
|
|
48
|
+
interface IslandConfig<P = Record<string, unknown>> {
|
|
49
|
+
/** Unique identifier for this island type */
|
|
50
|
+
id: string;
|
|
51
|
+
/** The component to render (framework-specific) */
|
|
52
|
+
component: unknown;
|
|
53
|
+
/** When to hydrate on client */
|
|
54
|
+
hydrate: HydrationTrigger;
|
|
55
|
+
/** Default props */
|
|
56
|
+
defaultProps?: P;
|
|
57
|
+
/** Media query for 'media' trigger */
|
|
58
|
+
mediaQuery?: string;
|
|
59
|
+
/** Path to client-side component bundle */
|
|
60
|
+
clientEntry?: string;
|
|
61
|
+
/** Fallback HTML while not hydrated (optional override) */
|
|
62
|
+
fallback?: string;
|
|
63
|
+
/** Loading priority hint */
|
|
64
|
+
priority?: 'high' | 'low';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Island instance with props
|
|
68
|
+
*/
|
|
69
|
+
interface Island<P = Record<string, unknown>> {
|
|
70
|
+
/** Island configuration */
|
|
71
|
+
config: IslandConfig<P>;
|
|
72
|
+
/** Instance props */
|
|
73
|
+
props: P;
|
|
74
|
+
/** Unique instance ID (for multiple instances of same island type) */
|
|
75
|
+
instanceId: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Rendered island HTML with metadata
|
|
79
|
+
*/
|
|
80
|
+
interface RenderedIsland {
|
|
81
|
+
/** The HTML string */
|
|
82
|
+
html: string;
|
|
83
|
+
/** Island ID */
|
|
84
|
+
id: string;
|
|
85
|
+
/** Instance ID */
|
|
86
|
+
instanceId: string;
|
|
87
|
+
/** Serialized props for hydration */
|
|
88
|
+
propsScript: string;
|
|
89
|
+
/** CSS if any */
|
|
90
|
+
css?: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Island registry for client-side hydration
|
|
94
|
+
*/
|
|
95
|
+
interface IslandRegistry {
|
|
96
|
+
/** Register a component for an island ID */
|
|
97
|
+
register(id: string, loader: () => Promise<unknown>): void;
|
|
98
|
+
/** Get registered loader */
|
|
99
|
+
get(id: string): (() => Promise<unknown>) | undefined;
|
|
100
|
+
/** Check if island is registered */
|
|
101
|
+
has(id: string): boolean;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Client-side hydration options
|
|
105
|
+
*/
|
|
106
|
+
interface HydrateOptions {
|
|
107
|
+
/** Root element to scan for islands */
|
|
108
|
+
root?: HTMLElement;
|
|
109
|
+
/** Custom island registry */
|
|
110
|
+
registry?: IslandRegistry;
|
|
111
|
+
/** Callback when an island is hydrated */
|
|
112
|
+
onHydrate?: (id: string, instanceId: string, duration: number) => void;
|
|
113
|
+
/** Callback on hydration error */
|
|
114
|
+
onError?: (id: string, error: Error) => void;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Define an island component
|
|
118
|
+
*/
|
|
119
|
+
declare function defineIsland<P = Record<string, unknown>>(config: IslandConfig<P>): (props?: P) => Island<P>;
|
|
120
|
+
/**
|
|
121
|
+
* UI framework adapter for island rendering
|
|
122
|
+
*/
|
|
123
|
+
interface IslandRenderAdapter {
|
|
124
|
+
/** Framework name */
|
|
125
|
+
name: string;
|
|
126
|
+
/** Render component to HTML */
|
|
127
|
+
renderToString(component: unknown, props: Record<string, unknown>): Promise<string>;
|
|
128
|
+
/** Get CSS if any */
|
|
129
|
+
getCSS?(component: unknown): string;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Set the global island render adapter
|
|
133
|
+
*/
|
|
134
|
+
declare function setIslandAdapter(adapter: IslandRenderAdapter): void;
|
|
135
|
+
/**
|
|
136
|
+
* Render an island to HTML with hydration markers
|
|
137
|
+
*/
|
|
138
|
+
declare function renderIsland<P extends Record<string, unknown>>(island: Island<P>, adapter?: IslandRenderAdapter): Promise<RenderedIsland>;
|
|
139
|
+
/**
|
|
140
|
+
* Render multiple islands and collect their outputs
|
|
141
|
+
*/
|
|
142
|
+
declare function renderIslands<P extends Record<string, unknown>>(islands: Island<P>[], adapter?: IslandRenderAdapter): Promise<{
|
|
143
|
+
html: string;
|
|
144
|
+
propsScripts: string;
|
|
145
|
+
css: string;
|
|
146
|
+
}>;
|
|
147
|
+
/**
|
|
148
|
+
* Create an island registry for client-side hydration
|
|
149
|
+
*/
|
|
150
|
+
declare function createIslandRegistry(): IslandRegistry;
|
|
151
|
+
/**
|
|
152
|
+
* Register an island component for client-side hydration
|
|
153
|
+
*/
|
|
154
|
+
declare function registerIsland(id: string, loader: () => Promise<unknown>): void;
|
|
155
|
+
/**
|
|
156
|
+
* Client-side hydration bootstrapper
|
|
157
|
+
* Call this in your client entry point
|
|
158
|
+
*/
|
|
159
|
+
declare function hydrateIslands(options?: HydrateOptions): void;
|
|
160
|
+
/**
|
|
161
|
+
* Create a React island render adapter
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* import { renderToString } from 'react-dom/server';
|
|
166
|
+
* import { createElement } from 'react';
|
|
167
|
+
*
|
|
168
|
+
* const reactAdapter = createReactIslandAdapter({
|
|
169
|
+
* renderToString,
|
|
170
|
+
* createElement,
|
|
171
|
+
* });
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
declare function createReactIslandAdapter(deps: {
|
|
175
|
+
renderToString: (element: unknown) => string;
|
|
176
|
+
createElement: (type: unknown, props?: unknown) => unknown;
|
|
177
|
+
}): IslandRenderAdapter;
|
|
178
|
+
/**
|
|
179
|
+
* Create a Preact island render adapter
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* import { renderToString } from 'preact-render-to-string';
|
|
184
|
+
* import { h } from 'preact';
|
|
185
|
+
*
|
|
186
|
+
* const preactAdapter = createPreactIslandAdapter({
|
|
187
|
+
* renderToString,
|
|
188
|
+
* h,
|
|
189
|
+
* });
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
declare function createPreactIslandAdapter(deps: {
|
|
193
|
+
renderToString: (element: unknown) => string;
|
|
194
|
+
h: (type: unknown, props?: unknown) => unknown;
|
|
195
|
+
}): IslandRenderAdapter;
|
|
196
|
+
/**
|
|
197
|
+
* Create a Vue island render adapter
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* import { renderToString, createSSRApp } from 'vue/server-renderer';
|
|
202
|
+
*
|
|
203
|
+
* const vueAdapter = createVueIslandAdapter({
|
|
204
|
+
* renderToString,
|
|
205
|
+
* createSSRApp,
|
|
206
|
+
* });
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
declare function createVueIslandAdapter(deps: {
|
|
210
|
+
renderToString: (app: unknown) => Promise<string>;
|
|
211
|
+
createSSRApp: (component: unknown, props?: unknown) => unknown;
|
|
212
|
+
}): IslandRenderAdapter;
|
|
213
|
+
/**
|
|
214
|
+
* Create a Solid island render adapter
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* import { renderToString } from 'solid-js/web';
|
|
219
|
+
*
|
|
220
|
+
* const solidAdapter = createSolidIslandAdapter({
|
|
221
|
+
* renderToString,
|
|
222
|
+
* });
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
declare function createSolidIslandAdapter(deps: {
|
|
226
|
+
renderToString: (fn: () => unknown) => string;
|
|
227
|
+
}): IslandRenderAdapter;
|
|
228
|
+
/**
|
|
229
|
+
* Register the flight-island custom element
|
|
230
|
+
* This provides additional functionality like slot support
|
|
231
|
+
*/
|
|
232
|
+
declare function registerFlightIslandElement(): void;
|
|
233
|
+
|
|
234
|
+
export { type CustomHydrationTrigger, type HydrateOptions, type HydrationTrigger, type Island, type IslandConfig, type IslandRegistry, type IslandRenderAdapter, type RenderedIsland, createIslandRegistry, createPreactIslandAdapter, createReactIslandAdapter, createSolidIslandAdapter, createVueIslandAdapter, defineIsland, hydrateIslands, registerFlightIslandElement, registerIsland, renderIsland, renderIslands, setIslandAdapter };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createIslandRegistry, createPreactIslandAdapter, createReactIslandAdapter, createSolidIslandAdapter, createVueIslandAdapter, defineIsland, hydrateIslands, registerFlightIslandElement, registerIsland, renderIsland, renderIslands, setIslandAdapter } from '../chunk-WFAWAHJH.js';
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { StreamingRenderOptions, StreamingRenderResult } from '../index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @flight-framework/core - Multi-Framework Streaming Adapters
|
|
5
|
+
*
|
|
6
|
+
* Streaming SSR adapters for React, Vue, Svelte, Solid, and HTMX.
|
|
7
|
+
* Uses dependency injection pattern for optional framework dependencies.
|
|
8
|
+
*
|
|
9
|
+
* Best Practices 2026:
|
|
10
|
+
* - Dependency injection for optional peer dependencies
|
|
11
|
+
* - Support both Node.js and Edge runtimes
|
|
12
|
+
* - Progressive hydration support
|
|
13
|
+
* - Error boundary integration
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // React adapter with your imports
|
|
18
|
+
* import { renderToReadableStream } from 'react-dom/server';
|
|
19
|
+
*
|
|
20
|
+
* const adapter = createReactStreamAdapter({
|
|
21
|
+
* renderToReadableStream,
|
|
22
|
+
* bootstrapModules: ['/client.js'],
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Framework-specific streaming adapter
|
|
29
|
+
*/
|
|
30
|
+
interface StreamingAdapter<TComponent = unknown> {
|
|
31
|
+
/** Adapter name */
|
|
32
|
+
readonly name: string;
|
|
33
|
+
/** Framework version support */
|
|
34
|
+
readonly framework: string;
|
|
35
|
+
/** Runtime support */
|
|
36
|
+
readonly runtime: 'universal' | 'node' | 'edge';
|
|
37
|
+
/**
|
|
38
|
+
* Create a streaming response from a component
|
|
39
|
+
*/
|
|
40
|
+
stream(component: TComponent, options?: StreamingRenderOptions): Promise<StreamingRenderResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Render to static string (for comparison/fallback)
|
|
43
|
+
*/
|
|
44
|
+
renderToString?(component: TComponent): Promise<string>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Common adapter options
|
|
48
|
+
*/
|
|
49
|
+
interface AdapterOptions {
|
|
50
|
+
/** Enable streaming (default: true) */
|
|
51
|
+
streaming?: boolean;
|
|
52
|
+
/** Scripts to bootstrap on client */
|
|
53
|
+
bootstrapScripts?: string[];
|
|
54
|
+
/** Modules to bootstrap on client */
|
|
55
|
+
bootstrapModules?: string[];
|
|
56
|
+
/** Error handling strategy */
|
|
57
|
+
onError?: (error: Error) => void;
|
|
58
|
+
/** Shell ready callback */
|
|
59
|
+
onShellReady?: () => void;
|
|
60
|
+
/** All content ready callback */
|
|
61
|
+
onAllReady?: () => void;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* React streaming adapter options with required dependencies
|
|
65
|
+
*/
|
|
66
|
+
interface ReactAdapterOptions extends AdapterOptions {
|
|
67
|
+
/** React's renderToReadableStream (for Edge) */
|
|
68
|
+
renderToReadableStream?: (element: unknown, options?: {
|
|
69
|
+
bootstrapScripts?: string[];
|
|
70
|
+
bootstrapModules?: string[];
|
|
71
|
+
identifierPrefix?: string;
|
|
72
|
+
signal?: AbortSignal;
|
|
73
|
+
onError?: (error: unknown) => void;
|
|
74
|
+
}) => Promise<ReadableStream<Uint8Array> & {
|
|
75
|
+
allReady: Promise<void>;
|
|
76
|
+
}>;
|
|
77
|
+
/** React's renderToString (for static fallback) */
|
|
78
|
+
renderToString?: (element: unknown) => string;
|
|
79
|
+
/** Custom identifier prefix */
|
|
80
|
+
identifierPrefix?: string;
|
|
81
|
+
/** Abort signal */
|
|
82
|
+
signal?: AbortSignal;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Create a React streaming adapter
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* import { renderToReadableStream, renderToString } from 'react-dom/server';
|
|
90
|
+
*
|
|
91
|
+
* const adapter = createReactStreamAdapter({
|
|
92
|
+
* renderToReadableStream,
|
|
93
|
+
* renderToString,
|
|
94
|
+
* bootstrapModules: ['/client.js'],
|
|
95
|
+
* });
|
|
96
|
+
*
|
|
97
|
+
* const result = await adapter.stream(<App />);
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
declare function createReactStreamAdapter(options: ReactAdapterOptions): StreamingAdapter;
|
|
101
|
+
/**
|
|
102
|
+
* Vue streaming adapter options
|
|
103
|
+
*/
|
|
104
|
+
interface VueAdapterOptions extends AdapterOptions {
|
|
105
|
+
/** Vue's renderToWebStream */
|
|
106
|
+
renderToWebStream?: (app: unknown, context?: Record<string, unknown>) => ReadableStream;
|
|
107
|
+
/** Vue's renderToString */
|
|
108
|
+
renderToString?: (app: unknown) => Promise<string>;
|
|
109
|
+
/** Vue app context */
|
|
110
|
+
context?: Record<string, unknown>;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a Vue 3 streaming adapter
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* import { renderToWebStream, renderToString } from 'vue/server-renderer';
|
|
118
|
+
*
|
|
119
|
+
* const adapter = createVueStreamAdapter({
|
|
120
|
+
* renderToWebStream,
|
|
121
|
+
* renderToString,
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* const result = await adapter.stream(createSSRApp(App));
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function createVueStreamAdapter(options: VueAdapterOptions): StreamingAdapter;
|
|
128
|
+
/**
|
|
129
|
+
* Solid streaming adapter options
|
|
130
|
+
*/
|
|
131
|
+
interface SolidAdapterOptions extends AdapterOptions {
|
|
132
|
+
/** Solid's renderToStream */
|
|
133
|
+
renderToStream?: (fn: () => unknown, options?: {
|
|
134
|
+
nonce?: string;
|
|
135
|
+
onCompleteShell?: () => void;
|
|
136
|
+
onCompleteAll?: () => void;
|
|
137
|
+
}) => {
|
|
138
|
+
pipeTo: (writable: WritableStream) => void;
|
|
139
|
+
};
|
|
140
|
+
/** Solid's renderToString */
|
|
141
|
+
renderToString?: (fn: () => unknown) => string;
|
|
142
|
+
/** Nonce for CSP */
|
|
143
|
+
nonce?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create a Solid.js streaming adapter
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* import { renderToStream, renderToString } from 'solid-js/web';
|
|
151
|
+
*
|
|
152
|
+
* const adapter = createSolidStreamAdapter({
|
|
153
|
+
* renderToStream,
|
|
154
|
+
* renderToString,
|
|
155
|
+
* });
|
|
156
|
+
*
|
|
157
|
+
* const result = await adapter.stream(() => <App />);
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
declare function createSolidStreamAdapter(options: SolidAdapterOptions): StreamingAdapter;
|
|
161
|
+
/**
|
|
162
|
+
* Svelte streaming adapter options
|
|
163
|
+
*/
|
|
164
|
+
interface SvelteAdapterOptions extends AdapterOptions {
|
|
165
|
+
/** Svelte's render function */
|
|
166
|
+
render?: (component: unknown, options?: {
|
|
167
|
+
props?: Record<string, unknown>;
|
|
168
|
+
}) => {
|
|
169
|
+
body: string;
|
|
170
|
+
head?: string;
|
|
171
|
+
};
|
|
172
|
+
/** Props for the component */
|
|
173
|
+
props?: Record<string, unknown>;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Create a Svelte 5 streaming adapter
|
|
177
|
+
* Note: Svelte's SSR is primarily string-based, streaming is simulated
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* import { render } from 'svelte/server';
|
|
182
|
+
*
|
|
183
|
+
* const adapter = createSvelteStreamAdapter({
|
|
184
|
+
* render,
|
|
185
|
+
* props: { name: 'World' },
|
|
186
|
+
* });
|
|
187
|
+
*
|
|
188
|
+
* const result = await adapter.stream(App);
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
declare function createSvelteStreamAdapter(options: SvelteAdapterOptions): StreamingAdapter;
|
|
192
|
+
/**
|
|
193
|
+
* HTMX streaming adapter options
|
|
194
|
+
*/
|
|
195
|
+
interface HTMXAdapterOptions extends AdapterOptions {
|
|
196
|
+
/** Event name for SSE */
|
|
197
|
+
eventName?: string;
|
|
198
|
+
/** Retry interval for SSE */
|
|
199
|
+
retryMs?: number;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Create an HTMX SSE streaming adapter
|
|
203
|
+
* Uses Server-Sent Events for progressive updates
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* const adapter = createHTMXStreamAdapter({
|
|
208
|
+
* eventName: 'update',
|
|
209
|
+
* retryMs: 3000,
|
|
210
|
+
* });
|
|
211
|
+
*
|
|
212
|
+
* const result = await adapter.stream(['<div>Part 1</div>', '<div>Part 2</div>']);
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
declare function createHTMXStreamAdapter(options?: HTMXAdapterOptions): StreamingAdapter<string[]>;
|
|
216
|
+
type FrameworkType = 'react' | 'vue' | 'solid' | 'svelte' | 'htmx';
|
|
217
|
+
/**
|
|
218
|
+
* Create a streaming adapter for any supported framework
|
|
219
|
+
* Note: For react, vue, solid, svelte you need to pass the required dependencies
|
|
220
|
+
*/
|
|
221
|
+
declare function createStreamAdapter(framework: FrameworkType, options?: AdapterOptions & Record<string, unknown>): StreamingAdapter;
|
|
222
|
+
|
|
223
|
+
export { type AdapterOptions, type FrameworkType, type HTMXAdapterOptions, type ReactAdapterOptions, type SolidAdapterOptions, type StreamingAdapter, type SvelteAdapterOptions, type VueAdapterOptions, createHTMXStreamAdapter, createReactStreamAdapter, createSolidStreamAdapter, createStreamAdapter, createSvelteStreamAdapter, createVueStreamAdapter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flight-framework/core - Conditional Streaming
|
|
3
|
+
*
|
|
4
|
+
* Smart streaming decisions based on request context.
|
|
5
|
+
* Bots get full HTML, users get streaming - YOU control the logic.
|
|
6
|
+
*
|
|
7
|
+
* Best Practices 2026:
|
|
8
|
+
* - SEO-friendly: Crawlers receive complete HTML
|
|
9
|
+
* - Performance: Users get progressive streaming
|
|
10
|
+
* - Flexibility: Custom conditions for any use case
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { streamIf } from '@flight-framework/core/streaming';
|
|
15
|
+
*
|
|
16
|
+
* const response = await streamIf({
|
|
17
|
+
* request,
|
|
18
|
+
* condition: (req) => !isBot(req), // YOUR logic
|
|
19
|
+
* stream: () => createStreamingSSR({ ... }),
|
|
20
|
+
* static: () => renderToString(<App />),
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Condition function to determine if streaming should be used
|
|
26
|
+
*/
|
|
27
|
+
type StreamingCondition = (request: Request) => boolean | Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Built-in condition types
|
|
30
|
+
*/
|
|
31
|
+
type BuiltInCondition = 'always-stream' | 'never-stream' | 'no-bots' | 'fast-network' | 'modern-browser';
|
|
32
|
+
/**
|
|
33
|
+
* Configuration for conditional streaming
|
|
34
|
+
*/
|
|
35
|
+
interface StreamIfConfig<T = Response> {
|
|
36
|
+
/** The incoming request */
|
|
37
|
+
request: Request;
|
|
38
|
+
/** Condition to check (function or built-in) */
|
|
39
|
+
condition: StreamingCondition | BuiltInCondition;
|
|
40
|
+
/** Factory for streaming response */
|
|
41
|
+
stream: () => Promise<T> | T;
|
|
42
|
+
/** Factory for static response */
|
|
43
|
+
static: () => Promise<T> | T;
|
|
44
|
+
/** Optional: Custom bot patterns */
|
|
45
|
+
botPatterns?: RegExp[];
|
|
46
|
+
/** Optional: Force streaming via query param (for testing) */
|
|
47
|
+
forceStreamParam?: string;
|
|
48
|
+
/** Optional: Force static via query param (for testing) */
|
|
49
|
+
forceStaticParam?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Result of condition evaluation
|
|
53
|
+
*/
|
|
54
|
+
interface StreamingDecision {
|
|
55
|
+
/** Whether streaming was used */
|
|
56
|
+
streaming: boolean;
|
|
57
|
+
/** Reason for the decision */
|
|
58
|
+
reason: string;
|
|
59
|
+
/** The response */
|
|
60
|
+
response: Response;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Default bot patterns for detection
|
|
64
|
+
*/
|
|
65
|
+
declare const DEFAULT_BOT_PATTERNS: RegExp[];
|
|
66
|
+
/**
|
|
67
|
+
* Check if a request is from a bot/crawler
|
|
68
|
+
*/
|
|
69
|
+
declare function isBot(request: Request, customPatterns?: RegExp[]): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Check if request explicitly asks for no streaming
|
|
72
|
+
*/
|
|
73
|
+
declare function prefersNoStream(request: Request): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Check if a connection is likely slow (based on headers)
|
|
76
|
+
*/
|
|
77
|
+
declare function isSlowConnection(request: Request): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Check if browser supports streaming well
|
|
80
|
+
*/
|
|
81
|
+
declare function supportsStreaming(request: Request): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Conditionally use streaming or static rendering based on request context
|
|
84
|
+
*/
|
|
85
|
+
declare function streamIf<T = Response>(config: StreamIfConfig<T>): Promise<{
|
|
86
|
+
result: T;
|
|
87
|
+
streaming: boolean;
|
|
88
|
+
reason: string;
|
|
89
|
+
}>;
|
|
90
|
+
/**
|
|
91
|
+
* Create a middleware-style conditional streamer
|
|
92
|
+
*/
|
|
93
|
+
declare function createConditionalStreamer<T = Response>(defaultCondition: StreamingCondition | BuiltInCondition, options?: {
|
|
94
|
+
botPatterns?: RegExp[];
|
|
95
|
+
forceStreamParam?: string;
|
|
96
|
+
forceStaticParam?: string;
|
|
97
|
+
}): (config: {
|
|
98
|
+
request: Request;
|
|
99
|
+
stream: () => Promise<T> | T;
|
|
100
|
+
static: () => Promise<T> | T;
|
|
101
|
+
condition?: StreamingCondition | BuiltInCondition;
|
|
102
|
+
}) => Promise<{
|
|
103
|
+
result: T;
|
|
104
|
+
streaming: boolean;
|
|
105
|
+
reason: string;
|
|
106
|
+
}>;
|
|
107
|
+
/**
|
|
108
|
+
* Add streaming decision headers to response (for debugging)
|
|
109
|
+
*/
|
|
110
|
+
declare function addStreamingHeaders(response: Response, decision: {
|
|
111
|
+
streaming: boolean;
|
|
112
|
+
reason: string;
|
|
113
|
+
}): Response;
|
|
114
|
+
/**
|
|
115
|
+
* Create a streaming-aware Response with appropriate headers
|
|
116
|
+
*/
|
|
117
|
+
declare function createStreamingResponse(stream: ReadableStream<Uint8Array>, options?: {
|
|
118
|
+
status?: number;
|
|
119
|
+
headers?: Record<string, string>;
|
|
120
|
+
isStreaming?: boolean;
|
|
121
|
+
}): Response;
|
|
122
|
+
/**
|
|
123
|
+
* Create a static HTML Response
|
|
124
|
+
*/
|
|
125
|
+
declare function createStaticResponse(html: string, options?: {
|
|
126
|
+
status?: number;
|
|
127
|
+
headers?: Record<string, string>;
|
|
128
|
+
}): Response;
|
|
129
|
+
|
|
130
|
+
export { type BuiltInCondition, DEFAULT_BOT_PATTERNS, type StreamIfConfig, type StreamingCondition, type StreamingDecision, addStreamingHeaders, createConditionalStreamer, createStaticResponse, createStreamingResponse, isBot, isSlowConnection, prefersNoStream, streamIf, supportsStreaming };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { DEFAULT_BOT_PATTERNS, addStreamingHeaders, createConditionalStreamer, createStaticResponse, createStreamingResponse, isBot, isSlowConnection, prefersNoStream, streamIf, supportsStreaming } from '../chunk-XOIYNY4I.js';
|
|
2
|
+
//# sourceMappingURL=conditional.js.map
|
|
3
|
+
//# sourceMappingURL=conditional.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"conditional.js"}
|
|
@@ -61,6 +61,14 @@ interface SuspenseBoundaryConfig {
|
|
|
61
61
|
fallback: string;
|
|
62
62
|
/** Content resolver promise */
|
|
63
63
|
contentPromise: Promise<string>;
|
|
64
|
+
/**
|
|
65
|
+
* IDs of boundaries that must resolve before this one.
|
|
66
|
+
* Enables dependency-aware streaming for complex data relationships.
|
|
67
|
+
* @example ['user'] - Wait for 'user' boundary before starting
|
|
68
|
+
*/
|
|
69
|
+
dependsOn?: string[];
|
|
70
|
+
/** Custom metadata for observability */
|
|
71
|
+
meta?: Record<string, unknown>;
|
|
64
72
|
}
|
|
65
73
|
/**
|
|
66
74
|
* Create a streaming SSR response using Web Streams API.
|
package/dist/streaming/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { createLazyContent, createStreamingResponse, createStreamingSSR, renderWithStreaming, streamParallel, streamSequential } from '../chunk-
|
|
1
|
+
export { createLazyContent, createStreamingResponse, createStreamingSSR, renderWithStreaming, streamParallel, streamSequential } from '../chunk-6WSPUG5L.js';
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|