@reckona/mreact-server 0.0.159 → 0.0.161
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/boundary.d.ts +16 -0
- package/dist/boundary.d.ts.map +1 -1
- package/dist/boundary.js +8 -0
- package/dist/boundary.js.map +1 -1
- package/dist/buffer-sink.d.ts +8 -9
- package/dist/buffer-sink.d.ts.map +1 -1
- package/dist/buffer-sink.js +5 -0
- package/dist/buffer-sink.js.map +1 -1
- package/dist/flight.d.ts +51 -0
- package/dist/flight.d.ts.map +1 -1
- package/dist/flight.js +16 -0
- package/dist/flight.js.map +1 -1
- package/dist/html-helpers.d.ts +12 -0
- package/dist/html-helpers.d.ts.map +1 -1
- package/dist/html-helpers.js +8 -0
- package/dist/html-helpers.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/reorder.d.ts +1 -0
- package/dist/reorder.d.ts.map +1 -1
- package/dist/reorder.js +1 -0
- package/dist/reorder.js.map +1 -1
- package/dist/sink.d.ts +6 -0
- package/dist/sink.d.ts.map +1 -1
- package/dist/sink.js +2 -0
- package/dist/sink.js.map +1 -1
- package/dist/stream.d.ts +2 -0
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +1 -0
- package/dist/stream.js.map +1 -1
- package/package.json +3 -3
- package/src/boundary.ts +16 -0
- package/src/buffer-sink.ts +8 -9
- package/src/flight.ts +51 -0
- package/src/html-helpers.ts +12 -0
- package/src/index.ts +5 -0
- package/src/reorder.ts +1 -0
- package/src/sink.ts +6 -0
- package/src/stream.ts +2 -0
package/src/buffer-sink.ts
CHANGED
|
@@ -30,6 +30,7 @@ interface BufferConstructor {
|
|
|
30
30
|
|
|
31
31
|
declare const Buffer: BufferConstructor;
|
|
32
32
|
|
|
33
|
+
/** Accumulates server-rendered chunks into a Node Buffer. */
|
|
33
34
|
export interface BufferSink {
|
|
34
35
|
append(chunk: string | NodeBuffer): void;
|
|
35
36
|
toBuffer(): NodeBuffer;
|
|
@@ -37,6 +38,7 @@ export interface BufferSink {
|
|
|
37
38
|
size(): number;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
/** Options controlling allocation and growth for a Node buffer sink. */
|
|
40
42
|
export interface BufferSinkOptions {
|
|
41
43
|
/**
|
|
42
44
|
* Initial backing buffer size (UTF-8 bytes). The buffer grows
|
|
@@ -50,15 +52,6 @@ export interface BufferSinkOptions {
|
|
|
50
52
|
growthFactor?: number;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
/**
|
|
54
|
-
* Creates a Node-only buffer sink with a single pre-allocated growing
|
|
55
|
-
* backing `Buffer`. UTF-8 encoding happens in-place at the current write
|
|
56
|
-
* offset, avoiding per-chunk Buffer allocation and a final concat.
|
|
57
|
-
*
|
|
58
|
-
* Compared to `Buffer.concat`-style implementations, this trades a small
|
|
59
|
-
* amount of headroom memory for ~5-10x throughput on small chunks
|
|
60
|
-
* (see docs/benchmarks/2026-05-12-server-sink-strategy.md).
|
|
61
|
-
*/
|
|
62
55
|
/**
|
|
63
56
|
* A streaming-flavored buffer sink used by
|
|
64
57
|
* `renderToReadableStream`. Coalesces successive `append(chunk)` calls
|
|
@@ -87,6 +80,7 @@ export interface StreamingBufferSink {
|
|
|
87
80
|
size(): number;
|
|
88
81
|
}
|
|
89
82
|
|
|
83
|
+
/** Options controlling automatic flush behavior for a streaming buffer sink. */
|
|
90
84
|
export interface StreamingBufferSinkOptions {
|
|
91
85
|
/** UTF-8 byte threshold that triggers an automatic flush from inside
|
|
92
86
|
* `append`. Default 8 KiB (one common TCP segment payload). */
|
|
@@ -98,6 +92,7 @@ export interface StreamingBufferSinkOptions {
|
|
|
98
92
|
onFlush(buffer: Uint8Array): void;
|
|
99
93
|
}
|
|
100
94
|
|
|
95
|
+
/** Creates a streaming sink that coalesces appended text into byte buffers. */
|
|
101
96
|
export function createStreamingBufferSink(
|
|
102
97
|
options: StreamingBufferSinkOptions,
|
|
103
98
|
): StreamingBufferSink {
|
|
@@ -186,6 +181,10 @@ function hasNodeBuffer(): boolean {
|
|
|
186
181
|
return typeof Buffer !== "undefined" && typeof Buffer.allocUnsafe === "function";
|
|
187
182
|
}
|
|
188
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Creates a Node-only buffer sink with a single pre-allocated growing
|
|
186
|
+
* backing `Buffer`.
|
|
187
|
+
*/
|
|
189
188
|
export function createBufferSink(options: BufferSinkOptions = {}): BufferSink {
|
|
190
189
|
const initialSize = options.initialSize ?? 8192;
|
|
191
190
|
const growthFactor = options.growthFactor ?? 2;
|
package/src/flight.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { getNativeFlight } from "./native-flight.js";
|
|
2
2
|
|
|
3
|
+
/** Symbol tag used to identify client references in serialized Flight values. */
|
|
3
4
|
export const CLIENT_REFERENCE_TYPE = Symbol.for("modular.react.client_reference");
|
|
5
|
+
/** Symbol tag used to identify server references in serialized Flight values. */
|
|
4
6
|
export const SERVER_REFERENCE_TYPE = Symbol.for("modular.react.server_reference");
|
|
5
7
|
const CACHE_SCOPE_SYMBOL = Symbol.for("modular.react.cache_scope");
|
|
6
8
|
|
|
7
9
|
const REACT_COMPAT_ELEMENT_TYPE = Symbol.for("react.transitional.element");
|
|
8
10
|
const REACT_COMPAT_FRAGMENT_TYPE = Symbol.for("react.fragment");
|
|
9
11
|
|
|
12
|
+
/** Registered client reference included in a Flight response. */
|
|
10
13
|
export interface FlightClientReference {
|
|
11
14
|
id: number;
|
|
12
15
|
moduleId: string;
|
|
@@ -14,37 +17,46 @@ export interface FlightClientReference {
|
|
|
14
17
|
chunks?: string[];
|
|
15
18
|
}
|
|
16
19
|
|
|
20
|
+
/** Input used to register a client reference before assigning a Flight id. */
|
|
17
21
|
export interface FlightClientReferenceInput {
|
|
18
22
|
name: string;
|
|
19
23
|
moduleId: string;
|
|
20
24
|
exportName: string;
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
/** Client manifest entry with resolved module chunks. */
|
|
23
28
|
export interface FlightClientManifestEntry extends FlightClientReferenceInput {
|
|
24
29
|
chunks: string[];
|
|
25
30
|
}
|
|
26
31
|
|
|
32
|
+
/** Function that can be invoked through a server action request. */
|
|
27
33
|
export type ServerAction = (...args: unknown[]) => unknown | Promise<unknown>;
|
|
28
34
|
|
|
35
|
+
/** Validation result returned by server action guards. */
|
|
29
36
|
export type ServerActionValidationResult = boolean | string;
|
|
30
37
|
|
|
38
|
+
/** Server action entry with optional argument validation. */
|
|
31
39
|
export interface ServerActionDescriptor {
|
|
32
40
|
action: ServerAction;
|
|
33
41
|
validateArgs?: (args: unknown[]) => ServerActionValidationResult;
|
|
34
42
|
}
|
|
35
43
|
|
|
44
|
+
/** Registry mapping server action keys to handlers. */
|
|
36
45
|
export type ServerActionRegistry = Record<string, ServerAction | ServerActionDescriptor>;
|
|
37
46
|
|
|
47
|
+
/** Store used to reject replayed server action nonces. */
|
|
38
48
|
export interface ServerActionReplayStore {
|
|
39
49
|
has(value: string): boolean;
|
|
40
50
|
add(value: string): void;
|
|
41
51
|
}
|
|
42
52
|
|
|
53
|
+
/** Module export reference requested by a server action request. */
|
|
43
54
|
export interface ServerActionRequestReference {
|
|
44
55
|
moduleId: string;
|
|
45
56
|
exportName: string;
|
|
46
57
|
}
|
|
47
58
|
|
|
59
|
+
/** Security and validation options for createServerActionHandler. */
|
|
48
60
|
export interface ServerActionHandlerOptions {
|
|
49
61
|
// Issue 076: secure defaults. When undefined, the handler enforces the
|
|
50
62
|
// same-origin policy by comparing `Origin` to the request URL. Pass an
|
|
@@ -77,11 +89,13 @@ export interface ServerActionHandlerOptions {
|
|
|
77
89
|
|
|
78
90
|
const DEFAULT_MAX_BODY_BYTES = 1024 * 1024;
|
|
79
91
|
|
|
92
|
+
/** Options for embedding a serialized Flight response in a script tag. */
|
|
80
93
|
export interface FlightScriptOptions {
|
|
81
94
|
id?: string;
|
|
82
95
|
nonce?: string;
|
|
83
96
|
}
|
|
84
97
|
|
|
98
|
+
/** Registered server reference included in a Flight response. */
|
|
85
99
|
export interface FlightServerReference {
|
|
86
100
|
id: number;
|
|
87
101
|
moduleId: string;
|
|
@@ -89,6 +103,7 @@ export interface FlightServerReference {
|
|
|
89
103
|
bound?: FlightModel[];
|
|
90
104
|
}
|
|
91
105
|
|
|
106
|
+
/** Runtime marker object representing a client module export. */
|
|
92
107
|
export interface ClientReference {
|
|
93
108
|
$$typeof: typeof CLIENT_REFERENCE_TYPE;
|
|
94
109
|
moduleId: string;
|
|
@@ -96,6 +111,7 @@ export interface ClientReference {
|
|
|
96
111
|
chunks?: string[];
|
|
97
112
|
}
|
|
98
113
|
|
|
114
|
+
/** Runtime marker object representing a server module export. */
|
|
99
115
|
export interface ServerReference {
|
|
100
116
|
$$typeof: typeof SERVER_REFERENCE_TYPE;
|
|
101
117
|
moduleId: string;
|
|
@@ -103,6 +119,7 @@ export interface ServerReference {
|
|
|
103
119
|
bound?: unknown[];
|
|
104
120
|
}
|
|
105
121
|
|
|
122
|
+
/** Serializable Flight payload with root model and module references. */
|
|
106
123
|
export interface FlightResponse {
|
|
107
124
|
version: 1;
|
|
108
125
|
root: FlightModel;
|
|
@@ -110,6 +127,7 @@ export interface FlightResponse {
|
|
|
110
127
|
serverReferences: FlightServerReference[];
|
|
111
128
|
}
|
|
112
129
|
|
|
130
|
+
/** Recursive value model supported by the mreact Flight serializer. */
|
|
113
131
|
export type FlightModel =
|
|
114
132
|
| null
|
|
115
133
|
| string
|
|
@@ -135,11 +153,13 @@ export type FlightModel =
|
|
|
135
153
|
| FlightDataViewModel
|
|
136
154
|
| { kind: "undefined" };
|
|
137
155
|
|
|
156
|
+
/** Plain object shape inside a Flight model. */
|
|
138
157
|
export interface FlightObjectModel {
|
|
139
158
|
kind?: never;
|
|
140
159
|
[key: string]: FlightModel | undefined;
|
|
141
160
|
}
|
|
142
161
|
|
|
162
|
+
/** Serialized React-compatible element inside a Flight model. */
|
|
143
163
|
export interface FlightElementModel {
|
|
144
164
|
kind: "element";
|
|
145
165
|
type: string | FlightClientReferenceModel | { kind: "fragment" };
|
|
@@ -147,56 +167,67 @@ export interface FlightElementModel {
|
|
|
147
167
|
props: Record<string, FlightModel>;
|
|
148
168
|
}
|
|
149
169
|
|
|
170
|
+
/** Reference to a client module export inside a Flight model. */
|
|
150
171
|
export interface FlightClientReferenceModel {
|
|
151
172
|
kind: "client-reference";
|
|
152
173
|
id: number;
|
|
153
174
|
}
|
|
154
175
|
|
|
176
|
+
/** Reference to a server module export inside a Flight model. */
|
|
155
177
|
export interface FlightServerReferenceModel {
|
|
156
178
|
kind: "server-reference";
|
|
157
179
|
id: number;
|
|
158
180
|
}
|
|
159
181
|
|
|
182
|
+
/** Serialized Date value inside a Flight model. */
|
|
160
183
|
export interface FlightDateModel {
|
|
161
184
|
kind: "date";
|
|
162
185
|
value: string;
|
|
163
186
|
}
|
|
164
187
|
|
|
188
|
+
/** Serialized bigint value inside a Flight model. */
|
|
165
189
|
export interface FlightBigIntModel {
|
|
166
190
|
kind: "bigint";
|
|
167
191
|
value: string;
|
|
168
192
|
}
|
|
169
193
|
|
|
194
|
+
/** Serialized non-finite or negative-zero number inside a Flight model. */
|
|
170
195
|
export interface FlightNumberModel {
|
|
171
196
|
kind: "number";
|
|
172
197
|
value: "Infinity" | "-Infinity" | "NaN" | "-0";
|
|
173
198
|
}
|
|
174
199
|
|
|
200
|
+
/** Serialized global symbol reference inside a Flight model. */
|
|
175
201
|
export interface FlightSymbolModel {
|
|
176
202
|
kind: "symbol";
|
|
177
203
|
name: string;
|
|
178
204
|
}
|
|
179
205
|
|
|
206
|
+
/** Serialized Map value inside a Flight model. */
|
|
180
207
|
export interface FlightMapModel {
|
|
181
208
|
kind: "map";
|
|
182
209
|
entries: [FlightModel, FlightModel][];
|
|
183
210
|
}
|
|
184
211
|
|
|
212
|
+
/** Serialized Set value inside a Flight model. */
|
|
185
213
|
export interface FlightSetModel {
|
|
186
214
|
kind: "set";
|
|
187
215
|
values: FlightModel[];
|
|
188
216
|
}
|
|
189
217
|
|
|
218
|
+
/** Serialized FormData value inside a Flight model. */
|
|
190
219
|
export interface FlightFormDataModel {
|
|
191
220
|
kind: "form-data";
|
|
192
221
|
entries: [string, FlightModel][];
|
|
193
222
|
}
|
|
194
223
|
|
|
224
|
+
/** Serialized iterable value inside a Flight model. */
|
|
195
225
|
export interface FlightIterableModel {
|
|
196
226
|
kind: "iterable";
|
|
197
227
|
values: FlightModel[];
|
|
198
228
|
}
|
|
199
229
|
|
|
230
|
+
/** Serialized Error value inside a Flight model. */
|
|
200
231
|
export interface FlightErrorModel {
|
|
201
232
|
kind: "error";
|
|
202
233
|
name: string;
|
|
@@ -204,27 +235,32 @@ export interface FlightErrorModel {
|
|
|
204
235
|
digest?: string;
|
|
205
236
|
}
|
|
206
237
|
|
|
238
|
+
/** Reference to an outlined promise chunk inside a Flight model. */
|
|
207
239
|
export interface FlightPromiseModel {
|
|
208
240
|
kind: "promise";
|
|
209
241
|
id: number;
|
|
210
242
|
}
|
|
211
243
|
|
|
244
|
+
/** Serialized ArrayBuffer value inside a Flight model. */
|
|
212
245
|
export interface FlightArrayBufferModel {
|
|
213
246
|
kind: "array-buffer";
|
|
214
247
|
bytes: number[];
|
|
215
248
|
}
|
|
216
249
|
|
|
250
|
+
/** Serialized typed array value inside a Flight model. */
|
|
217
251
|
export interface FlightTypedArrayModel {
|
|
218
252
|
kind: "typed-array";
|
|
219
253
|
arrayType: FlightTypedArrayName;
|
|
220
254
|
bytes: number[];
|
|
221
255
|
}
|
|
222
256
|
|
|
257
|
+
/** Serialized DataView value inside a Flight model. */
|
|
223
258
|
export interface FlightDataViewModel {
|
|
224
259
|
kind: "data-view";
|
|
225
260
|
bytes: number[];
|
|
226
261
|
}
|
|
227
262
|
|
|
263
|
+
/** Typed array constructor names supported by the Flight serializer. */
|
|
228
264
|
export type FlightTypedArrayName =
|
|
229
265
|
| "Int8Array"
|
|
230
266
|
| "Uint8Array"
|
|
@@ -262,12 +298,14 @@ const reactFlightModelTokens = [
|
|
|
262
298
|
"$undefined",
|
|
263
299
|
] as const;
|
|
264
300
|
|
|
301
|
+
/** Lists the React Flight row tags and model tokens covered by the serializer. */
|
|
265
302
|
export interface ReactFlightProtocolCoverage {
|
|
266
303
|
binaryRowTags: string[];
|
|
267
304
|
modelTokens: string[];
|
|
268
305
|
rowTags: string[];
|
|
269
306
|
}
|
|
270
307
|
|
|
308
|
+
/** Returns the React Flight protocol tags and tokens supported by this package. */
|
|
271
309
|
export function getReactFlightProtocolCoverage(): ReactFlightProtocolCoverage {
|
|
272
310
|
return {
|
|
273
311
|
binaryRowTags: [...reactFlightBinaryRowTags],
|
|
@@ -296,6 +334,7 @@ interface ServerCacheScope {
|
|
|
296
334
|
ownerStack: string[];
|
|
297
335
|
}
|
|
298
336
|
|
|
337
|
+
/** Creates a runtime client reference marker for a module export. */
|
|
299
338
|
export function createClientReference(
|
|
300
339
|
moduleId: string,
|
|
301
340
|
exportName = "default",
|
|
@@ -309,6 +348,7 @@ export function createClientReference(
|
|
|
309
348
|
};
|
|
310
349
|
}
|
|
311
350
|
|
|
351
|
+
/** Creates a runtime server reference marker for a module export. */
|
|
312
352
|
export function createServerReference(
|
|
313
353
|
moduleId: string,
|
|
314
354
|
exportName = "default",
|
|
@@ -322,6 +362,7 @@ export function createServerReference(
|
|
|
322
362
|
};
|
|
323
363
|
}
|
|
324
364
|
|
|
365
|
+
/** Returns true when a value is a runtime client reference marker. */
|
|
325
366
|
export function isClientReference(value: unknown): value is ClientReference {
|
|
326
367
|
return (
|
|
327
368
|
typeof value === "object" &&
|
|
@@ -330,6 +371,7 @@ export function isClientReference(value: unknown): value is ClientReference {
|
|
|
330
371
|
);
|
|
331
372
|
}
|
|
332
373
|
|
|
374
|
+
/** Returns true when a value is a runtime server reference marker. */
|
|
333
375
|
export function isServerReference(value: unknown): value is ServerReference {
|
|
334
376
|
return (
|
|
335
377
|
typeof value === "object" &&
|
|
@@ -338,6 +380,7 @@ export function isServerReference(value: unknown): value is ServerReference {
|
|
|
338
380
|
);
|
|
339
381
|
}
|
|
340
382
|
|
|
383
|
+
/** Serializes a renderable value into a structured Flight response. */
|
|
341
384
|
export async function renderToFlightResponse<P extends Record<string, unknown>>(
|
|
342
385
|
renderable: ((props: P) => unknown) | unknown,
|
|
343
386
|
props = {} as P,
|
|
@@ -363,10 +406,12 @@ export async function renderToFlightResponse<P extends Record<string, unknown>>(
|
|
|
363
406
|
});
|
|
364
407
|
}
|
|
365
408
|
|
|
409
|
+
/** Serializes a Flight response to JSON text. */
|
|
366
410
|
export function stringifyFlightResponse(response: FlightResponse): string {
|
|
367
411
|
return JSON.stringify(response);
|
|
368
412
|
}
|
|
369
413
|
|
|
414
|
+
/** Renders a Flight response as an HTML script tag. */
|
|
370
415
|
export function renderFlightResponseScript(
|
|
371
416
|
response: FlightResponse,
|
|
372
417
|
options: FlightScriptOptions = {},
|
|
@@ -378,6 +423,7 @@ export function renderFlightResponseScript(
|
|
|
378
423
|
return `<script type="application/json" data-mreact-flight${idAttribute}${nonceAttribute}>${serializeJsonForHtml(response)}</script>`;
|
|
379
424
|
}
|
|
380
425
|
|
|
426
|
+
/** Creates a request handler that validates and invokes registered server actions. */
|
|
381
427
|
export function createServerActionHandler(
|
|
382
428
|
actions: ServerActionRegistry,
|
|
383
429
|
options: ServerActionHandlerOptions = {},
|
|
@@ -498,6 +544,7 @@ export function createServerActionHandler(
|
|
|
498
544
|
};
|
|
499
545
|
}
|
|
500
546
|
|
|
547
|
+
/** Encodes a structured Flight response into React Flight row text. */
|
|
501
548
|
export function toReactFlightRows(response: FlightResponse): string {
|
|
502
549
|
// Issue 081 note: a native encoder exists in
|
|
503
550
|
// `packages/router-native/src/flight.rs::encode_flight_response`
|
|
@@ -555,6 +602,7 @@ export function toReactFlightRows(response: FlightResponse): string {
|
|
|
555
602
|
return rows.join("\n");
|
|
556
603
|
}
|
|
557
604
|
|
|
605
|
+
/** Decodes React Flight row text into a structured Flight response. */
|
|
558
606
|
export function fromReactFlightRows(rows: string): FlightResponse {
|
|
559
607
|
// Issue 081 note: a native decoder exists in
|
|
560
608
|
// `packages/router-native/src/flight.rs::decode_flight_rows`
|
|
@@ -644,6 +692,7 @@ export function fromReactFlightRows(rows: string): FlightResponse {
|
|
|
644
692
|
};
|
|
645
693
|
}
|
|
646
694
|
|
|
695
|
+
/** Merges additional React Flight row text into an existing Flight response. */
|
|
647
696
|
export function mergeReactFlightRows(
|
|
648
697
|
response: FlightResponse,
|
|
649
698
|
rows: string,
|
|
@@ -700,6 +749,7 @@ export function mergeReactFlightRows(
|
|
|
700
749
|
};
|
|
701
750
|
}
|
|
702
751
|
|
|
752
|
+
/** Builds a Flight client manifest from client references and chunk resolution. */
|
|
703
753
|
export function createFlightClientManifest(
|
|
704
754
|
references: readonly FlightClientReferenceInput[],
|
|
705
755
|
resolveChunks: (reference: FlightClientReferenceInput) => string[],
|
|
@@ -710,6 +760,7 @@ export function createFlightClientManifest(
|
|
|
710
760
|
}));
|
|
711
761
|
}
|
|
712
762
|
|
|
763
|
+
/** Renders modulepreload links for client chunks referenced by a Flight response. */
|
|
713
764
|
export function renderFlightPreloadLinks(
|
|
714
765
|
response: FlightResponse,
|
|
715
766
|
options: { nonce?: string } = {},
|
package/src/html-helpers.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import { createStringSink, hasDeferredTasks, type StreamRender } from "./sink.js";
|
|
29
29
|
import { renderToReadableStream } from "./stream.js";
|
|
30
30
|
|
|
31
|
+
/** External script asset attributes emitted by renderScriptAsset. */
|
|
31
32
|
export interface ScriptAssetOptions {
|
|
32
33
|
src: string;
|
|
33
34
|
nonce?: string;
|
|
@@ -35,27 +36,32 @@ export interface ScriptAssetOptions {
|
|
|
35
36
|
crossOrigin?: "anonymous" | "use-credentials";
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/** Event handler entry used by the hydration manifest. */
|
|
38
40
|
export interface EventHydrationEntry {
|
|
39
41
|
id: string;
|
|
40
42
|
event: string;
|
|
41
43
|
handler: string;
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
/** Manifest of event handlers that can be hydrated on the client. */
|
|
44
47
|
export interface EventHydrationManifest {
|
|
45
48
|
version: 1;
|
|
46
49
|
events: EventHydrationEntry[];
|
|
47
50
|
}
|
|
48
51
|
|
|
52
|
+
/** Response options used when wrapping rendered HTML in a Response. */
|
|
49
53
|
export interface HtmlResponseOptions {
|
|
50
54
|
headers?: HeadersInit;
|
|
51
55
|
status?: number;
|
|
52
56
|
statusText?: string;
|
|
53
57
|
}
|
|
54
58
|
|
|
59
|
+
/** Serializes state for safe embedding in an HTML script tag. */
|
|
55
60
|
export function serializeSsrState(value: unknown): string {
|
|
56
61
|
return serializeScriptJson(value);
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
/** Appends serialized SSR state as a JSON script tag. */
|
|
59
65
|
export function renderSsrState(
|
|
60
66
|
sink: HtmlSink,
|
|
61
67
|
value: unknown,
|
|
@@ -66,6 +72,7 @@ export function renderSsrState(
|
|
|
66
72
|
);
|
|
67
73
|
}
|
|
68
74
|
|
|
75
|
+
/** Creates a defensive copy of an event hydration manifest. */
|
|
69
76
|
export function createEventHydrationManifest(
|
|
70
77
|
events: readonly EventHydrationEntry[],
|
|
71
78
|
): EventHydrationManifest {
|
|
@@ -75,6 +82,7 @@ export function createEventHydrationManifest(
|
|
|
75
82
|
};
|
|
76
83
|
}
|
|
77
84
|
|
|
85
|
+
/** Appends an event hydration manifest as a JSON script tag. */
|
|
78
86
|
export function renderEventHydrationManifest(
|
|
79
87
|
sink: HtmlSink,
|
|
80
88
|
manifest: EventHydrationManifest,
|
|
@@ -85,6 +93,7 @@ export function renderEventHydrationManifest(
|
|
|
85
93
|
);
|
|
86
94
|
}
|
|
87
95
|
|
|
96
|
+
/** Appends an external script tag with optional nonce and integrity attributes. */
|
|
88
97
|
export function renderScriptAsset(sink: HtmlSink, options: ScriptAssetOptions): void {
|
|
89
98
|
const integrityAttribute =
|
|
90
99
|
options.integrity === undefined ? "" : ` integrity="${escapeAttribute(options.integrity)}"`;
|
|
@@ -98,6 +107,7 @@ export function renderScriptAsset(sink: HtmlSink, options: ScriptAssetOptions):
|
|
|
98
107
|
);
|
|
99
108
|
}
|
|
100
109
|
|
|
110
|
+
/** Creates an HTML Response from a React-compatible node. */
|
|
101
111
|
export function html(node: unknown, options: HtmlResponseOptions = {}): Response {
|
|
102
112
|
const headers = new Headers(options.headers);
|
|
103
113
|
const responseOptions: ResponseInit = { headers };
|
|
@@ -123,6 +133,7 @@ export function html(node: unknown, options: HtmlResponseOptions = {}): Response
|
|
|
123
133
|
);
|
|
124
134
|
}
|
|
125
135
|
|
|
136
|
+
/** Renders sink output to a string after awaiting deferred work. */
|
|
126
137
|
export async function renderToString(render: StreamRender): Promise<string> {
|
|
127
138
|
const sink = createStringSink();
|
|
128
139
|
|
|
@@ -132,6 +143,7 @@ export async function renderToString(render: StreamRender): Promise<string> {
|
|
|
132
143
|
return sink.toString();
|
|
133
144
|
}
|
|
134
145
|
|
|
146
|
+
/** Renders a React-compatible node to an HTML string. */
|
|
135
147
|
export async function renderReactNodeToString(node: unknown): Promise<string> {
|
|
136
148
|
const sink = createStringSink();
|
|
137
149
|
const state: HtmlRenderState = { suspenseId: 0 };
|
package/src/index.ts
CHANGED
|
@@ -4,8 +4,11 @@ import {
|
|
|
4
4
|
type ReactCompatNode,
|
|
5
5
|
} from "@reckona/mreact-compat";
|
|
6
6
|
|
|
7
|
+
/** Fragment marker used to group children without emitting an extra element. */
|
|
7
8
|
export { Fragment } from "@reckona/mreact-compat";
|
|
9
|
+
/** Any value accepted by the React-compatible renderer. */
|
|
8
10
|
export type { ReactCompatNode } from "@reckona/mreact-compat";
|
|
11
|
+
/** Receives HTML chunks and deferred work while server rendering. */
|
|
9
12
|
export type { HtmlSink } from "@reckona/mreact-shared/compiler-contract";
|
|
10
13
|
|
|
11
14
|
export {
|
|
@@ -109,11 +112,13 @@ export type {
|
|
|
109
112
|
ScriptAssetOptions,
|
|
110
113
|
} from "./html-helpers.js";
|
|
111
114
|
|
|
115
|
+
/** Props accepted by the server Suspense compatibility component. */
|
|
112
116
|
export interface SuspenseProps extends Record<string, unknown> {
|
|
113
117
|
fallback?: unknown;
|
|
114
118
|
children?: unknown;
|
|
115
119
|
}
|
|
116
120
|
|
|
121
|
+
/** Creates a React-compatible Suspense boundary for server rendering. */
|
|
117
122
|
export function Suspense(props: SuspenseProps): never {
|
|
118
123
|
const config: SuspenseProps = {};
|
|
119
124
|
|
package/src/reorder.ts
CHANGED
package/src/sink.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import type { HtmlSink } from "@reckona/mreact-shared/compiler-contract";
|
|
2
2
|
|
|
3
|
+
/** HTML sink that buffers output as a string and can await deferred tasks. */
|
|
3
4
|
export interface StringHtmlSink extends HtmlSink {
|
|
4
5
|
bufferStrategy(): StringSinkBufferStrategy;
|
|
5
6
|
drain(): Promise<void>;
|
|
6
7
|
toString(): string;
|
|
7
8
|
}
|
|
8
9
|
|
|
10
|
+
/** String buffering strategy used by createStringSink. */
|
|
9
11
|
export type StringSinkBufferStrategy = "concat" | "array-join";
|
|
10
12
|
|
|
13
|
+
/** Options controlling how a string sink buffers appended chunks. */
|
|
11
14
|
export interface StringSinkOptions {
|
|
12
15
|
strategy?: StringSinkBufferStrategy | "auto";
|
|
13
16
|
arrayJoinThreshold?: number;
|
|
14
17
|
}
|
|
15
18
|
|
|
19
|
+
/** Callback that writes server-rendered HTML into a sink. */
|
|
16
20
|
export type StreamRender = (sink: HtmlSink) => void | PromiseLike<void>;
|
|
17
21
|
|
|
18
22
|
const stringSinkDeferredTasks = new WeakMap<HtmlSink, PromiseLike<void>[]>();
|
|
19
23
|
|
|
24
|
+
/** Creates an HTML sink that stores appended chunks in memory as a string. */
|
|
20
25
|
export function createStringSink(options: StringSinkOptions = {}): StringHtmlSink {
|
|
21
26
|
// Default to "concat" - V8 rope flattening yields 2-6x throughput over
|
|
22
27
|
// `Array#join("")` across all measured fixture sizes (see
|
|
@@ -81,6 +86,7 @@ export function createStringSink(options: StringSinkOptions = {}): StringHtmlSin
|
|
|
81
86
|
return sink;
|
|
82
87
|
}
|
|
83
88
|
|
|
89
|
+
/** Returns true when a sink created by createStringSink has deferred tasks. */
|
|
84
90
|
export function hasDeferredTasks(sink: HtmlSink): boolean {
|
|
85
91
|
return (stringSinkDeferredTasks.get(sink)?.length ?? 0) > 0;
|
|
86
92
|
}
|
package/src/stream.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { createStreamingBufferSink } from "./buffer-sink.js";
|
|
2
2
|
import type { StreamRender } from "./sink.js";
|
|
3
3
|
|
|
4
|
+
/** Options controlling server render stream error logging behavior. */
|
|
4
5
|
export interface RenderToReadableStreamOptions {
|
|
5
6
|
logAbortedDeferredErrors?: boolean;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
const streamQueuedChunkSoftLimitBytes = 1024 * 1024;
|
|
9
10
|
|
|
11
|
+
/** Renders HTML sink output to a WHATWG readable byte stream. */
|
|
10
12
|
export function renderToReadableStream(
|
|
11
13
|
render: StreamRender,
|
|
12
14
|
options: RenderToReadableStreamOptions = {},
|