@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.
@@ -0,0 +1,71 @@
1
+ export const reactFlightBinaryRowTags = [
2
+ "A",
3
+ "O",
4
+ "o",
5
+ "U",
6
+ "S",
7
+ "s",
8
+ "L",
9
+ "l",
10
+ "G",
11
+ "g",
12
+ "M",
13
+ "m",
14
+ "V",
15
+ ] as const;
16
+
17
+ export const reactFlightRowTags = [
18
+ "C",
19
+ "D",
20
+ "E",
21
+ "F",
22
+ "H",
23
+ "I",
24
+ "J",
25
+ "N",
26
+ "P",
27
+ "R",
28
+ "T",
29
+ "W",
30
+ "X",
31
+ "x",
32
+ "r",
33
+ ] as const;
34
+
35
+ export const reactFlightModelTokens = [
36
+ "$",
37
+ "$$",
38
+ "$@",
39
+ "$D",
40
+ "$E",
41
+ "$F",
42
+ "$I",
43
+ "$K",
44
+ "$L",
45
+ "$N",
46
+ "$Q",
47
+ "$S",
48
+ "$W",
49
+ "$Y",
50
+ "$Z",
51
+ "$i",
52
+ "$n",
53
+ "$u",
54
+ "$undefined",
55
+ ] as const;
56
+
57
+ export type ReactFlightBinaryRowTag = (typeof reactFlightBinaryRowTags)[number];
58
+
59
+ export interface ReactFlightProtocolCoverage {
60
+ binaryRowTags: string[];
61
+ modelTokens: string[];
62
+ rowTags: string[];
63
+ }
64
+
65
+ export function getReactFlightProtocolCoverage(): ReactFlightProtocolCoverage {
66
+ return {
67
+ binaryRowTags: [...reactFlightBinaryRowTags],
68
+ modelTokens: [...reactFlightModelTokens],
69
+ rowTags: [...reactFlightRowTags],
70
+ };
71
+ }
@@ -0,0 +1,148 @@
1
+ export interface FlightClientReference {
2
+ id: number;
3
+ moduleId: string;
4
+ exportName: string;
5
+ chunks?: string[];
6
+ }
7
+
8
+ export interface FlightServerReference {
9
+ id: number;
10
+ moduleId: string;
11
+ exportName: string;
12
+ bound?: FlightModel[];
13
+ }
14
+
15
+ export interface FlightResponse {
16
+ version: 1;
17
+ root: FlightModel;
18
+ clientReferences: FlightClientReference[];
19
+ serverReferences: FlightServerReference[];
20
+ }
21
+
22
+ export type FlightModel =
23
+ | null
24
+ | string
25
+ | number
26
+ | boolean
27
+ | FlightModel[]
28
+ | FlightObjectModel
29
+ | FlightElementModel
30
+ | FlightClientReferenceModel
31
+ | FlightServerReferenceModel
32
+ | FlightDateModel
33
+ | FlightBigIntModel
34
+ | FlightNumberModel
35
+ | FlightSymbolModel
36
+ | FlightMapModel
37
+ | FlightSetModel
38
+ | FlightFormDataModel
39
+ | FlightIterableModel
40
+ | FlightErrorModel
41
+ | FlightPromiseModel
42
+ | FlightArrayBufferModel
43
+ | FlightTypedArrayModel
44
+ | FlightDataViewModel
45
+ | { kind: "undefined" };
46
+
47
+ export interface FlightObjectModel {
48
+ kind?: never;
49
+ [key: string]: FlightModel | undefined;
50
+ }
51
+
52
+ export interface FlightElementModel {
53
+ kind: "element";
54
+ type: string | FlightClientReferenceModel | { kind: "fragment" };
55
+ key: string | null;
56
+ props: Record<string, FlightModel>;
57
+ }
58
+
59
+ export interface FlightClientReferenceModel {
60
+ kind: "client-reference";
61
+ id: number;
62
+ }
63
+
64
+ export interface FlightServerReferenceModel {
65
+ kind: "server-reference";
66
+ id: number;
67
+ }
68
+
69
+ export interface FlightDateModel {
70
+ kind: "date";
71
+ value: string;
72
+ }
73
+
74
+ export interface FlightBigIntModel {
75
+ kind: "bigint";
76
+ value: string;
77
+ }
78
+
79
+ export interface FlightNumberModel {
80
+ kind: "number";
81
+ value: "Infinity" | "-Infinity" | "NaN" | "-0";
82
+ }
83
+
84
+ export interface FlightSymbolModel {
85
+ kind: "symbol";
86
+ name: string;
87
+ }
88
+
89
+ export interface FlightMapModel {
90
+ kind: "map";
91
+ entries: [FlightModel, FlightModel][];
92
+ }
93
+
94
+ export interface FlightSetModel {
95
+ kind: "set";
96
+ values: FlightModel[];
97
+ }
98
+
99
+ export interface FlightFormDataModel {
100
+ kind: "form-data";
101
+ entries: [string, FlightModel][];
102
+ }
103
+
104
+ export interface FlightIterableModel {
105
+ kind: "iterable";
106
+ values: FlightModel[];
107
+ }
108
+
109
+ export interface FlightErrorModel {
110
+ kind: "error";
111
+ name: string;
112
+ message: string;
113
+ digest?: string;
114
+ }
115
+
116
+ export interface FlightPromiseModel {
117
+ kind: "promise";
118
+ id: number;
119
+ }
120
+
121
+ export interface FlightArrayBufferModel {
122
+ kind: "array-buffer";
123
+ bytes: number[];
124
+ }
125
+
126
+ export interface FlightTypedArrayModel {
127
+ kind: "typed-array";
128
+ arrayType: FlightTypedArrayName;
129
+ bytes: number[];
130
+ }
131
+
132
+ export interface FlightDataViewModel {
133
+ kind: "data-view";
134
+ bytes: number[];
135
+ }
136
+
137
+ export type FlightTypedArrayName =
138
+ | "Int8Array"
139
+ | "Uint8Array"
140
+ | "Uint8ClampedArray"
141
+ | "Int16Array"
142
+ | "Uint16Array"
143
+ | "Int32Array"
144
+ | "Uint32Array"
145
+ | "Float32Array"
146
+ | "Float64Array"
147
+ | "BigInt64Array"
148
+ | "BigUint64Array";
package/src/flight.ts ADDED
@@ -0,0 +1,162 @@
1
+ import type { ReactCompatNode } from "./element.js";
2
+ import { hydrateRoot, type HydrateRootOptions } from "./render.js";
3
+ import {
4
+ getReactFlightProtocolCoverage,
5
+ type ReactFlightProtocolCoverage,
6
+ } from "./flight-protocol.js";
7
+ import { decodeFlightModel, type DecodeFlightOptions } from "./flight-decoder.js";
8
+ import { parseReactFlightPayload } from "./flight-parser.js";
9
+ import type {
10
+ FlightArrayBufferModel,
11
+ FlightBigIntModel,
12
+ FlightClientReference,
13
+ FlightClientReferenceModel,
14
+ FlightDataViewModel,
15
+ FlightDateModel,
16
+ FlightElementModel,
17
+ FlightErrorModel,
18
+ FlightFormDataModel,
19
+ FlightIterableModel,
20
+ FlightMapModel,
21
+ FlightModel,
22
+ FlightNumberModel,
23
+ FlightPromiseModel,
24
+ FlightResponse,
25
+ FlightServerReference,
26
+ FlightServerReferenceModel,
27
+ FlightSetModel,
28
+ FlightSymbolModel,
29
+ FlightTypedArrayModel,
30
+ FlightTypedArrayName,
31
+ } from "./flight-types.js";
32
+
33
+ export { getReactFlightProtocolCoverage };
34
+ export type {
35
+ DecodeFlightOptions,
36
+ FlightArrayBufferModel,
37
+ FlightBigIntModel,
38
+ FlightClientReference,
39
+ FlightClientReferenceModel,
40
+ FlightDataViewModel,
41
+ FlightDateModel,
42
+ FlightElementModel,
43
+ FlightErrorModel,
44
+ FlightFormDataModel,
45
+ FlightIterableModel,
46
+ FlightMapModel,
47
+ FlightModel,
48
+ FlightNumberModel,
49
+ FlightPromiseModel,
50
+ FlightResponse,
51
+ FlightServerReference,
52
+ FlightServerReferenceModel,
53
+ FlightSetModel,
54
+ FlightSymbolModel,
55
+ FlightTypedArrayModel,
56
+ FlightTypedArrayName,
57
+ };
58
+ export type { ReactFlightProtocolCoverage };
59
+
60
+ export interface FetchServerReferenceCallerOptions {
61
+ fetch?: typeof fetch;
62
+ headers?: Record<string, string>;
63
+ credentials?: RequestCredentials;
64
+ csrfHeaderName?: string;
65
+ csrfToken?: string | (() => string);
66
+ nonceHeaderName?: string;
67
+ nonce?: string | (() => string);
68
+ }
69
+
70
+ export interface HydrateFlightOptions extends DecodeFlightOptions {
71
+ hydrate?: HydrateRootOptions;
72
+ }
73
+
74
+ export function parseFlightResponse(payload: string | ArrayBuffer | Uint8Array): FlightResponse {
75
+ return parseReactFlightPayload(payload);
76
+ }
77
+
78
+ export function decodeFlightResponse(
79
+ response: FlightResponse,
80
+ options: DecodeFlightOptions,
81
+ ): ReactCompatNode {
82
+ return decodeFlightModel(response.root, response, options) as ReactCompatNode;
83
+ }
84
+
85
+ export function readFlightResponse(
86
+ root: Document | ParentNode,
87
+ id?: string,
88
+ ): FlightResponse {
89
+ const selector =
90
+ id === undefined
91
+ ? "script[data-mreact-flight]"
92
+ : `script[data-mreact-flight]#${cssEscape(id)}`;
93
+ const script = root.querySelector(selector);
94
+
95
+ if (script === null || script.textContent === null) {
96
+ throw new Error("Flight response script was not found.");
97
+ }
98
+
99
+ return parseFlightResponse(script.textContent);
100
+ }
101
+
102
+ export function hydrateFlightResponse(
103
+ container: Element,
104
+ response: FlightResponse,
105
+ options: HydrateFlightOptions,
106
+ ): ReturnType<typeof import("./render.js").hydrateRoot> {
107
+ return hydrateRoot(container, decodeFlightResponse(response, options), options.hydrate);
108
+ }
109
+
110
+ export function createFetchServerReferenceCaller(
111
+ endpoint: string,
112
+ options: FetchServerReferenceCallerOptions = {},
113
+ ): NonNullable<DecodeFlightOptions["callServerReference"]> {
114
+ const fetchImpl = options.fetch ?? fetch;
115
+
116
+ return async (reference, args) => {
117
+ const response = await fetchImpl(endpoint, {
118
+ method: "POST",
119
+ credentials: options.credentials ?? "same-origin",
120
+ headers: createServerReferenceHeaders(options),
121
+ body: JSON.stringify({
122
+ moduleId: reference.moduleId,
123
+ exportName: reference.exportName,
124
+ ...(reference.bound === undefined ? {} : { bound: reference.bound }),
125
+ args,
126
+ }),
127
+ });
128
+ const payload = (await response.json()) as { ok?: boolean; value?: unknown; error?: string };
129
+
130
+ if (!response.ok || payload.ok !== true) {
131
+ throw new Error(payload.error ?? "Server action failed.");
132
+ }
133
+
134
+ return payload.value;
135
+ };
136
+ }
137
+
138
+ function createServerReferenceHeaders(
139
+ options: FetchServerReferenceCallerOptions,
140
+ ): Record<string, string> {
141
+ const csrfToken = readOptionalToken(options.csrfToken);
142
+ const nonce = readOptionalToken(options.nonce);
143
+
144
+ return {
145
+ "content-type": "application/json",
146
+ ...options.headers,
147
+ ...(csrfToken === undefined
148
+ ? {}
149
+ : { [options.csrfHeaderName ?? "x-mreact-csrf"]: csrfToken }),
150
+ ...(nonce === undefined
151
+ ? {}
152
+ : { [options.nonceHeaderName ?? "x-mreact-action-nonce"]: nonce }),
153
+ };
154
+ }
155
+
156
+ function readOptionalToken(token: string | (() => string) | undefined): string | undefined {
157
+ return typeof token === "function" ? token() : token;
158
+ }
159
+
160
+ function cssEscape(value: string): string {
161
+ return globalThis.CSS?.escape?.(value) ?? value.replaceAll('"', '\\"');
162
+ }