@reckona/mreact-compat 0.0.66 → 0.0.67
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/package.json +4 -3
- package/src/class-component.ts +386 -0
- package/src/context.ts +140 -0
- package/src/devtools.ts +1275 -0
- package/src/dom-children.ts +34 -0
- package/src/dom-props.ts +408 -0
- package/src/element.ts +317 -0
- package/src/event-listeners.ts +27 -0
- package/src/event-priority.ts +1 -0
- package/src/event-replay.ts +154 -0
- package/src/event-types.ts +18 -0
- package/src/events.ts +384 -0
- package/src/fiber-child.ts +364 -0
- package/src/fiber-commit.ts +83 -0
- package/src/fiber-flags.ts +21 -0
- package/src/fiber-host.ts +1564 -0
- package/src/fiber-lanes.ts +99 -0
- package/src/fiber-reconciler.ts +639 -0
- package/src/fiber-scheduler.ts +435 -0
- package/src/fiber-work-loop.ts +224 -0
- package/src/fiber.ts +148 -0
- package/src/flight-decoder.ts +205 -0
- package/src/flight-element-builder.ts +110 -0
- package/src/flight-parser.ts +698 -0
- package/src/flight-protocol.ts +71 -0
- package/src/flight-types.ts +148 -0
- package/src/flight.ts +162 -0
- package/src/hooks.ts +1940 -0
- package/src/hydration.ts +314 -0
- package/src/index.ts +95 -0
- package/src/internal.ts +7 -0
- package/src/jsx-dev-runtime.ts +40 -0
- package/src/jsx-runtime.ts +119 -0
- package/src/prop-comparison.ts +50 -0
- package/src/reconcile-types.ts +26 -0
- package/src/reconciler.ts +692 -0
- package/src/render.ts +29 -0
- package/src/root.ts +493 -0
- package/src/scheduler.ts +157 -0
- package/src/suspense.ts +317 -0
- package/src/thenable.ts +7 -0
- package/src/url-safety.ts +7 -0
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
import type { ReactFlightBinaryRowTag } from "./flight-protocol.js";
|
|
2
|
+
import type {
|
|
3
|
+
FlightArrayBufferModel,
|
|
4
|
+
FlightClientReference,
|
|
5
|
+
FlightDataViewModel,
|
|
6
|
+
FlightElementModel,
|
|
7
|
+
FlightErrorModel,
|
|
8
|
+
FlightModel,
|
|
9
|
+
FlightResponse,
|
|
10
|
+
FlightServerReference,
|
|
11
|
+
FlightTypedArrayModel,
|
|
12
|
+
FlightTypedArrayName,
|
|
13
|
+
} from "./flight-types.js";
|
|
14
|
+
|
|
15
|
+
interface ReactFlightRow {
|
|
16
|
+
id: number;
|
|
17
|
+
tag?: string;
|
|
18
|
+
payload: string;
|
|
19
|
+
payloadBytes?: Uint8Array;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function parseReactFlightPayload(payload: string | ArrayBuffer | Uint8Array): FlightResponse {
|
|
23
|
+
if (typeof payload !== "string") {
|
|
24
|
+
return parseReactFlightBinaryRows(payload);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const trimmed = payload.trim();
|
|
28
|
+
|
|
29
|
+
if (trimmed.startsWith("{")) {
|
|
30
|
+
return JSON.parse(trimmed) as FlightResponse;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return parseReactFlightRows(trimmed);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function parseReactFlightRows(rows: string): FlightResponse {
|
|
37
|
+
const lines = rows.split(/\r?\n/).filter(Boolean);
|
|
38
|
+
const metadataLine = lines.find((line) => line.startsWith("M0:"));
|
|
39
|
+
const rootLine = lines.find((line) => line.startsWith("J0:"));
|
|
40
|
+
|
|
41
|
+
if (metadataLine !== undefined && rootLine !== undefined) {
|
|
42
|
+
const metadata = JSON.parse(metadataLine.slice(3)) as Omit<FlightResponse, "root">;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
version: metadata.version,
|
|
46
|
+
clientReferences: metadata.clientReferences,
|
|
47
|
+
serverReferences: metadata.serverReferences,
|
|
48
|
+
root: JSON.parse(rootLine.slice(3)) as FlightModel,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return parseReactFlightRowObjects(lines.map((line) => parseReactFlightRow(line)));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseReactFlightBinaryRows(payload: ArrayBuffer | Uint8Array): FlightResponse {
|
|
56
|
+
const bytes = payload instanceof Uint8Array ? payload : new Uint8Array(payload);
|
|
57
|
+
const decoder = new TextDecoder();
|
|
58
|
+
const rows: ReactFlightRow[] = [];
|
|
59
|
+
let index = 0;
|
|
60
|
+
|
|
61
|
+
while (index < bytes.length) {
|
|
62
|
+
index = skipReactFlightRowBreak(bytes, index);
|
|
63
|
+
|
|
64
|
+
if (index >= bytes.length) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const idStart = index;
|
|
69
|
+
while (index < bytes.length && bytes[index] !== 58) {
|
|
70
|
+
index += 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (index >= bytes.length) {
|
|
74
|
+
throw new Error("Invalid React Flight binary row.");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const idText = decoder.decode(bytes.subarray(idStart, index));
|
|
78
|
+
const id = idText === "" ? 0 : parseReactFlightId(idText);
|
|
79
|
+
index += 1;
|
|
80
|
+
|
|
81
|
+
if (index >= bytes.length) {
|
|
82
|
+
throw new Error("Invalid React Flight binary row.");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const tag = String.fromCharCode(bytes[index] ?? 0);
|
|
86
|
+
|
|
87
|
+
if (isReactFlightBinaryRowTag(tag)) {
|
|
88
|
+
index += 1;
|
|
89
|
+
const lengthStart = index;
|
|
90
|
+
|
|
91
|
+
while (index < bytes.length && bytes[index] !== 44) {
|
|
92
|
+
index += 1;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (index >= bytes.length) {
|
|
96
|
+
throw new Error("Invalid React Flight binary row.");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const byteLength = parseReactFlightId(decoder.decode(bytes.subarray(lengthStart, index)));
|
|
100
|
+
index += 1;
|
|
101
|
+
|
|
102
|
+
if (index + byteLength > bytes.length) {
|
|
103
|
+
throw new Error("React Flight binary row ended before declared payload length.");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
rows.push({
|
|
107
|
+
id,
|
|
108
|
+
tag,
|
|
109
|
+
payload: `${byteLength.toString(16)},`,
|
|
110
|
+
payloadBytes: bytes.slice(index, index + byteLength),
|
|
111
|
+
});
|
|
112
|
+
index += byteLength;
|
|
113
|
+
index = skipReactFlightRowBreak(bytes, index);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const bodyStart = index;
|
|
118
|
+
while (index < bytes.length && bytes[index] !== 10 && bytes[index] !== 13) {
|
|
119
|
+
index += 1;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
rows.push(parseReactFlightRow(`${idText}:${decoder.decode(bytes.subarray(bodyStart, index))}`));
|
|
123
|
+
index = skipReactFlightRowBreak(bytes, index);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return parseReactFlightRowObjects(rows);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function parseReactFlightRowObjects(rows: ReactFlightRow[]): FlightResponse {
|
|
130
|
+
const clientReferences: FlightClientReference[] = [];
|
|
131
|
+
const serverReferences: FlightServerReference[] = [];
|
|
132
|
+
const modelChunks = new Map<number, unknown>();
|
|
133
|
+
const errorChunks = new Map<number, FlightErrorModel>();
|
|
134
|
+
let root: FlightModel | undefined;
|
|
135
|
+
|
|
136
|
+
for (const row of rows) {
|
|
137
|
+
if (row.tag === "I") {
|
|
138
|
+
clientReferences.push(parseReactFlightClientReference(row.id, row.payload));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (row.tag === "F") {
|
|
143
|
+
serverReferences.push(
|
|
144
|
+
parseReactFlightServerReference(row.id, row.payload, modelChunks, errorChunks),
|
|
145
|
+
);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (row.tag === "E") {
|
|
150
|
+
const error = parseReactFlightError(row.payload);
|
|
151
|
+
errorChunks.set(row.id, error);
|
|
152
|
+
|
|
153
|
+
if (row.id === 0) {
|
|
154
|
+
root = error;
|
|
155
|
+
}
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (row.tag === "T") {
|
|
160
|
+
modelChunks.set(row.id, parseReactFlightTextChunk(row.payload));
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (isReactFlightBinaryRowTag(row.tag)) {
|
|
165
|
+
modelChunks.set(row.id, parseReactFlightBinaryChunk(row.tag, row.payload, row.payloadBytes));
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (isReactFlightMetadataTag(row.tag)) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (row.tag === undefined && row.payload !== "") {
|
|
174
|
+
modelChunks.set(row.id, JSON.parse(row.payload));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (root === undefined && modelChunks.has(0)) {
|
|
179
|
+
root = decodeReactFlightModel(modelChunks.get(0), modelChunks, errorChunks);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (root === undefined) {
|
|
183
|
+
throw new Error("Invalid React Flight rows.");
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
version: 1,
|
|
188
|
+
root,
|
|
189
|
+
clientReferences,
|
|
190
|
+
serverReferences,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function skipReactFlightRowBreak(bytes: Uint8Array, index: number): number {
|
|
195
|
+
let next = index;
|
|
196
|
+
|
|
197
|
+
while (next < bytes.length && (bytes[next] === 10 || bytes[next] === 13)) {
|
|
198
|
+
next += 1;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return next;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function parseReactFlightRow(line: string): ReactFlightRow {
|
|
205
|
+
const separator = line.indexOf(":");
|
|
206
|
+
|
|
207
|
+
if (separator < 0) {
|
|
208
|
+
throw new Error("Invalid React Flight row.");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const id = separator === 0 ? 0 : parseReactFlightId(line.slice(0, separator));
|
|
212
|
+
const body = line.slice(separator + 1);
|
|
213
|
+
const first = body[0];
|
|
214
|
+
const hasTag = first !== undefined && isReactFlightRowTag(first, body);
|
|
215
|
+
|
|
216
|
+
if (first !== undefined && !hasTag && looksLikeUnsupportedReactFlightTag(first, body)) {
|
|
217
|
+
throw new Error(`Unsupported React Flight row tag: ${first}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
id,
|
|
222
|
+
...(hasTag ? { tag: first } : {}),
|
|
223
|
+
payload: hasTag ? body.slice(1) : body,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function looksLikeUnsupportedReactFlightTag(tag: string, body: string): boolean {
|
|
228
|
+
return /^[A-Z]$/.test(tag) && (body[1] === "{" || body[1] === "[" || body[1] === "\"");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function parseReactFlightTextChunk(payload: string): string {
|
|
232
|
+
const separator = payload.indexOf(",");
|
|
233
|
+
|
|
234
|
+
if (separator < 0) {
|
|
235
|
+
throw new Error("Invalid React Flight text row.");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return payload.slice(separator + 1);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function parseReactFlightBinaryChunk(
|
|
242
|
+
tag: ReactFlightBinaryRowTag,
|
|
243
|
+
payload: string,
|
|
244
|
+
payloadBytes?: Uint8Array,
|
|
245
|
+
): FlightArrayBufferModel | FlightTypedArrayModel | FlightDataViewModel {
|
|
246
|
+
if (payloadBytes !== undefined) {
|
|
247
|
+
return createReactFlightBinaryModel(tag, payloadBytes);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const separator = payload.indexOf(",");
|
|
251
|
+
|
|
252
|
+
if (separator < 0) {
|
|
253
|
+
throw new Error("Invalid React Flight binary row.");
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const byteLength = parseReactFlightId(payload.slice(0, separator));
|
|
257
|
+
const bytes = decodeBase64Bytes(payload.slice(separator + 1));
|
|
258
|
+
|
|
259
|
+
if (bytes.length !== byteLength) {
|
|
260
|
+
throw new Error("React Flight binary row length did not match declared payload length.");
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return createReactFlightBinaryModel(tag, bytes);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function isReactFlightMetadataTag(tag: string | undefined): boolean {
|
|
267
|
+
return (
|
|
268
|
+
tag === "H" ||
|
|
269
|
+
tag === "N" ||
|
|
270
|
+
tag === "P" ||
|
|
271
|
+
tag === "D" ||
|
|
272
|
+
tag === "J" ||
|
|
273
|
+
tag === "W" ||
|
|
274
|
+
tag === "R" ||
|
|
275
|
+
tag === "r" ||
|
|
276
|
+
tag === "X" ||
|
|
277
|
+
tag === "x" ||
|
|
278
|
+
tag === "C"
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function isReactFlightRowTag(tag: string, body: string): boolean {
|
|
283
|
+
if (
|
|
284
|
+
tag === "I" ||
|
|
285
|
+
tag === "F" ||
|
|
286
|
+
tag === "E" ||
|
|
287
|
+
tag === "T" ||
|
|
288
|
+
tag === "H" ||
|
|
289
|
+
tag === "N" ||
|
|
290
|
+
tag === "P" ||
|
|
291
|
+
tag === "D" ||
|
|
292
|
+
tag === "J" ||
|
|
293
|
+
tag === "W" ||
|
|
294
|
+
tag === "R" ||
|
|
295
|
+
tag === "r" ||
|
|
296
|
+
tag === "X" ||
|
|
297
|
+
tag === "x" ||
|
|
298
|
+
tag === "C"
|
|
299
|
+
) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return isReactFlightBinaryRowTag(tag) && /^[AOoUSsLlGgMmV][0-9a-f]+,/i.test(body);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function isReactFlightBinaryRowTag(tag: string | undefined): tag is ReactFlightBinaryRowTag {
|
|
307
|
+
return (
|
|
308
|
+
tag === "A" ||
|
|
309
|
+
tag === "O" ||
|
|
310
|
+
tag === "o" ||
|
|
311
|
+
tag === "U" ||
|
|
312
|
+
tag === "S" ||
|
|
313
|
+
tag === "s" ||
|
|
314
|
+
tag === "L" ||
|
|
315
|
+
tag === "l" ||
|
|
316
|
+
tag === "G" ||
|
|
317
|
+
tag === "g" ||
|
|
318
|
+
tag === "M" ||
|
|
319
|
+
tag === "m" ||
|
|
320
|
+
tag === "V"
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function createReactFlightBinaryModel(
|
|
325
|
+
tag: ReactFlightBinaryRowTag,
|
|
326
|
+
bytes: Uint8Array,
|
|
327
|
+
): FlightArrayBufferModel | FlightTypedArrayModel | FlightDataViewModel {
|
|
328
|
+
const byteValues = Array.from(bytes);
|
|
329
|
+
|
|
330
|
+
if (tag === "A") {
|
|
331
|
+
return {
|
|
332
|
+
kind: "array-buffer",
|
|
333
|
+
bytes: byteValues,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (tag === "V") {
|
|
338
|
+
return {
|
|
339
|
+
kind: "data-view",
|
|
340
|
+
bytes: byteValues,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
kind: "typed-array",
|
|
346
|
+
arrayType: getReactFlightTypedArrayName(tag),
|
|
347
|
+
bytes: byteValues,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function getReactFlightTypedArrayName(
|
|
352
|
+
tag: Exclude<ReactFlightBinaryRowTag, "A" | "V">,
|
|
353
|
+
): FlightTypedArrayName {
|
|
354
|
+
switch (tag) {
|
|
355
|
+
case "O":
|
|
356
|
+
return "Int8Array";
|
|
357
|
+
case "o":
|
|
358
|
+
return "Uint8Array";
|
|
359
|
+
case "U":
|
|
360
|
+
return "Uint8ClampedArray";
|
|
361
|
+
case "S":
|
|
362
|
+
return "Int16Array";
|
|
363
|
+
case "s":
|
|
364
|
+
return "Uint16Array";
|
|
365
|
+
case "L":
|
|
366
|
+
return "Int32Array";
|
|
367
|
+
case "l":
|
|
368
|
+
return "Uint32Array";
|
|
369
|
+
case "G":
|
|
370
|
+
return "Float32Array";
|
|
371
|
+
case "g":
|
|
372
|
+
return "Float64Array";
|
|
373
|
+
case "M":
|
|
374
|
+
return "BigInt64Array";
|
|
375
|
+
case "m":
|
|
376
|
+
return "BigUint64Array";
|
|
377
|
+
default:
|
|
378
|
+
throw new Error(`Unsupported React Flight typed array row tag: ${tag}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function decodeBase64Bytes(value: string): Uint8Array {
|
|
383
|
+
const normalized = value.replaceAll("-", "+").replaceAll("_", "/");
|
|
384
|
+
const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "=");
|
|
385
|
+
const binary = globalThis.atob(padded);
|
|
386
|
+
const bytes = new Uint8Array(binary.length);
|
|
387
|
+
|
|
388
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
389
|
+
bytes[index] = binary.charCodeAt(index);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return bytes;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function parseReactFlightClientReference(id: number, payload: string): FlightClientReference {
|
|
396
|
+
const value = JSON.parse(payload) as unknown;
|
|
397
|
+
|
|
398
|
+
if (Array.isArray(value)) {
|
|
399
|
+
return {
|
|
400
|
+
id,
|
|
401
|
+
moduleId: String(value[0]),
|
|
402
|
+
chunks: Array.isArray(value[1]) ? value[1].map(String) : [],
|
|
403
|
+
exportName: String(value[2] ?? "default"),
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const object = valueIsObject(value) ? value : {};
|
|
408
|
+
|
|
409
|
+
return {
|
|
410
|
+
id,
|
|
411
|
+
moduleId: String(object.id ?? object.moduleId ?? ""),
|
|
412
|
+
chunks: Array.isArray(object.chunks) ? object.chunks.map(String) : [],
|
|
413
|
+
exportName: String(object.name ?? object.exportName ?? "default"),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function parseReactFlightServerReference(
|
|
418
|
+
id: number,
|
|
419
|
+
payload: string,
|
|
420
|
+
modelChunks: ReadonlyMap<number, unknown> = new Map(),
|
|
421
|
+
errorChunks: ReadonlyMap<number, FlightErrorModel> = new Map(),
|
|
422
|
+
): FlightServerReference {
|
|
423
|
+
const value = JSON.parse(payload) as unknown;
|
|
424
|
+
const object = valueIsObject(value) ? value : {};
|
|
425
|
+
const actionId = String(object.id ?? "");
|
|
426
|
+
const separator = actionId.lastIndexOf("#");
|
|
427
|
+
const bound = Array.isArray(object.bound)
|
|
428
|
+
? object.bound.map((entry) => decodeReactFlightModel(entry, modelChunks, errorChunks))
|
|
429
|
+
: undefined;
|
|
430
|
+
|
|
431
|
+
return {
|
|
432
|
+
id,
|
|
433
|
+
moduleId: separator < 0 ? actionId : actionId.slice(0, separator),
|
|
434
|
+
exportName:
|
|
435
|
+
typeof object.name === "string"
|
|
436
|
+
? object.name
|
|
437
|
+
: separator < 0
|
|
438
|
+
? "default"
|
|
439
|
+
: actionId.slice(separator + 1),
|
|
440
|
+
...(bound === undefined ? {} : { bound }),
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function decodeReactFlightModel(
|
|
445
|
+
value: unknown,
|
|
446
|
+
modelChunks: ReadonlyMap<number, unknown> = new Map(),
|
|
447
|
+
errorChunks: ReadonlyMap<number, FlightErrorModel> = new Map(),
|
|
448
|
+
): FlightModel {
|
|
449
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
450
|
+
return value;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (typeof value === "string") {
|
|
454
|
+
return decodeReactFlightString(value, modelChunks, errorChunks);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if (Array.isArray(value)) {
|
|
458
|
+
if (value[0] === "$") {
|
|
459
|
+
return {
|
|
460
|
+
kind: "element",
|
|
461
|
+
type: decodeReactFlightElementType(value[1]),
|
|
462
|
+
key: typeof value[2] === "string" ? value[2] : null,
|
|
463
|
+
props: decodeReactFlightProps(
|
|
464
|
+
valueIsObject(value[3]) ? value[3] : {},
|
|
465
|
+
modelChunks,
|
|
466
|
+
errorChunks,
|
|
467
|
+
),
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return value.map((item) => decodeReactFlightModel(item, modelChunks, errorChunks));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (isReactFlightBinaryModel(value)) {
|
|
475
|
+
return value;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
if (valueIsObject(value)) {
|
|
479
|
+
return decodeReactFlightProps(value, modelChunks, errorChunks);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return { kind: "undefined" };
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function decodeReactFlightString(
|
|
486
|
+
value: string,
|
|
487
|
+
modelChunks: ReadonlyMap<number, unknown>,
|
|
488
|
+
errorChunks: ReadonlyMap<number, FlightErrorModel>,
|
|
489
|
+
): FlightModel {
|
|
490
|
+
if (value === "$undefined" || value === "$u") {
|
|
491
|
+
return { kind: "undefined" };
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (value.startsWith("$$")) {
|
|
495
|
+
return value.slice(1);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (value === "$I") {
|
|
499
|
+
return { kind: "number", value: "Infinity" };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
if (value === "$-Infinity") {
|
|
503
|
+
return { kind: "number", value: "-Infinity" };
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (value === "$-0") {
|
|
507
|
+
return { kind: "number", value: "-0" };
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (value === "$N") {
|
|
511
|
+
return { kind: "number", value: "NaN" };
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
if (value.startsWith("$D")) {
|
|
515
|
+
return { kind: "date", value: value.slice(2) };
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
if (value.startsWith("$n")) {
|
|
519
|
+
return { kind: "bigint", value: value.slice(2) };
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (/^\$F[0-9a-f]+$/i.test(value)) {
|
|
523
|
+
return {
|
|
524
|
+
kind: "server-reference",
|
|
525
|
+
id: parseReactFlightId(value.slice(2)),
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (/^\$L[0-9a-f]+$/i.test(value)) {
|
|
530
|
+
return {
|
|
531
|
+
kind: "client-reference",
|
|
532
|
+
id: parseReactFlightId(value.slice(2)),
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (/^\$[AOoUSsLlGgMmV][0-9a-f]+$/.test(value)) {
|
|
537
|
+
return decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (value.startsWith("$S")) {
|
|
541
|
+
return { kind: "symbol", name: value.slice(2) };
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (/^\$@[0-9a-f]*$/i.test(value)) {
|
|
545
|
+
return {
|
|
546
|
+
kind: "promise",
|
|
547
|
+
id: value.length === 2 ? 0 : parseReactFlightId(value.slice(2)),
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (/^\$Q[0-9a-f]+$/i.test(value)) {
|
|
552
|
+
const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
|
|
553
|
+
const entries = Array.isArray(decoded)
|
|
554
|
+
? decoded.map((entry): [FlightModel, FlightModel] =>
|
|
555
|
+
Array.isArray(entry)
|
|
556
|
+
? [entry[0] ?? { kind: "undefined" }, entry[1] ?? { kind: "undefined" }]
|
|
557
|
+
: [entry, { kind: "undefined" }],
|
|
558
|
+
)
|
|
559
|
+
: [];
|
|
560
|
+
|
|
561
|
+
return {
|
|
562
|
+
kind: "map",
|
|
563
|
+
entries,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (/^\$W[0-9a-f]+$/i.test(value)) {
|
|
568
|
+
const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
|
|
569
|
+
|
|
570
|
+
return {
|
|
571
|
+
kind: "set",
|
|
572
|
+
values: Array.isArray(decoded) ? decoded : [],
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (/^\$K[0-9a-f]+$/i.test(value)) {
|
|
577
|
+
const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
|
|
578
|
+
const entries = Array.isArray(decoded)
|
|
579
|
+
? decoded.flatMap((entry): [string, FlightModel][] =>
|
|
580
|
+
Array.isArray(entry) && typeof entry[0] === "string"
|
|
581
|
+
? [[entry[0], entry[1] ?? { kind: "undefined" }]]
|
|
582
|
+
: [],
|
|
583
|
+
)
|
|
584
|
+
: [];
|
|
585
|
+
|
|
586
|
+
return {
|
|
587
|
+
kind: "form-data",
|
|
588
|
+
entries,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (/^\$i[0-9a-f]+$/i.test(value)) {
|
|
593
|
+
const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
|
|
594
|
+
|
|
595
|
+
return {
|
|
596
|
+
kind: "iterable",
|
|
597
|
+
values: Array.isArray(decoded) ? decoded : [],
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (/^\$Z[0-9a-f]+$/i.test(value)) {
|
|
602
|
+
return errorChunks.get(parseReactFlightId(value.slice(2))) ?? {
|
|
603
|
+
kind: "error",
|
|
604
|
+
name: "Error",
|
|
605
|
+
message: "Unknown React Flight error.",
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (value === "$Y" || value.startsWith("$E")) {
|
|
610
|
+
return { kind: "undefined" };
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (/^\$[0-9a-f]+$/i.test(value)) {
|
|
614
|
+
return decodeReactFlightChunk(value.slice(1), modelChunks, errorChunks);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return value;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function decodeReactFlightChunk(
|
|
621
|
+
id: string,
|
|
622
|
+
modelChunks: ReadonlyMap<number, unknown>,
|
|
623
|
+
errorChunks: ReadonlyMap<number, FlightErrorModel>,
|
|
624
|
+
): FlightModel {
|
|
625
|
+
const numericId = parseReactFlightId(id);
|
|
626
|
+
const error = errorChunks.get(numericId);
|
|
627
|
+
|
|
628
|
+
if (error !== undefined) {
|
|
629
|
+
return error;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
if (!modelChunks.has(numericId)) {
|
|
633
|
+
return {
|
|
634
|
+
kind: "promise",
|
|
635
|
+
id: numericId,
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return decodeReactFlightModel(modelChunks.get(numericId), modelChunks, errorChunks);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function decodeReactFlightElementType(value: unknown): FlightElementModel["type"] {
|
|
643
|
+
if (value === "$Sreact.fragment") {
|
|
644
|
+
return { kind: "fragment" };
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (typeof value === "string" && /^\$L[0-9a-f]+$/i.test(value)) {
|
|
648
|
+
return {
|
|
649
|
+
kind: "client-reference",
|
|
650
|
+
id: parseReactFlightId(value.slice(2)),
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
return typeof value === "string" ? value : String(value);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
function decodeReactFlightProps(
|
|
658
|
+
value: Record<string, unknown>,
|
|
659
|
+
modelChunks: ReadonlyMap<number, unknown>,
|
|
660
|
+
errorChunks: ReadonlyMap<number, FlightErrorModel>,
|
|
661
|
+
): Record<string, FlightModel> {
|
|
662
|
+
return Object.fromEntries(
|
|
663
|
+
Object.entries(value).map(([key, child]) => [
|
|
664
|
+
key,
|
|
665
|
+
decodeReactFlightModel(child, modelChunks, errorChunks),
|
|
666
|
+
]),
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function isReactFlightBinaryModel(
|
|
671
|
+
value: unknown,
|
|
672
|
+
): value is FlightArrayBufferModel | FlightTypedArrayModel | FlightDataViewModel {
|
|
673
|
+
return (
|
|
674
|
+
valueIsObject(value) &&
|
|
675
|
+
(value.kind === "array-buffer" || value.kind === "typed-array" || value.kind === "data-view")
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function parseReactFlightError(payload: string): FlightErrorModel {
|
|
680
|
+
const value = JSON.parse(payload) as unknown;
|
|
681
|
+
const object = valueIsObject(value) ? value : {};
|
|
682
|
+
const digest = typeof object.digest === "string" ? object.digest : undefined;
|
|
683
|
+
|
|
684
|
+
return {
|
|
685
|
+
kind: "error",
|
|
686
|
+
name: typeof object.name === "string" ? object.name : "Error",
|
|
687
|
+
message: typeof object.message === "string" ? object.message : "React Flight error.",
|
|
688
|
+
...(digest === undefined ? {} : { digest }),
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function valueIsObject(value: unknown): value is Record<string, unknown> {
|
|
693
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
function parseReactFlightId(value: string): number {
|
|
697
|
+
return Number.parseInt(value, 16);
|
|
698
|
+
}
|