@bgub/fig-server 0.1.0-alpha.1 → 0.1.0-alpha.3
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/{shared-Bna74_aZ.js → image-preloads-BIFcrqm9.js} +40 -2
- package/dist/image-preloads-BIFcrqm9.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +68 -12
- package/dist/index.js.map +1 -1
- package/dist/payload.d.ts +1 -1
- package/dist/payload.js +22 -6
- package/dist/payload.js.map +1 -1
- package/dist/{types-CimwEFsf.d.ts → types-mrjoQDOc.d.ts} +6 -3
- package/dist-development/escaping-DAot8sFu.js +26 -0
- package/dist-development/escaping-DAot8sFu.js.map +1 -0
- package/dist-development/html-entry.js +2 -0
- package/dist-development/image-preloads-D3OBEaWp.js +164 -0
- package/dist-development/image-preloads-D3OBEaWp.js.map +1 -0
- package/dist-development/index.js +1764 -0
- package/dist-development/index.js.map +1 -0
- package/dist-development/payload.js +602 -0
- package/dist-development/payload.js.map +1 -0
- package/package.json +8 -4
- package/dist/shared-Bna74_aZ.js.map +0 -1
|
@@ -0,0 +1,1764 @@
|
|
|
1
|
+
import { i as escapeText, n as escapeScriptJson, t as escapeAttribute } from "./escaping-DAot8sFu.js";
|
|
2
|
+
import { a as componentStack, c as errorMessage, d as streamHighWaterMark, f as withContextValue, i as cloneContextValues, l as nonceAttribute, n as suppressesImagePreloads, o as createStaticDispatcher, r as STREAMED_METADATA_ATTRIBUTE, s as deferred, t as imagePreloadFromHostProps, u as streamFlowBlocked } from "./image-preloads-D3OBEaWp.js";
|
|
3
|
+
import { Fragment, createElement, isValidElement } from "@bgub/fig";
|
|
4
|
+
import { ACTIVITY_TEMPLATE_ATTRIBUTE, EARLY_EVENT_HANDLER_PROPERTY, EARLY_EVENT_QUEUE_PROPERTY, HYDRATION_SKIP_ATTRIBUTE, REPLAYABLE_EVENT_TYPES, SUSPENSE_CLIENT_MARKER, SUSPENSE_COMPLETED_MARKER, SUSPENSE_END_MARKER, SUSPENSE_MARKER_PREFIX, SUSPENSE_PENDING_PREFIX, TEXT_SEPARATOR_DATA, VIEW_TRANSITION_CLASS_ATTRIBUTE, VIEW_TRANSITION_NAME_ATTRIBUTE, VIEW_TRANSITION_PENDING_PROPERTY, VIEW_TRANSITION_TIMEOUT_MS, assetResourceFromHostProps, assetResourceHostAttributes, assetResourceKey, attachDataStore, collectChildren, createRendererDataStore, invalidChildError, isActivity, isAssets, isClientReference, isContext, isErrorBoundary, isFigAssetResource, isPortal, isSuspense, isThenable, isViewTransition, readThenable, setCurrentDataStore, setCurrentDispatcher, validateInstanceNesting, validateTextNesting } from "@bgub/fig/internal";
|
|
5
|
+
//#region src/html.ts
|
|
6
|
+
const voidElements = /* @__PURE__ */ new Set([
|
|
7
|
+
"area",
|
|
8
|
+
"base",
|
|
9
|
+
"br",
|
|
10
|
+
"col",
|
|
11
|
+
"embed",
|
|
12
|
+
"hr",
|
|
13
|
+
"img",
|
|
14
|
+
"input",
|
|
15
|
+
"link",
|
|
16
|
+
"meta",
|
|
17
|
+
"param",
|
|
18
|
+
"source",
|
|
19
|
+
"track",
|
|
20
|
+
"wbr"
|
|
21
|
+
]);
|
|
22
|
+
function writeText(value, sink) {
|
|
23
|
+
sink.write(escapeText(value));
|
|
24
|
+
}
|
|
25
|
+
function writeElementStart(type, props, sink, inheritedProps = {}) {
|
|
26
|
+
validateTagName(type);
|
|
27
|
+
sink.write(`<${type}${serializeAttributes(type, props, inheritedProps)}>`);
|
|
28
|
+
}
|
|
29
|
+
function writeElementEnd(type, sink) {
|
|
30
|
+
sink.write(`</${type}>`);
|
|
31
|
+
}
|
|
32
|
+
function isVoidElement(type) {
|
|
33
|
+
return voidElements.has(type);
|
|
34
|
+
}
|
|
35
|
+
function hasRenderableChild(node) {
|
|
36
|
+
if (Array.isArray(node)) return node.some(hasRenderableChild);
|
|
37
|
+
if (isPortal(node)) return false;
|
|
38
|
+
return !emptyChild(node);
|
|
39
|
+
}
|
|
40
|
+
function formTextContent(type, props) {
|
|
41
|
+
if (type !== "textarea") return null;
|
|
42
|
+
return formString(props.value !== void 0 ? props.value : props.defaultValue);
|
|
43
|
+
}
|
|
44
|
+
function unsafeHTMLContent(props) {
|
|
45
|
+
const value = props.unsafeHTML;
|
|
46
|
+
if (emptyValue(value)) return null;
|
|
47
|
+
if (typeof value === "string") return value;
|
|
48
|
+
throw new Error("The unsafeHTML prop must be a string during server render.");
|
|
49
|
+
}
|
|
50
|
+
function serializeAttributes(type, props, inheritedProps) {
|
|
51
|
+
let attributes = "";
|
|
52
|
+
for (const name of Object.keys(props)) {
|
|
53
|
+
const value = props[name];
|
|
54
|
+
if (reservedProp(name)) continue;
|
|
55
|
+
if (name === "value" && props.defaultValue !== void 0) continue;
|
|
56
|
+
if (name === "checked" && props.defaultChecked !== void 0) continue;
|
|
57
|
+
if (name === "style") {
|
|
58
|
+
const style = serializeStyle(value);
|
|
59
|
+
if (style !== "") attributes += serializeAttribute("style", style);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
attributes += serializeProp(type, name, value);
|
|
63
|
+
}
|
|
64
|
+
if (type === "option" && props.selected === void 0 && optionSelected(optionValue(props), inheritedProps)) attributes += " selected";
|
|
65
|
+
return attributes;
|
|
66
|
+
}
|
|
67
|
+
function serializeProp(type, name, value) {
|
|
68
|
+
if ((type === "textarea" || type === "select") && valueProp(name)) return "";
|
|
69
|
+
let attributeName = name;
|
|
70
|
+
let attributeValue = value;
|
|
71
|
+
if (valueProp(name)) {
|
|
72
|
+
attributeName = "value";
|
|
73
|
+
if (serializableAttributeValue(value)) attributeValue = String(value);
|
|
74
|
+
} else if (name === "defaultChecked") {
|
|
75
|
+
attributeName = "checked";
|
|
76
|
+
attributeValue = value === true ? true : null;
|
|
77
|
+
} else if (type === "option" && name === "selected") attributeValue = value === true ? true : null;
|
|
78
|
+
if (emptyValue(attributeValue)) return "";
|
|
79
|
+
validateAttributeName(attributeName);
|
|
80
|
+
if (attributeValue === true) return ` ${attributeName}`;
|
|
81
|
+
if (serializableAttributeValue(attributeValue)) return serializeAttribute(attributeName, String(attributeValue));
|
|
82
|
+
throw new Error(`Cannot serialize prop "${name}" to HTML.`);
|
|
83
|
+
}
|
|
84
|
+
function optionSelected(value, selectProps) {
|
|
85
|
+
const selectValue = selectProps.value !== void 0 ? selectProps.value : selectProps.defaultValue;
|
|
86
|
+
if (emptyValue(selectValue)) return false;
|
|
87
|
+
const optionValue = formString(value);
|
|
88
|
+
if (optionValue === null) return false;
|
|
89
|
+
return selectedValueSet(selectValue).has(optionValue);
|
|
90
|
+
}
|
|
91
|
+
function optionValue(props) {
|
|
92
|
+
return props.value === void 0 ? optionTextValue(props.children) : formString(props.value);
|
|
93
|
+
}
|
|
94
|
+
function optionTextValue(node) {
|
|
95
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
96
|
+
if (Array.isArray(node)) {
|
|
97
|
+
let text = "";
|
|
98
|
+
for (const child of node) {
|
|
99
|
+
const childText = optionTextValue(child);
|
|
100
|
+
if (childText === null) return null;
|
|
101
|
+
text += childText;
|
|
102
|
+
}
|
|
103
|
+
return text;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function formString(value) {
|
|
108
|
+
if (emptyValue(value)) return null;
|
|
109
|
+
if (serializableAttributeValue(value)) return String(value);
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
function selectedValueSet(value) {
|
|
113
|
+
return new Set(Array.isArray(value) ? value.map(String) : [String(value)]);
|
|
114
|
+
}
|
|
115
|
+
function serializableAttributeValue(value) {
|
|
116
|
+
return value === true || typeof value === "string" || typeof value === "number" || typeof value === "bigint";
|
|
117
|
+
}
|
|
118
|
+
function emptyValue(value) {
|
|
119
|
+
return value === null || value === void 0 || value === false;
|
|
120
|
+
}
|
|
121
|
+
function emptyChild(value) {
|
|
122
|
+
return value === null || value === void 0 || typeof value === "boolean";
|
|
123
|
+
}
|
|
124
|
+
function serializeAttribute(name, value) {
|
|
125
|
+
return ` ${name}="${escapeAttribute(value)}"`;
|
|
126
|
+
}
|
|
127
|
+
function serializeStyle(value) {
|
|
128
|
+
if (emptyValue(value)) return "";
|
|
129
|
+
if (typeof value !== "object" || value === null) throw new Error("The style prop must be an object during server render.");
|
|
130
|
+
let serialized = "";
|
|
131
|
+
for (const [name, item] of Object.entries(value)) {
|
|
132
|
+
if (emptyValue(item)) continue;
|
|
133
|
+
if (typeof item !== "string" && typeof item !== "number" && typeof item !== "bigint") throw new Error(`Cannot serialize style property "${name}" to HTML.`);
|
|
134
|
+
if (serialized !== "") serialized += ";";
|
|
135
|
+
serialized += `${styleName(name)}:${String(item)}`;
|
|
136
|
+
}
|
|
137
|
+
return serialized;
|
|
138
|
+
}
|
|
139
|
+
function reservedProp(name) {
|
|
140
|
+
return name === "children" || name === "key" || name === "mix" || name === "bind" || name === "suppressHydrationWarning" || name === "unsafeHTML" || /^on[A-Z]/.test(name);
|
|
141
|
+
}
|
|
142
|
+
function valueProp(name) {
|
|
143
|
+
return name === "value" || name === "defaultValue";
|
|
144
|
+
}
|
|
145
|
+
function styleName(name) {
|
|
146
|
+
if (name.startsWith("--")) return name;
|
|
147
|
+
return name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
148
|
+
}
|
|
149
|
+
function validateTagName(name) {
|
|
150
|
+
if (!/^[A-Za-z][A-Za-z0-9:._-]*$/.test(name)) throw new Error(`Invalid HTML tag name "${name}".`);
|
|
151
|
+
}
|
|
152
|
+
function validateAttributeName(name) {
|
|
153
|
+
if (/[\s"'<>/=]/.test(name)) throw new Error(`Invalid HTML attribute name "${name}".`);
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
//#region src/preload-header.ts
|
|
157
|
+
const DEFAULT_LENGTH = 2e3;
|
|
158
|
+
const HEX_ESCAPE = /^[0-9A-Fa-f]{2}$/;
|
|
159
|
+
const PARAMETER_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
160
|
+
const URI_REFERENCE_PUNCTUATION = "-._~:/?#[]@!$&'()*+,;=";
|
|
161
|
+
function createPreloadHeaderEntries(resources, isEarlyImage) {
|
|
162
|
+
const preconnects = [];
|
|
163
|
+
const criticalPreloads = [];
|
|
164
|
+
const stylesheets = [];
|
|
165
|
+
const remaining = [];
|
|
166
|
+
for (const resource of resources) {
|
|
167
|
+
if (!isServerPreloadHeaderResource(resource)) continue;
|
|
168
|
+
const value = preloadHeaderValue(resource);
|
|
169
|
+
if (value === null) continue;
|
|
170
|
+
const entry = {
|
|
171
|
+
resource,
|
|
172
|
+
value
|
|
173
|
+
};
|
|
174
|
+
if (resource.kind === "preconnect") preconnects.push(entry);
|
|
175
|
+
else if (resource.kind === "font" || resource.kind === "preload" && (resource.as === "font" || resource.as === "image" && (resource.fetchpriority === "high" || isEarlyImage?.(resource) === true))) criticalPreloads.push(entry);
|
|
176
|
+
else if (resource.kind === "stylesheet") stylesheets.push(entry);
|
|
177
|
+
else remaining.push(entry);
|
|
178
|
+
}
|
|
179
|
+
return [
|
|
180
|
+
...preconnects,
|
|
181
|
+
...criticalPreloads,
|
|
182
|
+
...stylesheets,
|
|
183
|
+
...remaining
|
|
184
|
+
];
|
|
185
|
+
}
|
|
186
|
+
function formatPreloadHeader(entries, options = {}) {
|
|
187
|
+
const maxLength = normalizedLength(options.maxLength);
|
|
188
|
+
if (maxLength === 0) return void 0;
|
|
189
|
+
const seen = /* @__PURE__ */ new Set();
|
|
190
|
+
const values = [];
|
|
191
|
+
let length = 0;
|
|
192
|
+
for (const entry of entries) {
|
|
193
|
+
if (options.filter !== void 0 && !options.filter(entry.resource)) continue;
|
|
194
|
+
if (seen.has(entry.value)) continue;
|
|
195
|
+
const addedLength = entry.value.length + (values.length === 0 ? 0 : 2);
|
|
196
|
+
if (length + addedLength > maxLength) continue;
|
|
197
|
+
seen.add(entry.value);
|
|
198
|
+
values.push(entry.value);
|
|
199
|
+
length += addedLength;
|
|
200
|
+
}
|
|
201
|
+
return values.length === 0 ? void 0 : values.join(", ");
|
|
202
|
+
}
|
|
203
|
+
function preloadHeaderValue(resource) {
|
|
204
|
+
switch (resource.kind) {
|
|
205
|
+
case "stylesheet": return serializeLink(resource.href, [
|
|
206
|
+
["rel", "preload"],
|
|
207
|
+
["as", "style"],
|
|
208
|
+
["crossorigin", resource.crossorigin],
|
|
209
|
+
["media", resource.media]
|
|
210
|
+
]);
|
|
211
|
+
case "preload": return serializeLink(resource.href, [
|
|
212
|
+
["rel", "preload"],
|
|
213
|
+
["as", resource.as],
|
|
214
|
+
["crossorigin", resource.crossorigin],
|
|
215
|
+
["type", resource.type],
|
|
216
|
+
["fetchpriority", resource.fetchpriority],
|
|
217
|
+
["referrerpolicy", resource.referrerpolicy]
|
|
218
|
+
]);
|
|
219
|
+
case "modulepreload": return serializeLink(resource.href, [
|
|
220
|
+
["rel", "modulepreload"],
|
|
221
|
+
["as", "script"],
|
|
222
|
+
["crossorigin", resource.crossorigin],
|
|
223
|
+
["fetchpriority", resource.fetchpriority]
|
|
224
|
+
]);
|
|
225
|
+
case "font": return serializeLink(resource.href, [
|
|
226
|
+
["rel", "preload"],
|
|
227
|
+
["as", "font"],
|
|
228
|
+
["crossorigin", resource.crossorigin ?? "anonymous"],
|
|
229
|
+
["type", resource.type],
|
|
230
|
+
["fetchpriority", resource.fetchpriority]
|
|
231
|
+
]);
|
|
232
|
+
case "preconnect": return serializeLink(resource.href, [["rel", "preconnect"], ["crossorigin", resource.crossorigin]]);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function isServerPreloadHeaderResource(resource) {
|
|
236
|
+
if (resource.kind === "script") return false;
|
|
237
|
+
return resource.kind !== "preload" || resource.href !== void 0 && (resource.as !== "image" || !resource.imagesrcset);
|
|
238
|
+
}
|
|
239
|
+
function serializeLink(target, parameters) {
|
|
240
|
+
const encodedTarget = encodeLinkTarget(target);
|
|
241
|
+
if (encodedTarget === null) return null;
|
|
242
|
+
const parts = [`<${encodedTarget}>`];
|
|
243
|
+
for (const [name, value] of parameters) {
|
|
244
|
+
if (value === void 0) continue;
|
|
245
|
+
const parameter = serializeParameter(name, value);
|
|
246
|
+
if (parameter === null) return null;
|
|
247
|
+
parts.push(parameter);
|
|
248
|
+
}
|
|
249
|
+
return parts.join("; ");
|
|
250
|
+
}
|
|
251
|
+
function serializeParameter(name, value) {
|
|
252
|
+
if (value === "") return name;
|
|
253
|
+
if (hasInvalidParameterCharacter(value)) return null;
|
|
254
|
+
if (PARAMETER_TOKEN.test(value)) return `${name}=${value}`;
|
|
255
|
+
return `${name}="${value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"")}"`;
|
|
256
|
+
}
|
|
257
|
+
function encodeLinkTarget(value) {
|
|
258
|
+
if (value === "") return null;
|
|
259
|
+
let encoded = "";
|
|
260
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
261
|
+
const code = value.charCodeAt(index);
|
|
262
|
+
if (code <= 32 || code === 127) return null;
|
|
263
|
+
const character = value[index];
|
|
264
|
+
if (character === "%" && HEX_ESCAPE.test(value.slice(index + 1, index + 3))) {
|
|
265
|
+
encoded += value.slice(index, index + 3);
|
|
266
|
+
index += 2;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || URI_REFERENCE_PUNCTUATION.includes(character)) {
|
|
270
|
+
encoded += character;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const codePoint = value.codePointAt(index);
|
|
274
|
+
if (codePoint === void 0) return null;
|
|
275
|
+
const symbol = String.fromCodePoint(codePoint);
|
|
276
|
+
if (symbol.length === 2) index += 1;
|
|
277
|
+
try {
|
|
278
|
+
encoded += encodeURIComponent(symbol);
|
|
279
|
+
} catch {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return encoded;
|
|
284
|
+
}
|
|
285
|
+
function hasInvalidParameterCharacter(value) {
|
|
286
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
287
|
+
const code = value.charCodeAt(index);
|
|
288
|
+
if (code < 32 || code === 127 || code > 255) return true;
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
function normalizedLength(value) {
|
|
293
|
+
if (value === void 0 || Number.isNaN(value)) return DEFAULT_LENGTH;
|
|
294
|
+
return Math.max(0, Math.floor(value));
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/asset-registry.ts
|
|
298
|
+
var AssetResourceRegistry = class {
|
|
299
|
+
identifierPrefix;
|
|
300
|
+
earlyImageKeys = /* @__PURE__ */ new Set();
|
|
301
|
+
emittedResources = /* @__PURE__ */ new Set();
|
|
302
|
+
deliveryResources = /* @__PURE__ */ new Map();
|
|
303
|
+
metadataByOwner = /* @__PURE__ */ new Map();
|
|
304
|
+
stylesheetIds = /* @__PURE__ */ new Map();
|
|
305
|
+
nextStylesheetId = 0;
|
|
306
|
+
constructor(identifierPrefix) {
|
|
307
|
+
this.identifierPrefix = identifierPrefix;
|
|
308
|
+
}
|
|
309
|
+
register(resource) {
|
|
310
|
+
if (isMetadataResource(resource)) return;
|
|
311
|
+
this.canonical(resource);
|
|
312
|
+
}
|
|
313
|
+
registerAutomaticImage(resource) {
|
|
314
|
+
const { key, resource: current } = this.canonical(resource);
|
|
315
|
+
if (this.earlyImageKeys.size < 10 || current.kind === "preload" && current.as === "image" && current.fetchpriority === "high") this.earlyImageKeys.add(key);
|
|
316
|
+
}
|
|
317
|
+
isEarlyImage(resource) {
|
|
318
|
+
return this.earlyImageKeys.has(assetResourceKey(resource));
|
|
319
|
+
}
|
|
320
|
+
activateMetadata(owner, resources) {
|
|
321
|
+
const metadata = resources.filter(isMetadataResource);
|
|
322
|
+
if (metadata.length === 0) {
|
|
323
|
+
this.metadataByOwner.delete(owner);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
this.metadataByOwner.set(owner, metadata);
|
|
327
|
+
}
|
|
328
|
+
releaseMetadata(owner) {
|
|
329
|
+
this.metadataByOwner.delete(owner);
|
|
330
|
+
}
|
|
331
|
+
write(resource, sink) {
|
|
332
|
+
if (isMetadataResource(resource)) return null;
|
|
333
|
+
const { key, resource: current } = this.canonical(resource);
|
|
334
|
+
const id = this.revealBlockerId(key, current);
|
|
335
|
+
if (this.emittedResources.has(key)) return id;
|
|
336
|
+
this.emittedResources.add(key);
|
|
337
|
+
writeAssetTag(sink, current, id);
|
|
338
|
+
return id;
|
|
339
|
+
}
|
|
340
|
+
headHtml(nonce, streamMetadata = false) {
|
|
341
|
+
const { preamble, metadata } = this.headMetadataHtml(nonce, streamMetadata);
|
|
342
|
+
return preamble + metadata;
|
|
343
|
+
}
|
|
344
|
+
headMetadataHtml(nonce, streamMetadata = false) {
|
|
345
|
+
const buckets = {
|
|
346
|
+
charset: [],
|
|
347
|
+
parser: [],
|
|
348
|
+
viewport: [],
|
|
349
|
+
metadata: []
|
|
350
|
+
};
|
|
351
|
+
for (const resource of this.visibleMetadata().values()) {
|
|
352
|
+
const bucket = buckets[metadataPhase(resource)];
|
|
353
|
+
writeAssetTag({
|
|
354
|
+
nonce,
|
|
355
|
+
streamMetadata,
|
|
356
|
+
write: (chunk) => bucket.push(chunk)
|
|
357
|
+
}, resource, null);
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
preamble: [
|
|
361
|
+
...buckets.charset,
|
|
362
|
+
...buckets.parser,
|
|
363
|
+
...buckets.viewport
|
|
364
|
+
].join(""),
|
|
365
|
+
metadata: buckets.metadata.join("")
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
metadataSnapshot() {
|
|
369
|
+
const snapshot = [];
|
|
370
|
+
for (const [key, resource] of this.visibleMetadata()) if (resource.kind === "title") snapshot.push([
|
|
371
|
+
key,
|
|
372
|
+
resource.kind,
|
|
373
|
+
resource.value
|
|
374
|
+
]);
|
|
375
|
+
else snapshot.push([
|
|
376
|
+
key,
|
|
377
|
+
resource.kind,
|
|
378
|
+
metadataAttributes(resource)
|
|
379
|
+
]);
|
|
380
|
+
return snapshot;
|
|
381
|
+
}
|
|
382
|
+
preloadHeaderEntries() {
|
|
383
|
+
return createPreloadHeaderEntries(this.deliveryResources.values(), (resource) => this.isEarlyImage(resource));
|
|
384
|
+
}
|
|
385
|
+
visibleMetadata() {
|
|
386
|
+
const visible = /* @__PURE__ */ new Map();
|
|
387
|
+
for (const metadata of this.metadataByOwner.values()) for (const resource of metadata) visible.set(assetResourceKey(resource), resource);
|
|
388
|
+
return visible;
|
|
389
|
+
}
|
|
390
|
+
canonical(resource) {
|
|
391
|
+
const key = assetResourceKey(resource);
|
|
392
|
+
const current = this.deliveryResources.get(key);
|
|
393
|
+
if (current !== void 0) {
|
|
394
|
+
if (assetSignature(current) !== assetSignature(resource)) {
|
|
395
|
+
const promoted = promoteCompatibleImagePreload(current, resource);
|
|
396
|
+
if (promoted === null) throw new AssetResourceConflictError(key, current, resource);
|
|
397
|
+
this.deliveryResources.set(key, promoted);
|
|
398
|
+
return {
|
|
399
|
+
key,
|
|
400
|
+
resource: promoted
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
key,
|
|
405
|
+
resource: current
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
this.deliveryResources.set(key, resource);
|
|
409
|
+
return {
|
|
410
|
+
key,
|
|
411
|
+
resource
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
revealBlockerId(key, resource) {
|
|
415
|
+
if (resource.kind !== "stylesheet") return null;
|
|
416
|
+
if (resource.blocking === "none") return null;
|
|
417
|
+
return this.stylesheetIdFor(key);
|
|
418
|
+
}
|
|
419
|
+
stylesheetIdFor(key) {
|
|
420
|
+
const current = this.stylesheetIds.get(key);
|
|
421
|
+
if (current !== void 0) return current;
|
|
422
|
+
const id = this.identifierPrefix === "" ? `r-${this.nextStylesheetId}` : `${this.identifierPrefix}-r-${this.nextStylesheetId}`;
|
|
423
|
+
this.nextStylesheetId += 1;
|
|
424
|
+
this.stylesheetIds.set(key, id);
|
|
425
|
+
return id;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
var AssetResourceConflictError = class extends Error {
|
|
429
|
+
constructor(key, current, incoming) {
|
|
430
|
+
super(`Conflicting Fig resource for key "${key}". Existing: ${JSON.stringify(current)}. Incoming: ${JSON.stringify(incoming)}.`);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
function writeAssetTag(sink, resource, id) {
|
|
434
|
+
switch (resource.kind) {
|
|
435
|
+
case "title":
|
|
436
|
+
writeElementStart("title", {
|
|
437
|
+
[HYDRATION_SKIP_ATTRIBUTE]: true,
|
|
438
|
+
[STREAMED_METADATA_ATTRIBUTE]: sink.streamMetadata ? assetResourceKey(resource) : void 0
|
|
439
|
+
}, sink);
|
|
440
|
+
writeText(resource.value, sink);
|
|
441
|
+
writeElementEnd("title", sink);
|
|
442
|
+
return;
|
|
443
|
+
case "meta":
|
|
444
|
+
writeElementStart("meta", {
|
|
445
|
+
charset: resource.charset,
|
|
446
|
+
name: resource.name,
|
|
447
|
+
property: resource.property,
|
|
448
|
+
"http-equiv": resource["http-equiv"],
|
|
449
|
+
content: resource.content,
|
|
450
|
+
[HYDRATION_SKIP_ATTRIBUTE]: true,
|
|
451
|
+
[STREAMED_METADATA_ATTRIBUTE]: sink.streamMetadata ? assetResourceKey(resource) : void 0,
|
|
452
|
+
"data-fig-resource-key": resource.key
|
|
453
|
+
}, sink);
|
|
454
|
+
return;
|
|
455
|
+
default: {
|
|
456
|
+
const props = {
|
|
457
|
+
[HYDRATION_SKIP_ATTRIBUTE]: true,
|
|
458
|
+
...Object.fromEntries(assetResourceHostAttributes(resource))
|
|
459
|
+
};
|
|
460
|
+
if (resource.kind === "stylesheet" && id !== null) props.id = id;
|
|
461
|
+
const tag = resource.kind === "script" ? "script" : "link";
|
|
462
|
+
writeElementStart(tag, withNonce(sink, props), sink);
|
|
463
|
+
if (tag === "script") writeElementEnd("script", sink);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function isMetadataResource(resource) {
|
|
468
|
+
return resource.kind === "title" || resource.kind === "meta";
|
|
469
|
+
}
|
|
470
|
+
function metadataPhase(resource) {
|
|
471
|
+
if (resource.kind === "title") return "metadata";
|
|
472
|
+
if (resource.charset !== void 0) return "charset";
|
|
473
|
+
if (normalizedMetadataName(resource["http-equiv"]) === "content-security-policy") return "parser";
|
|
474
|
+
if (normalizedMetadataName(resource.name) === "viewport") return "viewport";
|
|
475
|
+
return "metadata";
|
|
476
|
+
}
|
|
477
|
+
function normalizedMetadataName(value) {
|
|
478
|
+
return value?.trim().toLowerCase();
|
|
479
|
+
}
|
|
480
|
+
function metadataAttributes(resource) {
|
|
481
|
+
return [
|
|
482
|
+
["charset", resource.charset],
|
|
483
|
+
["name", resource.name],
|
|
484
|
+
["property", resource.property],
|
|
485
|
+
["http-equiv", resource["http-equiv"]],
|
|
486
|
+
["content", resource.content],
|
|
487
|
+
["data-fig-resource-key", resource.key]
|
|
488
|
+
].filter((entry) => entry[1] !== void 0);
|
|
489
|
+
}
|
|
490
|
+
function withNonce(sink, props) {
|
|
491
|
+
return sink.nonce === void 0 ? props : {
|
|
492
|
+
...props,
|
|
493
|
+
nonce: sink.nonce
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
function assetSignature(resource) {
|
|
497
|
+
switch (resource.kind) {
|
|
498
|
+
case "stylesheet": return signature(resource.kind, resource.href, resource.media ?? "", resource.precedence ?? "", resource.crossorigin ?? "", resource.blocking ?? "reveal");
|
|
499
|
+
case "preload": {
|
|
500
|
+
const imagesrcset = resource.as === "image" ? resource.imagesrcset || void 0 : void 0;
|
|
501
|
+
return signature(resource.kind, imagesrcset === void 0 ? resource.href ?? "" : "", resource.as, resource.type ?? "", resource.crossorigin ?? "", resource.fetchpriority ?? "", imagesrcset ?? "", imagesrcset === void 0 ? "" : resource.imagesizes ?? "", resource.referrerpolicy ?? "");
|
|
502
|
+
}
|
|
503
|
+
case "modulepreload": return signature(resource.kind, resource.href, resource.crossorigin ?? "", resource.fetchpriority ?? "");
|
|
504
|
+
case "font": return signature("preload", resource.href, "font", resource.type, resource.crossorigin ?? "anonymous", resource.fetchpriority ?? "", "", "", "");
|
|
505
|
+
case "preconnect": return signature(resource.kind, resource.href, resource.crossorigin ?? "");
|
|
506
|
+
case "script": return signature(resource.kind, resource.src, resource.module === true, resource.async !== false, resource.defer === true, resource.crossorigin ?? "");
|
|
507
|
+
case "title": return signature(resource.kind, resource.value);
|
|
508
|
+
case "meta": return signature(resource.kind, resource.charset ?? "", resource.name ?? "", resource.property ?? "", resource["http-equiv"] ?? "", resource.content ?? "");
|
|
509
|
+
}
|
|
510
|
+
return unsupportedAssetResource(resource);
|
|
511
|
+
}
|
|
512
|
+
function promoteCompatibleImagePreload(current, incoming) {
|
|
513
|
+
if (current.kind !== "preload" || incoming.kind !== "preload" || current.as !== "image" || incoming.as !== "image" || assetSignature({
|
|
514
|
+
...current,
|
|
515
|
+
fetchpriority: incoming.fetchpriority
|
|
516
|
+
}) !== assetSignature(incoming)) return null;
|
|
517
|
+
const currentPriority = current.fetchpriority === "auto" ? void 0 : current.fetchpriority;
|
|
518
|
+
const incomingPriority = incoming.fetchpriority === "auto" ? void 0 : incoming.fetchpriority;
|
|
519
|
+
if (currentPriority === incomingPriority) return current;
|
|
520
|
+
if (currentPriority === "low" || incomingPriority === "low") return null;
|
|
521
|
+
return currentPriority === "high" ? current : {
|
|
522
|
+
...current,
|
|
523
|
+
fetchpriority: "high"
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function unsupportedAssetResource(resource) {
|
|
527
|
+
throw new Error(`Unsupported asset resource kind: ${resource.kind}`);
|
|
528
|
+
}
|
|
529
|
+
function signature(...values) {
|
|
530
|
+
return JSON.stringify(values);
|
|
531
|
+
}
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region src/protocol.ts
|
|
534
|
+
function serverRuntimeCodeFor(runtimeName) {
|
|
535
|
+
return `globalThis[${jsString(runtimeName)}]??={r(a,f){let n=0,d=()=>{--n||f()};for(let i of a){let e=document.getElementById(i);if(e&&e.tagName==='LINK'&&e.rel==='stylesheet'&&!e.sheet){n++;e.addEventListener('load',d,{once:true});e.addEventListener('error',d,{once:true})}}n||f()},q(e,a){if(e&&e.nodeType===1){if(e.hasAttribute&&e.hasAttribute('${VIEW_TRANSITION_NAME_ATTRIBUTE}'))a.push([e,e.getAttribute('${VIEW_TRANSITION_NAME_ATTRIBUTE}'),e.getAttribute('${VIEW_TRANSITION_CLASS_ATTRIBUTE}')]);if(e.querySelectorAll)for(let x of e.querySelectorAll('[${VIEW_TRANSITION_NAME_ATTRIBUTE}]'))a.push([x,x.getAttribute('${VIEW_TRANSITION_NAME_ATTRIBUTE}'),x.getAttribute('${VIEW_TRANSITION_CLASS_ATTRIBUTE}')])}},g(r){let a=[];this.q(r,a);return a},h(b){let a=[],d=0;for(let e=b;e;){if(e.nodeType===8){if(e.data.indexOf('${SUSPENSE_MARKER_PREFIX}')===0)d++;else if(e.data==='${SUSPENSE_END_MARKER}'){if(d===0)break;d--}}else this.q(e,a);e=e.nextSibling}return a},a(l){for(let x of l){let e=x[0],s=e.style;x[3]=s.viewTransitionName;x[4]=s.viewTransitionClass;s.viewTransitionName=x[1];if(x[2])s.viewTransitionClass=x[2]}},u(l){for(let x of l){let e=x[0],s=e.style;s.viewTransitionName=x[3]||'';s.viewTransitionClass=x[4]||'';!(e.getAttribute&&e.getAttribute('style'))&&e.removeAttribute&&e.removeAttribute('style')}},z(l){for(let f of l)f()},j(t,r){let p=t&&(t.ready||t.finished);p&&p.then?p.then(r,()=>{let f=t&&t.finished;f&&f.then?f.then(r,r):r()}):r()},v(b,s,f){let o=this.h(b),n=this.g(s);if(!o.length&&!n.length){f();return}let d=document,w=d.startViewTransition;if(typeof w!='function'){f();return}let p=d.${VIEW_TRANSITION_PENDING_PROPERTY},pw=p&&(p.finished||p.ready);if(pw&&pw.then){let q=0,i,g=()=>{if(q)return;q=1;clearTimeout(i);d.${VIEW_TRANSITION_PENDING_PROPERTY}===p&&(d.${VIEW_TRANSITION_PENDING_PROPERTY}=null);this.v(b,s,f)};i=setTimeout(g,${VIEW_TRANSITION_TIMEOUT_MS});pw.then(g,g);return}this.a(o);let m=0,l=[],r=()=>{this.u(o);this.u(n);this.z(l)};try{let t=w.call(d,()=>{m=1;f(l);this.a(n)});if(t){d.${VIEW_TRANSITION_PENDING_PROPERTY}=t;let c=()=>{d.${VIEW_TRANSITION_PENDING_PROPERTY}===t&&(d.${VIEW_TRANSITION_PENDING_PROPERTY}=null)},cw=t.finished||t.ready;cw&&cw.then?cw.then(c,c):c()}this.j(t,r)}catch(e){r();if(m)throw e;f()}},m(a){let h=document.head,e=new Map;for(let n of h.querySelectorAll('[${STREAMED_METADATA_ATTRIBUTE}]'))e.set(n.getAttribute('${STREAMED_METADATA_ATTRIBUTE}'),n);for(let d of a){let k=d[0],t=d[1],v=d[2],n=e.get(k);if(!n||n.tagName.toLowerCase()!==t){n&&n.remove();n=document.createElement(t);n.setAttribute('${STREAMED_METADATA_ATTRIBUTE}',k);n.setAttribute('${HYDRATION_SKIP_ATTRIBUTE}','');h.appendChild(n)}e.delete(k);if(t==='title')n.textContent=v;else{for(let x of Array.from(n.attributes))if(x.name!=='${STREAMED_METADATA_ATTRIBUTE}'&&x.name!=='${HYDRATION_SKIP_ATTRIBUTE}')n.removeAttribute(x.name);for(let x of v)n.setAttribute(x[0],x[1])}}for(let n of e.values())n.remove()},s(p,s){p=document.getElementById(p);s=document.getElementById(s);if(!p||!s)return;this.v(p,s,()=>{while(s.firstChild)p.parentNode.insertBefore(s.firstChild,p);p.remove();s.remove()})},f(r,i){if(!r)return null;if(r.id===i)return r;for(let e of r.querySelectorAll?r.querySelectorAll('[id]'):[])if(e.id===i)return e;return null},b(t,b){let e=document.getElementById(t),r=e&&(e.content||e);return this.f(r,b)||document.getElementById(b)},c(b,s,m){let x=document.getElementById(b),y=document.getElementById(s);this.v(x,y,r=>this.o(x,y,r,m))},o(b,s,l,m){if(!b||!s)return;let a=b.previousSibling||b,p=a.parentNode,c=s.content||s;if(!p)return;let r=a.nodeType===8&&a.__figRetry;if(!r&&m)this.m(m);while(c.firstChild)p.insertBefore(c.firstChild,b);for(let e=b,d=0;e;){if(e.nodeType===8){if(e.data.indexOf('${SUSPENSE_MARKER_PREFIX}')===0)d++;else if(e.data==='${SUSPENSE_END_MARKER}'){if(d===0)break;d--}}let x=e.nextSibling;e.remove();e=x}s.remove();if(a.nodeType===8){a.data='${SUSPENSE_COMPLETED_MARKER}';if(r){if(l)l.push(r);else r()}}},x(b,d,m){this.y(document.getElementById(b),d,m)},y(b,d,m){if(!b)return;let s=b.previousSibling;if(s&&s.nodeType===8){s.data='${SUSPENSE_CLIENT_MARKER}';if(d)b.dataset.dgst=d;if(m)b.dataset.msg=m;s.__figRetry&&s.__figRetry()}},ac(t,b,s,m){let x=this.b(t,b),y=document.getElementById(s);this.v(x,y,r=>this.o(x,y,r,m))},ax(t,b,d,m){this.y(this.b(t,b),d,m)}}`;
|
|
536
|
+
}
|
|
537
|
+
function writeRuntime$1(request, write) {
|
|
538
|
+
if (request.runtimeWritten) return;
|
|
539
|
+
request.runtimeWritten = true;
|
|
540
|
+
writeScript$1(request, serverRuntimeCodeFor(request.runtimeName), write);
|
|
541
|
+
}
|
|
542
|
+
function writeScript$1(request, code, write) {
|
|
543
|
+
write(`<script ${HYDRATION_SKIP_ATTRIBUTE}=""${nonceAttribute(request.nonce)}>${code}<\/script>`);
|
|
544
|
+
}
|
|
545
|
+
function earlyEventCaptureCode() {
|
|
546
|
+
return `(d=>{if(d.${EARLY_EVENT_QUEUE_PROPERTY})return;let q=d.${EARLY_EVENT_QUEUE_PROPERTY}=[],h=d.${EARLY_EVENT_HANDLER_PROPERTY}=e=>{q.push(e)};for(let t of [${REPLAYABLE_EVENT_TYPES.map((type) => `'${type}'`).join(",")}])d.addEventListener(t,h,!0)})(document)`;
|
|
547
|
+
}
|
|
548
|
+
function earlyEventCaptureMarkup(request) {
|
|
549
|
+
return `<script ${HYDRATION_SKIP_ATTRIBUTE}=""${nonceAttribute(request.nonce)}>${earlyEventCaptureCode()}<\/script>`;
|
|
550
|
+
}
|
|
551
|
+
function placeholderMarkup(request, id) {
|
|
552
|
+
return templateMarkup(placeholderId(request, id));
|
|
553
|
+
}
|
|
554
|
+
function boundaryPlaceholderMarkup(request, id) {
|
|
555
|
+
return templateMarkup(boundaryId(request, id));
|
|
556
|
+
}
|
|
557
|
+
function templateMarkup(id) {
|
|
558
|
+
return `<template id="${escapeAttribute(id)}"></template>`;
|
|
559
|
+
}
|
|
560
|
+
function segmentContainerStartMarkup(request, id) {
|
|
561
|
+
return `<div hidden id="${escapeAttribute(segmentId(request, id))}">`;
|
|
562
|
+
}
|
|
563
|
+
function activityId(request, id) {
|
|
564
|
+
return prefixedId(request, "a", id);
|
|
565
|
+
}
|
|
566
|
+
function placeholderId(request, id) {
|
|
567
|
+
return prefixedId(request, "p", id);
|
|
568
|
+
}
|
|
569
|
+
function segmentId(request, id) {
|
|
570
|
+
return prefixedId(request, "s", id);
|
|
571
|
+
}
|
|
572
|
+
function boundaryId(request, id) {
|
|
573
|
+
return prefixedId(request, "b", id);
|
|
574
|
+
}
|
|
575
|
+
function jsString(value) {
|
|
576
|
+
return escapeScriptJson(value);
|
|
577
|
+
}
|
|
578
|
+
function prefixedId(request, kind, id) {
|
|
579
|
+
return request.identifierPrefix === "" ? `${kind}-${id}` : `${request.identifierPrefix}-${kind}-${id}`;
|
|
580
|
+
}
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/renderer-flush.ts
|
|
583
|
+
const documentHeadMarker = Symbol("fig.document-head");
|
|
584
|
+
const leadingNewlineStartMarker = Symbol("fig.leading-newline-start");
|
|
585
|
+
const leadingNewlineEndMarker = Symbol("fig.leading-newline-end");
|
|
586
|
+
const RUNTIME_REF = "__figSSR";
|
|
587
|
+
const textEncoder = new TextEncoder();
|
|
588
|
+
function flushCompletedQueues(request) {
|
|
589
|
+
if (request.controller === null || request.status === "closed") return;
|
|
590
|
+
if (request.pendingRootTasks > 0) return;
|
|
591
|
+
if (request.prerender && request.pendingTasks > 0) return;
|
|
592
|
+
if (request.flushing) return;
|
|
593
|
+
request.flushing = true;
|
|
594
|
+
try {
|
|
595
|
+
sealHead(request);
|
|
596
|
+
if (request.completedRootSegment !== null) {
|
|
597
|
+
flushSegment(request, request.completedRootSegment);
|
|
598
|
+
request.completedRootSegment = null;
|
|
599
|
+
flushWriteBuffer(request);
|
|
600
|
+
}
|
|
601
|
+
if (!drainBoundaryQueue(request, request.clientRenderedBoundaries, flushClientRenderedBoundary) && !drainBoundaryQueue(request, request.completedBoundaries, flushCompletedBoundary)) drainBoundaryQueue(request, request.partialBoundaries, flushPartialBoundary);
|
|
602
|
+
flushWriteBuffer(request);
|
|
603
|
+
} finally {
|
|
604
|
+
request.flushing = false;
|
|
605
|
+
}
|
|
606
|
+
if (request.pendingTasks === 0 && request.completedBoundaries.size === 0 && request.clientRenderedBoundaries.size === 0 && request.partialBoundaries.size === 0) {
|
|
607
|
+
request.cleanupAbortListener();
|
|
608
|
+
request.status = "closed";
|
|
609
|
+
request.dataStore.dispose();
|
|
610
|
+
request.controller.close();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
function sealHead(request) {
|
|
614
|
+
if (request.headSnapshot !== null) return;
|
|
615
|
+
activateVisibleMetadata(request, request.rootSegment);
|
|
616
|
+
const metadata = request.assetRegistry.headMetadataHtml(request.nonce, !request.prerender && request.pendingTasks > 0);
|
|
617
|
+
request.headSnapshot = {
|
|
618
|
+
...metadata,
|
|
619
|
+
preloadHeaderEntries: request.assetRegistry.preloadHeaderEntries()
|
|
620
|
+
};
|
|
621
|
+
request.headReady.resolve(metadata.preamble + metadata.metadata);
|
|
622
|
+
}
|
|
623
|
+
function flushSegment(request, segment) {
|
|
624
|
+
if (segment.status === "flushed") return;
|
|
625
|
+
if (segment.boundary !== null) {
|
|
626
|
+
flushSuspenseBoundary(request, segment, segment.boundary);
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
flushSubtree(request, segment);
|
|
630
|
+
}
|
|
631
|
+
function flushSubtree(request, segment) {
|
|
632
|
+
segment.parentFlushed = true;
|
|
633
|
+
if (segment.status === "pending" || segment.status === "rendering") {
|
|
634
|
+
request.write(placeholderMarkup(request, ensureSegmentId(request, segment)));
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (segment.status === "flushed") return;
|
|
638
|
+
segment.status = "flushed";
|
|
639
|
+
if (request.document === null || segment !== request.rootSegment) flushSegmentAssets(request, segment);
|
|
640
|
+
let chunkIndex = 0;
|
|
641
|
+
for (const child of segment.children) {
|
|
642
|
+
for (; chunkIndex < child.index; chunkIndex += 1) writeChunk(request, segment.chunks[chunkIndex], segment);
|
|
643
|
+
flushSegment(request, child);
|
|
644
|
+
}
|
|
645
|
+
for (; chunkIndex < segment.chunks.length; chunkIndex += 1) writeChunk(request, segment.chunks[chunkIndex], segment);
|
|
646
|
+
}
|
|
647
|
+
function flushSuspenseBoundary(request, segment, boundary) {
|
|
648
|
+
boundary.parentFlushed = true;
|
|
649
|
+
if (boundary.status === "completed") {
|
|
650
|
+
request.write(`<!--${SUSPENSE_COMPLETED_MARKER}-->`);
|
|
651
|
+
flushBoundaryContent(request, boundary);
|
|
652
|
+
request.write(`<!--${SUSPENSE_END_MARKER}-->`);
|
|
653
|
+
segment.status = "flushed";
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (request.prerender && boundary.status === "client-rendered") {
|
|
657
|
+
request.write(`<!--${SUSPENSE_CLIENT_MARKER}-->`);
|
|
658
|
+
request.write(clientRenderedBoundaryPlaceholderMarkup(request, boundary));
|
|
659
|
+
flushSubtree(request, segment);
|
|
660
|
+
request.write(`<!--${SUSPENSE_END_MARKER}-->`);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
const boundaryIdValue = ensureBoundaryId(request, boundary);
|
|
664
|
+
flushSegmentAssets(request, boundary.contentSegment);
|
|
665
|
+
request.write(`<!--${SUSPENSE_PENDING_PREFIX}${boundaryIdValue}-->`);
|
|
666
|
+
request.write(boundaryPlaceholderMarkup(request, boundaryIdValue));
|
|
667
|
+
flushSubtree(request, segment);
|
|
668
|
+
request.write(`<!--${SUSPENSE_END_MARKER}-->`);
|
|
669
|
+
if (boundary.status === "client-rendered") request.clientRenderedBoundaries.add(boundary);
|
|
670
|
+
else if (boundary.completedSegments.length > 0) request.partialBoundaries.add(boundary);
|
|
671
|
+
}
|
|
672
|
+
function flushBoundaryContent(request, boundary) {
|
|
673
|
+
for (const segment of boundary.completedSegments) flushSegment(request, segment);
|
|
674
|
+
boundary.completedSegments = [];
|
|
675
|
+
}
|
|
676
|
+
function clientRenderedBoundaryPlaceholderMarkup(request, boundary) {
|
|
677
|
+
const id = escapeAttribute(boundaryId(request, ensureBoundaryId(request, boundary)));
|
|
678
|
+
const digest = boundary.error?.digest;
|
|
679
|
+
const message = boundary.error?.message;
|
|
680
|
+
return `<template id="${id}"${digest === void 0 || digest === "" ? "" : ` data-dgst="${escapeAttribute(digest)}"`}${message === void 0 || message === "" ? "" : ` data-msg="${escapeAttribute(message)}"`}></template>`;
|
|
681
|
+
}
|
|
682
|
+
function flushCompletedBoundary(request, boundary) {
|
|
683
|
+
flushPartialBoundary(request, boundary);
|
|
684
|
+
writeBoundaryRevealScript(request, boundary);
|
|
685
|
+
}
|
|
686
|
+
function flushPartialBoundary(request, boundary) {
|
|
687
|
+
for (const segment of boundary.completedSegments) flushBoundarySegment(request, boundary, segment);
|
|
688
|
+
boundary.completedSegments = [];
|
|
689
|
+
}
|
|
690
|
+
function flushBoundarySegment(request, boundary, segment) {
|
|
691
|
+
ensureBoundaryId(request, boundary);
|
|
692
|
+
const blockingIds = flushSegmentContainer(request, segment);
|
|
693
|
+
if (segment !== boundary.contentSegment) writeSegmentRevealScript(request, segment, blockingIds);
|
|
694
|
+
}
|
|
695
|
+
function writeSegmentRevealScript(request, segment, blockingIds) {
|
|
696
|
+
const id = ensureSegmentId(request, segment);
|
|
697
|
+
writeRuntime(request);
|
|
698
|
+
writeScript(request, withAssetGate(blockingIds, `${RUNTIME_REF}.s(${jsString(placeholderId(request, id))},${jsString(segmentId(request, id))})`));
|
|
699
|
+
}
|
|
700
|
+
function writeBoundaryRevealScript(request, boundary) {
|
|
701
|
+
const blockingIds = flushSegmentAssets(request, boundary.contentSegment);
|
|
702
|
+
const metadata = switchBoundaryMetadata(request, boundary);
|
|
703
|
+
const metadataArgument = metadata === null ? "" : `,${metadata}`;
|
|
704
|
+
writeRuntime(request);
|
|
705
|
+
const boundaryRef = jsString(boundaryId(request, ensureBoundaryId(request, boundary)));
|
|
706
|
+
const contentRef = jsString(segmentId(request, ensureSegmentId(request, boundary.contentSegment)));
|
|
707
|
+
writeScript(request, withAssetGate(blockingIds, boundary.activityId === null ? `${RUNTIME_REF}.c(${boundaryRef},${contentRef}${metadataArgument})` : `${RUNTIME_REF}.ac(${jsString(boundary.activityId)},${boundaryRef},${contentRef}${metadataArgument})`));
|
|
708
|
+
}
|
|
709
|
+
function switchBoundaryMetadata(request, boundary) {
|
|
710
|
+
if (!boundary.metadataVisible) return null;
|
|
711
|
+
const before = escapeScriptJson(request.assetRegistry.metadataSnapshot());
|
|
712
|
+
const fallback = boundary.fallbackSegment;
|
|
713
|
+
if (fallback !== null) {
|
|
714
|
+
request.assetRegistry.releaseMetadata(fallback);
|
|
715
|
+
for (const child of fallback.children) deactivateMetadataTree(request, child);
|
|
716
|
+
}
|
|
717
|
+
activateVisibleMetadata(request, boundary.contentSegment);
|
|
718
|
+
const after = escapeScriptJson(request.assetRegistry.metadataSnapshot());
|
|
719
|
+
return before === after ? null : after;
|
|
720
|
+
}
|
|
721
|
+
function activateVisibleMetadata(request, segment) {
|
|
722
|
+
if (segment.status === "pending" || segment.status === "rendering") return;
|
|
723
|
+
const boundary = segment.boundary;
|
|
724
|
+
if (boundary !== null) {
|
|
725
|
+
boundary.metadataVisible = true;
|
|
726
|
+
if (boundary.status === "completed") {
|
|
727
|
+
activateVisibleMetadata(request, boundary.contentSegment);
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
request.assetRegistry.activateMetadata(segment, segment.assetResources);
|
|
732
|
+
for (const child of segment.children) activateVisibleMetadata(request, child);
|
|
733
|
+
}
|
|
734
|
+
function deactivateMetadataTree(request, segment) {
|
|
735
|
+
request.assetRegistry.releaseMetadata(segment);
|
|
736
|
+
for (const child of segment.children) deactivateMetadataTree(request, child);
|
|
737
|
+
const boundary = segment.boundary;
|
|
738
|
+
if (boundary === null) return;
|
|
739
|
+
boundary.metadataVisible = false;
|
|
740
|
+
deactivateMetadataTree(request, boundary.contentSegment);
|
|
741
|
+
}
|
|
742
|
+
function flushSegmentContainer(request, segment) {
|
|
743
|
+
if (segment.status === "flushed") return [];
|
|
744
|
+
const blockingIds = flushSegmentAssets(request, segment);
|
|
745
|
+
request.write(segmentContainerStartMarkup(request, ensureSegmentId(request, segment)));
|
|
746
|
+
flushSegment(request, segment);
|
|
747
|
+
request.write("</div>");
|
|
748
|
+
return blockingIds;
|
|
749
|
+
}
|
|
750
|
+
function flushSegmentAssets(request, segment) {
|
|
751
|
+
const blockingIds = /* @__PURE__ */ new Set();
|
|
752
|
+
collectSegmentAssets(request, segment, blockingIds);
|
|
753
|
+
return [...blockingIds];
|
|
754
|
+
}
|
|
755
|
+
function collectSegmentAssets(request, segment, blockingIds) {
|
|
756
|
+
if (segment.status !== "pending" && segment.status !== "rendering") flushAssetList(request, segment.assetResources, blockingIds);
|
|
757
|
+
for (const child of segment.children) collectSegmentAssets(request, child, blockingIds);
|
|
758
|
+
}
|
|
759
|
+
function flushAssetList(request, resources, blockingIds) {
|
|
760
|
+
for (const resource of resources) {
|
|
761
|
+
const id = request.assetRegistry.write(resource, request);
|
|
762
|
+
if (id !== null) blockingIds.add(id);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
function withAssetGate(blockingIds, call) {
|
|
766
|
+
if (blockingIds.length === 0) return call;
|
|
767
|
+
return `${RUNTIME_REF}.r([${blockingIds.map(jsString).join(",")}],()=>{${call}})`;
|
|
768
|
+
}
|
|
769
|
+
function flushClientRenderedBoundary(request, boundary) {
|
|
770
|
+
if (boundary.id === null) return;
|
|
771
|
+
writeRuntime(request);
|
|
772
|
+
const boundaryRef = jsString(boundaryId(request, boundary.id));
|
|
773
|
+
const digest = jsString(boundary.error?.digest ?? "");
|
|
774
|
+
const message = jsString(boundary.error?.message ?? "");
|
|
775
|
+
writeScript(request, boundary.activityId === null ? `${RUNTIME_REF}.x(${boundaryRef},${digest},${message})` : `${RUNTIME_REF}.ax(${jsString(boundary.activityId)},${boundaryRef},${digest},${message})`);
|
|
776
|
+
}
|
|
777
|
+
function drainBoundaryQueue(request, queue, flush) {
|
|
778
|
+
for (;;) {
|
|
779
|
+
if (streamFlowBlocked(request.controller)) return true;
|
|
780
|
+
const first = queue.values().next();
|
|
781
|
+
if (first.done === true) return false;
|
|
782
|
+
flush(request, first.value);
|
|
783
|
+
queue.delete(first.value);
|
|
784
|
+
flushWriteBuffer(request);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
function writeRuntime(request) {
|
|
788
|
+
writeRuntime$1(request, (chunk) => request.write(chunk));
|
|
789
|
+
}
|
|
790
|
+
function writeScript(request, code) {
|
|
791
|
+
writeScript$1(request, `(__figSSR=>{${code}})(globalThis[${jsString(request.runtimeName)}])`, (chunk) => request.write(chunk));
|
|
792
|
+
}
|
|
793
|
+
function writeChunk(request, chunk, segment) {
|
|
794
|
+
if (chunk === leadingNewlineStartMarker) {
|
|
795
|
+
request.leadingNewlineStack.push(false);
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
if (chunk === leadingNewlineEndMarker) {
|
|
799
|
+
request.leadingNewlineStack.pop();
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (typeof chunk === "object") {
|
|
803
|
+
request.write(request.leadingNewlineStack.at(-1) === false && chunk.value.startsWith("\n") ? `\n${chunk.value}` : chunk.value);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (chunk !== documentHeadMarker) {
|
|
807
|
+
request.write(chunk);
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
if (request.document === null) return;
|
|
811
|
+
const metadata = request.headSnapshot ?? request.assetRegistry.headMetadataHtml(request.nonce);
|
|
812
|
+
const [beforeMetadata, afterMetadata] = partitionHeadAssets(request, segment.assetResources);
|
|
813
|
+
const blockingIds = /* @__PURE__ */ new Set();
|
|
814
|
+
request.write(metadata.preamble);
|
|
815
|
+
flushAssetList(request, beforeMetadata, blockingIds);
|
|
816
|
+
request.write(metadata.metadata);
|
|
817
|
+
flushAssetList(request, afterMetadata, blockingIds);
|
|
818
|
+
}
|
|
819
|
+
function partitionHeadAssets(request, resources) {
|
|
820
|
+
const preconnects = [];
|
|
821
|
+
const criticalPreloads = [];
|
|
822
|
+
const stylesheets = [];
|
|
823
|
+
const afterMetadata = [];
|
|
824
|
+
for (const resource of resources) if (resource.kind === "preconnect") preconnects.push(resource);
|
|
825
|
+
else if (resource.kind === "font" || resource.kind === "preload" && (resource.as === "font" || resource.as === "image" && (resource.fetchpriority === "high" || request.assetRegistry.isEarlyImage(resource)))) criticalPreloads.push(resource);
|
|
826
|
+
else if (resource.kind === "stylesheet") stylesheets.push(resource);
|
|
827
|
+
else afterMetadata.push(resource);
|
|
828
|
+
return [[
|
|
829
|
+
...preconnects,
|
|
830
|
+
...criticalPreloads,
|
|
831
|
+
...stylesheets
|
|
832
|
+
], afterMetadata];
|
|
833
|
+
}
|
|
834
|
+
function flushWriteBuffer(request) {
|
|
835
|
+
if (request.writeBuffer.length === 0 || request.controller === null) return;
|
|
836
|
+
request.controller.enqueue(textEncoder.encode(request.writeBuffer.join("")));
|
|
837
|
+
request.writeBuffer = [];
|
|
838
|
+
}
|
|
839
|
+
function ensureSegmentId(request, segment) {
|
|
840
|
+
segment.id ??= request.nextSegmentId++;
|
|
841
|
+
return segment.id;
|
|
842
|
+
}
|
|
843
|
+
function ensureBoundaryId(request, boundary) {
|
|
844
|
+
boundary.id ??= request.nextBoundaryId++;
|
|
845
|
+
return boundary.id;
|
|
846
|
+
}
|
|
847
|
+
//#endregion
|
|
848
|
+
//#region src/renderer.ts
|
|
849
|
+
const errorStacks = /* @__PURE__ */ new WeakMap();
|
|
850
|
+
const TEXT_SEPARATOR = `<!--${TEXT_SEPARATOR_DATA}-->`;
|
|
851
|
+
let nextRuntimeId = 0;
|
|
852
|
+
function createServerRenderRequest(node, options = {}, mode = {}) {
|
|
853
|
+
throwIfAborted(options.signal);
|
|
854
|
+
const shellReady = deferred();
|
|
855
|
+
const headReady = deferred();
|
|
856
|
+
const allReady = deferred();
|
|
857
|
+
shellReady.promise.catch(() => void 0);
|
|
858
|
+
headReady.promise.catch(() => void 0);
|
|
859
|
+
allReady.promise.catch(() => void 0);
|
|
860
|
+
const rootSegment = createSegment(0, null);
|
|
861
|
+
const dataStoreHost = {
|
|
862
|
+
getLane: () => null,
|
|
863
|
+
partition: options.dataPartition,
|
|
864
|
+
schedule: () => void 0
|
|
865
|
+
};
|
|
866
|
+
const dataStore = options.dataStore === void 0 ? createRendererDataStore(dataStoreHost) : attachDataStore(options.dataStore, dataStoreHost, options.initialData);
|
|
867
|
+
const request = {
|
|
868
|
+
abortableTasks: /* @__PURE__ */ new Set(),
|
|
869
|
+
allReady,
|
|
870
|
+
cleanupAbortListener: () => void 0,
|
|
871
|
+
completedBoundaries: /* @__PURE__ */ new Set(),
|
|
872
|
+
completedRootSegment: null,
|
|
873
|
+
controller: null,
|
|
874
|
+
dataStore,
|
|
875
|
+
fatalError: null,
|
|
876
|
+
identifierPrefix: options.identifierPrefix ?? "",
|
|
877
|
+
leadingNewlineStack: [],
|
|
878
|
+
nextBoundaryId: 0,
|
|
879
|
+
nextSegmentId: 0,
|
|
880
|
+
nextActivityId: 0,
|
|
881
|
+
nextViewTransitionId: 0,
|
|
882
|
+
nonce: options.nonce,
|
|
883
|
+
onError: options.onError,
|
|
884
|
+
pendingRootTasks: 0,
|
|
885
|
+
pendingTasks: 0,
|
|
886
|
+
pingedTasks: [],
|
|
887
|
+
rootSegment,
|
|
888
|
+
runtimeName: createRuntimeName(options.identifierPrefix),
|
|
889
|
+
runtimeWritten: false,
|
|
890
|
+
headReady,
|
|
891
|
+
headSnapshot: null,
|
|
892
|
+
shellReady,
|
|
893
|
+
status: "open",
|
|
894
|
+
clientRenderedBoundaries: /* @__PURE__ */ new Set(),
|
|
895
|
+
clientReferenceFallback: options.clientReferenceFallback,
|
|
896
|
+
partialBoundaries: /* @__PURE__ */ new Set(),
|
|
897
|
+
prerender: mode.prerender === true,
|
|
898
|
+
componentAssets: options.assets,
|
|
899
|
+
document: mode.document === true ? { hasHead: false } : null,
|
|
900
|
+
assetRegistry: new AssetResourceRegistry(options.identifierPrefix ?? ""),
|
|
901
|
+
resolveAssetKey: options.resolveAssetKey,
|
|
902
|
+
workScheduled: false,
|
|
903
|
+
flushing: false,
|
|
904
|
+
writeBuffer: [],
|
|
905
|
+
write(chunk) {
|
|
906
|
+
if (chunk !== "" && this.leadingNewlineStack.length > 0) this.leadingNewlineStack[this.leadingNewlineStack.length - 1] = true;
|
|
907
|
+
this.writeBuffer.push(chunk);
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
if (options.dataStore === void 0 && options.initialData !== void 0) request.dataStore.hydrate(options.initialData);
|
|
911
|
+
rootSegment.parentFlushed = true;
|
|
912
|
+
const rootTask = createTask(request, node, rootSegment, {
|
|
913
|
+
abortSet: request.abortableTasks,
|
|
914
|
+
boundary: null,
|
|
915
|
+
contextValues: /* @__PURE__ */ new Map(),
|
|
916
|
+
hiddenActivityId: null,
|
|
917
|
+
hostAncestors: [],
|
|
918
|
+
hostNamespace: "html",
|
|
919
|
+
imagePreloadsSuppressed: false,
|
|
920
|
+
idPath: "",
|
|
921
|
+
pendingLeadingNewline: false,
|
|
922
|
+
selectProps: null,
|
|
923
|
+
stack: null,
|
|
924
|
+
treeParent: options.renderTree?.tree ?? null,
|
|
925
|
+
viewTransition: null
|
|
926
|
+
});
|
|
927
|
+
request.pingedTasks.push(rootTask);
|
|
928
|
+
const stream = new ReadableStream({
|
|
929
|
+
start(streamController) {
|
|
930
|
+
request.controller = streamController;
|
|
931
|
+
flushCompletedQueues(request);
|
|
932
|
+
},
|
|
933
|
+
pull() {
|
|
934
|
+
flushCompletedQueues(request);
|
|
935
|
+
},
|
|
936
|
+
cancel(reason) {
|
|
937
|
+
request.controller = null;
|
|
938
|
+
request.writeBuffer = [];
|
|
939
|
+
abort(request, reason);
|
|
940
|
+
request.status = "closed";
|
|
941
|
+
}
|
|
942
|
+
}, new ByteLengthQueuingStrategy({ highWaterMark: streamHighWaterMark(options.highWaterMark) }));
|
|
943
|
+
if (options.signal !== void 0) {
|
|
944
|
+
const signal = options.signal;
|
|
945
|
+
const abortListener = () => abort(request, signal.reason);
|
|
946
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
947
|
+
request.cleanupAbortListener = () => {
|
|
948
|
+
signal.removeEventListener("abort", abortListener);
|
|
949
|
+
request.cleanupAbortListener = () => void 0;
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
request.workScheduled = true;
|
|
953
|
+
queueMicrotask(() => {
|
|
954
|
+
request.workScheduled = false;
|
|
955
|
+
performWork(request);
|
|
956
|
+
});
|
|
957
|
+
return {
|
|
958
|
+
abort: (reason) => abort(request, reason),
|
|
959
|
+
allReady: allReady.promise,
|
|
960
|
+
contentType: "text/html; charset=utf-8",
|
|
961
|
+
data: request.dataStore,
|
|
962
|
+
getData: () => request.dataStore.snapshot(),
|
|
963
|
+
getPreloadHeader: (headerOptions) => request.headSnapshot === null ? void 0 : formatPreloadHeader(request.headSnapshot.preloadHeaderEntries, headerOptions),
|
|
964
|
+
getHead: () => {
|
|
965
|
+
const snapshot = request.headSnapshot;
|
|
966
|
+
return snapshot === null ? request.assetRegistry.headHtml(request.nonce) : snapshot.preamble + snapshot.metadata;
|
|
967
|
+
},
|
|
968
|
+
headReady: headReady.promise,
|
|
969
|
+
shellReady: shellReady.promise,
|
|
970
|
+
stream
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function createTask(request, node, segment, scope, childIndexBase = 0) {
|
|
974
|
+
request.pendingTasks += 1;
|
|
975
|
+
if (scope.boundary === null) request.pendingRootTasks += 1;
|
|
976
|
+
else scope.boundary.pendingTasks += 1;
|
|
977
|
+
const task = {
|
|
978
|
+
...scope,
|
|
979
|
+
childIndexBase,
|
|
980
|
+
node,
|
|
981
|
+
segment
|
|
982
|
+
};
|
|
983
|
+
request.abortableTasks.add(task);
|
|
984
|
+
scope.abortSet.add(task);
|
|
985
|
+
return task;
|
|
986
|
+
}
|
|
987
|
+
function forkScope(scope) {
|
|
988
|
+
return {
|
|
989
|
+
abortSet: scope.abortSet,
|
|
990
|
+
boundary: scope.boundary,
|
|
991
|
+
contextValues: cloneContextValues(scope.contextValues),
|
|
992
|
+
hiddenActivityId: scope.hiddenActivityId,
|
|
993
|
+
hostAncestors: scope.hostAncestors,
|
|
994
|
+
hostNamespace: scope.hostNamespace,
|
|
995
|
+
imagePreloadsSuppressed: scope.imagePreloadsSuppressed,
|
|
996
|
+
idPath: scope.idPath,
|
|
997
|
+
pendingLeadingNewline: scope.pendingLeadingNewline,
|
|
998
|
+
selectProps: scope.selectProps,
|
|
999
|
+
stack: scope.stack,
|
|
1000
|
+
treeParent: scope.treeParent,
|
|
1001
|
+
viewTransition: scope.viewTransition === null ? null : { ...scope.viewTransition }
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
function createSegment(index, boundary, textSeams = {
|
|
1005
|
+
lastPushedText: false,
|
|
1006
|
+
textEmbedded: false
|
|
1007
|
+
}) {
|
|
1008
|
+
return {
|
|
1009
|
+
boundary,
|
|
1010
|
+
children: [],
|
|
1011
|
+
chunks: [],
|
|
1012
|
+
id: null,
|
|
1013
|
+
index,
|
|
1014
|
+
lastPushedText: textSeams.lastPushedText,
|
|
1015
|
+
parentFlushed: false,
|
|
1016
|
+
assetResources: [],
|
|
1017
|
+
status: "pending",
|
|
1018
|
+
textEmbedded: textSeams.textEmbedded,
|
|
1019
|
+
write(chunk) {
|
|
1020
|
+
this.lastPushedText = false;
|
|
1021
|
+
this.chunks.push(chunk);
|
|
1022
|
+
}
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
function createBoundary(fallbackAbortableTasks, contentSegment) {
|
|
1026
|
+
return {
|
|
1027
|
+
activityId: null,
|
|
1028
|
+
completedSegments: [],
|
|
1029
|
+
contentSegment,
|
|
1030
|
+
error: null,
|
|
1031
|
+
fallbackSegment: null,
|
|
1032
|
+
fallbackAbortableTasks,
|
|
1033
|
+
id: null,
|
|
1034
|
+
parentFlushed: false,
|
|
1035
|
+
pendingTasks: 0,
|
|
1036
|
+
status: "pending",
|
|
1037
|
+
metadataVisible: false
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
function performWork(request) {
|
|
1041
|
+
if (request.status === "closed") return;
|
|
1042
|
+
const tasks = request.pingedTasks;
|
|
1043
|
+
request.pingedTasks = [];
|
|
1044
|
+
for (const task of tasks) retryTask(request, task);
|
|
1045
|
+
flushCompletedQueues(request);
|
|
1046
|
+
}
|
|
1047
|
+
function retryTask(request, task) {
|
|
1048
|
+
if (task.segment.status !== "pending") return;
|
|
1049
|
+
task.segment.status = "rendering";
|
|
1050
|
+
const frame = createRenderFrame(request, task.segment, forkScope(task));
|
|
1051
|
+
try {
|
|
1052
|
+
renderChildSequence(collectChildren(task.node), frame, task.childIndexBase);
|
|
1053
|
+
completeSegmentText(task.segment);
|
|
1054
|
+
task.segment.status = "completed";
|
|
1055
|
+
detachTask(request, task);
|
|
1056
|
+
finishedTask(request, task);
|
|
1057
|
+
} catch (error) {
|
|
1058
|
+
detachTask(request, task);
|
|
1059
|
+
task.segment.status = "completed";
|
|
1060
|
+
erroredTask(request, task, error);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
function createRenderFrame(request, segment, scope) {
|
|
1064
|
+
return {
|
|
1065
|
+
...scope,
|
|
1066
|
+
dispatcher: null,
|
|
1067
|
+
localIdCounter: 0,
|
|
1068
|
+
request,
|
|
1069
|
+
segment
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
function createServerDispatcher(frame) {
|
|
1073
|
+
return createStaticDispatcher({
|
|
1074
|
+
contextValues: frame.contextValues,
|
|
1075
|
+
externalStoreError: "useSyncExternalStore requires getServerSnapshot during server render.",
|
|
1076
|
+
readPromise(promise) {
|
|
1077
|
+
throwIfAborting(frame.request);
|
|
1078
|
+
return readThenable(promise);
|
|
1079
|
+
},
|
|
1080
|
+
readData(resource, args) {
|
|
1081
|
+
throwIfAborting(frame.request);
|
|
1082
|
+
return frame.request.dataStore.readData(resource, args, frame);
|
|
1083
|
+
},
|
|
1084
|
+
preloadData(resource, args) {
|
|
1085
|
+
throwIfAborting(frame.request);
|
|
1086
|
+
frame.request.dataStore.preloadData(resource, ...args);
|
|
1087
|
+
},
|
|
1088
|
+
useId() {
|
|
1089
|
+
const id = `${frame.request.identifierPrefix}fig-${frame.idPath}-${frame.localIdCounter.toString(32)}`;
|
|
1090
|
+
frame.localIdCounter += 1;
|
|
1091
|
+
return id;
|
|
1092
|
+
},
|
|
1093
|
+
updateError: "State updates are not allowed during server render."
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
function renderNode(node, frame) {
|
|
1097
|
+
if (Array.isArray(node)) {
|
|
1098
|
+
renderChildren(node, frame);
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
if (node === null || node === void 0 || typeof node === "boolean") return;
|
|
1102
|
+
if (typeof node === "string" || typeof node === "number") {
|
|
1103
|
+
const text = String(node);
|
|
1104
|
+
if (frame.request.document !== null && !frame.request.document.hasHead) {
|
|
1105
|
+
if (text.trim() !== "") throw invalidDocumentShellError();
|
|
1106
|
+
}
|
|
1107
|
+
if (frame.hostNamespace === "html") validateTextNesting(text, frame.hostAncestors);
|
|
1108
|
+
if (text !== "") {
|
|
1109
|
+
if (frame.treeParent !== null) frame.treeParent.children.push({
|
|
1110
|
+
children: [],
|
|
1111
|
+
key: null,
|
|
1112
|
+
kind: "text",
|
|
1113
|
+
name: "#text",
|
|
1114
|
+
props: { nodeValue: text }
|
|
1115
|
+
});
|
|
1116
|
+
if (frame.segment.lastPushedText) frame.segment.write(TEXT_SEPARATOR);
|
|
1117
|
+
if (consumePendingLeadingNewline(frame)) writeLeadingNewlineText(text, frame.segment);
|
|
1118
|
+
else writeText(text, frame.segment);
|
|
1119
|
+
frame.segment.lastPushedText = true;
|
|
1120
|
+
}
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
if (isPortal(node)) return;
|
|
1124
|
+
if (isValidElement(node)) {
|
|
1125
|
+
renderElement(node, frame);
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
if (isThenable(node)) {
|
|
1129
|
+
renderChildren(readThenable(node), frame);
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
throw invalidChildError(node);
|
|
1133
|
+
}
|
|
1134
|
+
function renderChildren(node, frame) {
|
|
1135
|
+
renderChildSequence(collectChildren(node), frame);
|
|
1136
|
+
}
|
|
1137
|
+
function renderChildSequence(children, frame, indexBase = 0) {
|
|
1138
|
+
for (let index = 0; index < children.length; index += 1) {
|
|
1139
|
+
const child = children[index];
|
|
1140
|
+
try {
|
|
1141
|
+
withIdSegment(frame, indexBase + index, () => renderNode(child, frame));
|
|
1142
|
+
} catch (error) {
|
|
1143
|
+
if (isThenable(error)) {
|
|
1144
|
+
spawnSuspendedTask(frame, child, error, indexBase + index);
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
throw error;
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
function completeSegmentText(segment) {
|
|
1152
|
+
if (segment.textEmbedded && segment.lastPushedText) segment.write(TEXT_SEPARATOR);
|
|
1153
|
+
}
|
|
1154
|
+
function withIdSegment(frame, index, callback) {
|
|
1155
|
+
const previousIdPath = frame.idPath;
|
|
1156
|
+
const segment = index.toString(32);
|
|
1157
|
+
frame.idPath = previousIdPath === "" ? segment : `${previousIdPath}-${segment}`;
|
|
1158
|
+
try {
|
|
1159
|
+
return callback();
|
|
1160
|
+
} finally {
|
|
1161
|
+
frame.idPath = previousIdPath;
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
function renderElement(element, frame) {
|
|
1165
|
+
if (frame.treeParent === null) {
|
|
1166
|
+
renderElementKind(element, frame);
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
const treeNode = collectedTreeNode(element);
|
|
1170
|
+
frame.treeParent.children.push(treeNode);
|
|
1171
|
+
const previousTreeParent = frame.treeParent;
|
|
1172
|
+
frame.treeParent = treeNode;
|
|
1173
|
+
try {
|
|
1174
|
+
renderElementKind(element, frame);
|
|
1175
|
+
} finally {
|
|
1176
|
+
frame.treeParent = previousTreeParent;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
function collectedTreeNode(element) {
|
|
1180
|
+
const { children: _children, ...ownProps } = element.props;
|
|
1181
|
+
const [name, kind] = collectedNameAndKind(element.type);
|
|
1182
|
+
return {
|
|
1183
|
+
children: [],
|
|
1184
|
+
key: element.key ?? null,
|
|
1185
|
+
kind,
|
|
1186
|
+
name,
|
|
1187
|
+
props: ownProps
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
function collectedNameAndKind(type) {
|
|
1191
|
+
if (typeof type === "string") return [type, "host"];
|
|
1192
|
+
if (type === Fragment) return ["Fragment", "fragment"];
|
|
1193
|
+
if (isContext(type)) return ["Context.Provider", "context-provider"];
|
|
1194
|
+
if (isAssets(type)) return ["Assets", "assets"];
|
|
1195
|
+
if (isSuspense(type)) return ["Suspense", "suspense"];
|
|
1196
|
+
if (isErrorBoundary(type)) return ["ErrorBoundary", "error-boundary"];
|
|
1197
|
+
if (isActivity(type)) return ["Activity", "activity"];
|
|
1198
|
+
if (isViewTransition(type)) return ["ViewTransition", "view-transition"];
|
|
1199
|
+
if (isClientReference(type)) return [type.id.slice(type.id.lastIndexOf("#") + 1) || "ClientReference", "client-reference"];
|
|
1200
|
+
if (typeof type === "function") return [type.name === "" ? "Anonymous" : type.name, "function"];
|
|
1201
|
+
return ["Anonymous", "function"];
|
|
1202
|
+
}
|
|
1203
|
+
function renderElementKind(element, frame) {
|
|
1204
|
+
const type = element.type;
|
|
1205
|
+
if (typeof type === "string") {
|
|
1206
|
+
renderHostElement(type, element.props, frame);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
if (type === Fragment) {
|
|
1210
|
+
renderChildren(element.props.children, frame);
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
if (isContext(type)) {
|
|
1214
|
+
renderContextProvider(type, element.props, frame);
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
if (isAssets(type)) {
|
|
1218
|
+
renderAssets(element.props, frame);
|
|
1219
|
+
return;
|
|
1220
|
+
}
|
|
1221
|
+
if (isSuspense(type)) {
|
|
1222
|
+
renderSuspense(element.props, frame);
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
if (isErrorBoundary(type)) {
|
|
1226
|
+
renderChildren(element.props.children, frame);
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
if (isClientReference(type)) {
|
|
1230
|
+
renderClientReference(type, element.props, frame);
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
if (isActivity(type)) {
|
|
1234
|
+
renderActivity(element.props, frame);
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
if (isViewTransition(type)) {
|
|
1238
|
+
renderViewTransition(element.props, frame);
|
|
1239
|
+
return;
|
|
1240
|
+
}
|
|
1241
|
+
if (typeof type === "function") {
|
|
1242
|
+
renderFunctionComponent(type, element.props, frame);
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
throw new Error(`Unsupported Fig element type: ${describeElementType(type)}.`);
|
|
1246
|
+
}
|
|
1247
|
+
function renderFunctionComponent(type, props, frame) {
|
|
1248
|
+
frame.dispatcher ??= createServerDispatcher(frame);
|
|
1249
|
+
const previousDispatcher = setCurrentDispatcher(frame.dispatcher);
|
|
1250
|
+
const previousDataStore = setCurrentDataStore(frame.request.dataStore);
|
|
1251
|
+
const previousStack = frame.stack;
|
|
1252
|
+
const previousLocalIdCounter = frame.localIdCounter;
|
|
1253
|
+
frame.stack = {
|
|
1254
|
+
name: type.name || "Anonymous",
|
|
1255
|
+
parent: previousStack
|
|
1256
|
+
};
|
|
1257
|
+
frame.localIdCounter = 0;
|
|
1258
|
+
try {
|
|
1259
|
+
renderComponentAssets(type, frame);
|
|
1260
|
+
renderChildren(type(props), frame);
|
|
1261
|
+
} catch (error) {
|
|
1262
|
+
recordErrorStack(error, frame.stack);
|
|
1263
|
+
throw error;
|
|
1264
|
+
} finally {
|
|
1265
|
+
frame.stack = previousStack;
|
|
1266
|
+
frame.localIdCounter = previousLocalIdCounter;
|
|
1267
|
+
setCurrentDataStore(previousDataStore);
|
|
1268
|
+
setCurrentDispatcher(previousDispatcher);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
function renderClientReference(type, props, frame) {
|
|
1272
|
+
if (type.ssr !== void 0) {
|
|
1273
|
+
renderComponentAssets(type, frame);
|
|
1274
|
+
renderElement(createElement(type.ssr, props), frame);
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
const fallback = frame.request.clientReferenceFallback;
|
|
1278
|
+
if (fallback === void 0) {
|
|
1279
|
+
renderFunctionComponent(type, props, frame);
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
renderComponentAssets(type, frame);
|
|
1283
|
+
renderChildren(fallback(type, props), frame);
|
|
1284
|
+
}
|
|
1285
|
+
function renderComponentAssets(type, frame) {
|
|
1286
|
+
const key = isClientReference(type) ? type.id : frame.request.resolveAssetKey?.(type);
|
|
1287
|
+
if (key !== void 0) renderAssetValue(frame.request.componentAssets?.[key], frame);
|
|
1288
|
+
}
|
|
1289
|
+
function renderContextProvider(context, props, frame) {
|
|
1290
|
+
withContextValue(frame.contextValues, context, props.value, () => renderChildren(props.children, frame));
|
|
1291
|
+
}
|
|
1292
|
+
function renderAssets(props, frame) {
|
|
1293
|
+
renderAssetValue(props.assets, frame);
|
|
1294
|
+
renderChildren(props.children, frame);
|
|
1295
|
+
}
|
|
1296
|
+
function renderAssetValue(value, frame) {
|
|
1297
|
+
if (value === void 0 || value === null || value === false) return;
|
|
1298
|
+
for (const resource of Array.isArray(value) ? value : [value]) {
|
|
1299
|
+
if (!isFigAssetResource(resource)) throw new Error("The assets prop must contain Fig asset resources.");
|
|
1300
|
+
try {
|
|
1301
|
+
frame.request.assetRegistry.register(resource);
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
recordErrorStack(error, frame.stack);
|
|
1304
|
+
throw error;
|
|
1305
|
+
}
|
|
1306
|
+
frame.segment.assetResources.push(resource);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
function renderAutomaticImagePreload(resource, frame) {
|
|
1310
|
+
try {
|
|
1311
|
+
frame.request.assetRegistry.registerAutomaticImage(resource);
|
|
1312
|
+
} catch (error) {
|
|
1313
|
+
recordErrorStack(error, frame.stack);
|
|
1314
|
+
throw error;
|
|
1315
|
+
}
|
|
1316
|
+
frame.segment.assetResources.push(resource);
|
|
1317
|
+
}
|
|
1318
|
+
function renderSuspense(props, frame) {
|
|
1319
|
+
consumePendingLeadingNewline(frame);
|
|
1320
|
+
const fallbackAbortableTasks = /* @__PURE__ */ new Set();
|
|
1321
|
+
const contentSegment = createSegment(0, null);
|
|
1322
|
+
const boundary = createBoundary(fallbackAbortableTasks, contentSegment);
|
|
1323
|
+
boundary.activityId = frame.hiddenActivityId;
|
|
1324
|
+
const parentSegment = frame.segment;
|
|
1325
|
+
const boundarySegment = createSegment(parentSegment.chunks.length, boundary);
|
|
1326
|
+
boundary.fallbackSegment = boundarySegment;
|
|
1327
|
+
parentSegment.children.push(boundarySegment);
|
|
1328
|
+
parentSegment.lastPushedText = false;
|
|
1329
|
+
contentSegment.parentFlushed = true;
|
|
1330
|
+
const contentFrame = createRenderFrame(frame.request, contentSegment, {
|
|
1331
|
+
...forkScope(frame),
|
|
1332
|
+
boundary
|
|
1333
|
+
});
|
|
1334
|
+
try {
|
|
1335
|
+
renderChildren(props.children, contentFrame);
|
|
1336
|
+
contentSegment.status = "completed";
|
|
1337
|
+
boundary.completedSegments.push(contentSegment);
|
|
1338
|
+
if (boundary.pendingTasks === 0) boundary.status = "completed";
|
|
1339
|
+
} catch (error) {
|
|
1340
|
+
contentSegment.status = "completed";
|
|
1341
|
+
markBoundaryClientRendered(frame.request, boundary, error, frame.stack);
|
|
1342
|
+
}
|
|
1343
|
+
const advanceSurfaceWatermark = (branch) => {
|
|
1344
|
+
if (frame.viewTransition !== null && branch.viewTransition !== null) frame.viewTransition.index = Math.max(frame.viewTransition.index, branch.viewTransition.index);
|
|
1345
|
+
};
|
|
1346
|
+
advanceSurfaceWatermark(contentFrame);
|
|
1347
|
+
if (boundary.status === "completed") return;
|
|
1348
|
+
const fallbackFrame = createRenderFrame(frame.request, boundarySegment, {
|
|
1349
|
+
...forkScope(frame),
|
|
1350
|
+
abortSet: fallbackAbortableTasks
|
|
1351
|
+
});
|
|
1352
|
+
try {
|
|
1353
|
+
renderChildren(props.fallback, fallbackFrame);
|
|
1354
|
+
boundarySegment.status = "completed";
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
if (boundary.pendingTasks > 0) for (const task of Array.from(boundary.fallbackAbortableTasks)) abortTask(frame.request, task);
|
|
1357
|
+
throw error;
|
|
1358
|
+
} finally {
|
|
1359
|
+
advanceSurfaceWatermark(fallbackFrame);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
function renderViewTransition(props, frame) {
|
|
1363
|
+
const previousViewTransition = frame.viewTransition;
|
|
1364
|
+
frame.viewTransition = createServerViewTransition(props, frame.request);
|
|
1365
|
+
try {
|
|
1366
|
+
renderChildren(props.children, frame);
|
|
1367
|
+
} finally {
|
|
1368
|
+
frame.viewTransition = previousViewTransition;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
function createServerViewTransition(props, request) {
|
|
1372
|
+
return {
|
|
1373
|
+
className: serverViewTransitionClass(props),
|
|
1374
|
+
index: 0,
|
|
1375
|
+
name: props.name === void 0 || props.name === "auto" ? `fig-vt-${request.nextViewTransitionId++}` : props.name
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
function serverViewTransitionClass(props) {
|
|
1379
|
+
const className = props.default;
|
|
1380
|
+
if (className === void 0 || className === "auto" || className === "none") return null;
|
|
1381
|
+
return className;
|
|
1382
|
+
}
|
|
1383
|
+
function renderActivity(props, frame) {
|
|
1384
|
+
if (props.mode !== "hidden") {
|
|
1385
|
+
renderChildren(props.children, frame);
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
const id = activityId(frame.request, frame.request.nextActivityId++);
|
|
1389
|
+
frame.segment.write(`<template ${ACTIVITY_TEMPLATE_ATTRIBUTE}="" id="${escapeAttribute(id)}">`);
|
|
1390
|
+
const previousHiddenActivityId = frame.hiddenActivityId;
|
|
1391
|
+
frame.hiddenActivityId = id;
|
|
1392
|
+
try {
|
|
1393
|
+
renderChildren(props.children, frame);
|
|
1394
|
+
} finally {
|
|
1395
|
+
frame.hiddenActivityId = previousHiddenActivityId;
|
|
1396
|
+
}
|
|
1397
|
+
frame.segment.write("</template>");
|
|
1398
|
+
}
|
|
1399
|
+
function renderHostElement(type, props, frame) {
|
|
1400
|
+
const namespace = hostElementNamespace(type, frame.hostNamespace);
|
|
1401
|
+
if (namespace === "html" && renderHostAsset(type, props, frame)) return;
|
|
1402
|
+
if (namespace === "html") validateInstanceNesting(type, frame.hostAncestors);
|
|
1403
|
+
const document = frame.request.document;
|
|
1404
|
+
if (document !== null && !document.hasHead) {
|
|
1405
|
+
if (type !== "html" && type !== "head") throw invalidDocumentShellError();
|
|
1406
|
+
}
|
|
1407
|
+
if (document !== null && type === "html") frame.segment.write("<!doctype html>");
|
|
1408
|
+
if (document !== null && type === "head") document.hasHead = true;
|
|
1409
|
+
const isVoid = namespace === "html" && isVoidElement(type);
|
|
1410
|
+
const unsafeHTML = unsafeHTMLContent(props);
|
|
1411
|
+
if (isVoid && hasRenderableChild(props.children)) throw new Error(`Void element <${type}> cannot have children.`);
|
|
1412
|
+
if (isVoid && unsafeHTML !== null) throw new Error(`Void element <${type}> cannot have unsafeHTML.`);
|
|
1413
|
+
if (unsafeHTML !== null && hasRenderableChild(props.children)) throw new Error("Host elements cannot have both unsafeHTML and children.");
|
|
1414
|
+
if (namespace === "html") {
|
|
1415
|
+
const imagePreload = imagePreloadFromHostProps(type, props, frame.imagePreloadsSuppressed);
|
|
1416
|
+
if (imagePreload !== null) renderAutomaticImagePreload(imagePreload, frame);
|
|
1417
|
+
}
|
|
1418
|
+
consumePendingLeadingNewline(frame);
|
|
1419
|
+
const viewTransition = frame.viewTransition;
|
|
1420
|
+
writeElementStart(type, viewTransition === null ? props : viewTransitionHostProps(props, viewTransition), frame.segment, frame.selectProps ?? {});
|
|
1421
|
+
if (document !== null && type === "head") frame.segment.write(earlyEventCaptureMarkup(frame.request));
|
|
1422
|
+
if (isVoid) return;
|
|
1423
|
+
const previousPendingLeadingNewline = frame.pendingLeadingNewline;
|
|
1424
|
+
const tracksLeadingNewline = leadingNewlineStrippedHost(type);
|
|
1425
|
+
frame.pendingLeadingNewline = tracksLeadingNewline;
|
|
1426
|
+
if (unsafeHTML !== null) {
|
|
1427
|
+
frame.segment.write(consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(unsafeHTML) : unsafeHTML);
|
|
1428
|
+
frame.pendingLeadingNewline = previousPendingLeadingNewline;
|
|
1429
|
+
writeElementEnd(type, frame.segment);
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
const formText = namespace === "html" ? formTextContent(type, props) : null;
|
|
1433
|
+
if (formText !== null) {
|
|
1434
|
+
writeText(consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(formText) : formText, frame.segment);
|
|
1435
|
+
frame.pendingLeadingNewline = previousPendingLeadingNewline;
|
|
1436
|
+
writeElementEnd(type, frame.segment);
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
const previousSelectProps = frame.selectProps;
|
|
1440
|
+
if (namespace === "html" && type === "select") frame.selectProps = props;
|
|
1441
|
+
const previousHostAncestors = frame.hostAncestors;
|
|
1442
|
+
const previousHostNamespace = frame.hostNamespace;
|
|
1443
|
+
const previousImagePreloadsSuppressed = frame.imagePreloadsSuppressed;
|
|
1444
|
+
const previousViewTransition = frame.viewTransition;
|
|
1445
|
+
if (viewTransition !== null) frame.viewTransition = null;
|
|
1446
|
+
frame.hostAncestors = [type, ...previousHostAncestors];
|
|
1447
|
+
frame.hostNamespace = childHostNamespace(type, namespace);
|
|
1448
|
+
frame.imagePreloadsSuppressed = previousImagePreloadsSuppressed || namespace === "html" && suppressesImagePreloads(type);
|
|
1449
|
+
if (tracksLeadingNewline) frame.segment.chunks.push(leadingNewlineStartMarker);
|
|
1450
|
+
try {
|
|
1451
|
+
renderChildren(props.children, frame);
|
|
1452
|
+
} finally {
|
|
1453
|
+
frame.selectProps = previousSelectProps;
|
|
1454
|
+
frame.hostAncestors = previousHostAncestors;
|
|
1455
|
+
frame.hostNamespace = previousHostNamespace;
|
|
1456
|
+
frame.imagePreloadsSuppressed = previousImagePreloadsSuppressed;
|
|
1457
|
+
frame.viewTransition = previousViewTransition;
|
|
1458
|
+
frame.pendingLeadingNewline = previousPendingLeadingNewline;
|
|
1459
|
+
}
|
|
1460
|
+
if (tracksLeadingNewline) frame.segment.chunks.push(leadingNewlineEndMarker);
|
|
1461
|
+
if (document !== null && type === "head") writeDocumentHeadMarker(frame.segment);
|
|
1462
|
+
writeElementEnd(type, frame.segment);
|
|
1463
|
+
}
|
|
1464
|
+
function hostElementNamespace(type, parent) {
|
|
1465
|
+
const normalizedType = type.toLowerCase();
|
|
1466
|
+
if (normalizedType === "svg") return "svg";
|
|
1467
|
+
if (normalizedType === "math") return "mathml";
|
|
1468
|
+
return parent;
|
|
1469
|
+
}
|
|
1470
|
+
function childHostNamespace(type, namespace) {
|
|
1471
|
+
return namespace === "svg" && type.toLowerCase() === "foreignobject" ? "html" : namespace;
|
|
1472
|
+
}
|
|
1473
|
+
function renderHostAsset(type, props, frame) {
|
|
1474
|
+
const resource = assetResourceFromHostProps(type, props);
|
|
1475
|
+
if (resource === null) return false;
|
|
1476
|
+
renderAssetValue(resource, frame);
|
|
1477
|
+
return true;
|
|
1478
|
+
}
|
|
1479
|
+
function viewTransitionHostProps(props, viewTransition) {
|
|
1480
|
+
const index = viewTransition.index++;
|
|
1481
|
+
const name = index === 0 ? viewTransition.name : `${viewTransition.name}_${index}`;
|
|
1482
|
+
const nextProps = {
|
|
1483
|
+
...props,
|
|
1484
|
+
[VIEW_TRANSITION_NAME_ATTRIBUTE]: name
|
|
1485
|
+
};
|
|
1486
|
+
if (viewTransition.className !== null) nextProps[VIEW_TRANSITION_CLASS_ATTRIBUTE] = viewTransition.className;
|
|
1487
|
+
return nextProps;
|
|
1488
|
+
}
|
|
1489
|
+
function spawnSuspendedTask(frame, node, thenable, childIndexBase) {
|
|
1490
|
+
const request = frame.request;
|
|
1491
|
+
const segment = createSegment(frame.segment.chunks.length, null, {
|
|
1492
|
+
lastPushedText: frame.segment.lastPushedText,
|
|
1493
|
+
textEmbedded: true
|
|
1494
|
+
});
|
|
1495
|
+
frame.segment.lastPushedText = false;
|
|
1496
|
+
frame.segment.children.push(segment);
|
|
1497
|
+
const task = createTask(request, node, segment, forkScope(frame), childIndexBase);
|
|
1498
|
+
thenable.then(() => pingTask(request, task), () => pingTask(request, task));
|
|
1499
|
+
}
|
|
1500
|
+
function pingTask(request, task) {
|
|
1501
|
+
if (request.status === "closed" || request.status === "aborting") return;
|
|
1502
|
+
request.pingedTasks.push(task);
|
|
1503
|
+
if (request.workScheduled) return;
|
|
1504
|
+
request.workScheduled = true;
|
|
1505
|
+
queueMicrotask(() => {
|
|
1506
|
+
request.workScheduled = false;
|
|
1507
|
+
performWork(request);
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
function finishedTask(request, task) {
|
|
1511
|
+
request.pendingTasks -= 1;
|
|
1512
|
+
const boundary = task.boundary;
|
|
1513
|
+
if (boundary === null) {
|
|
1514
|
+
request.pendingRootTasks -= 1;
|
|
1515
|
+
if (task.segment === request.rootSegment || request.completedRootSegment === null) request.completedRootSegment = request.rootSegment;
|
|
1516
|
+
if (request.pendingRootTasks === 0) finishRootShell(request);
|
|
1517
|
+
} else {
|
|
1518
|
+
boundary.pendingTasks -= 1;
|
|
1519
|
+
if (task.segment.parentFlushed) enqueueUnique(boundary.completedSegments, task.segment);
|
|
1520
|
+
if (!completeBoundaryIfReady(request, boundary) && boundary.parentFlushed) request.partialBoundaries.add(boundary);
|
|
1521
|
+
}
|
|
1522
|
+
if (request.pendingTasks === 0) request.allReady.resolve(void 0);
|
|
1523
|
+
}
|
|
1524
|
+
function erroredTask(request, task, error) {
|
|
1525
|
+
request.pendingTasks -= 1;
|
|
1526
|
+
const boundary = task.boundary;
|
|
1527
|
+
if (boundary === null) {
|
|
1528
|
+
request.pendingRootTasks -= 1;
|
|
1529
|
+
fatalError(request, error);
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
boundary.pendingTasks -= 1;
|
|
1533
|
+
markBoundaryClientRendered(request, boundary, error, task.stack);
|
|
1534
|
+
if (request.pendingTasks === 0) request.allReady.resolve(void 0);
|
|
1535
|
+
}
|
|
1536
|
+
function detachTask(request, task) {
|
|
1537
|
+
task.abortSet.delete(task);
|
|
1538
|
+
request.abortableTasks.delete(task);
|
|
1539
|
+
}
|
|
1540
|
+
function abortTask(request, task) {
|
|
1541
|
+
if (!request.abortableTasks.delete(task)) return;
|
|
1542
|
+
task.segment.status = "completed";
|
|
1543
|
+
task.abortSet.delete(task);
|
|
1544
|
+
request.pendingTasks -= 1;
|
|
1545
|
+
const boundary = task.boundary;
|
|
1546
|
+
if (boundary === null) {
|
|
1547
|
+
request.pendingRootTasks -= 1;
|
|
1548
|
+
if (request.pendingRootTasks === 0) finishRootShell(request);
|
|
1549
|
+
} else {
|
|
1550
|
+
boundary.pendingTasks -= 1;
|
|
1551
|
+
completeBoundaryIfReady(request, boundary);
|
|
1552
|
+
}
|
|
1553
|
+
if (request.pendingTasks === 0) request.allReady.resolve(void 0);
|
|
1554
|
+
}
|
|
1555
|
+
function completeBoundaryIfReady(request, boundary) {
|
|
1556
|
+
if (boundary.pendingTasks !== 0 || boundary.status !== "pending") return false;
|
|
1557
|
+
boundary.status = "completed";
|
|
1558
|
+
abortFallbackTasks(request, boundary);
|
|
1559
|
+
if (boundary.parentFlushed) request.completedBoundaries.add(boundary);
|
|
1560
|
+
return true;
|
|
1561
|
+
}
|
|
1562
|
+
function abortFallbackTasks(request, boundary) {
|
|
1563
|
+
for (const fallbackTask of Array.from(boundary.fallbackAbortableTasks)) abortTask(request, fallbackTask);
|
|
1564
|
+
}
|
|
1565
|
+
function markBoundaryClientRendered(request, boundary, error, stack, payload) {
|
|
1566
|
+
if (boundary.status !== "client-rendered") {
|
|
1567
|
+
boundary.status = "client-rendered";
|
|
1568
|
+
boundary.error = payload ?? reportBoundaryError(request, error, stack);
|
|
1569
|
+
}
|
|
1570
|
+
boundary.completedSegments = [];
|
|
1571
|
+
request.completedBoundaries.delete(boundary);
|
|
1572
|
+
request.partialBoundaries.delete(boundary);
|
|
1573
|
+
for (const task of Array.from(request.abortableTasks)) if (task.boundary === boundary) abortTask(request, task);
|
|
1574
|
+
for (const task of Array.from(boundary.fallbackAbortableTasks)) abortTask(request, task);
|
|
1575
|
+
if (boundary.parentFlushed) request.clientRenderedBoundaries.add(boundary);
|
|
1576
|
+
}
|
|
1577
|
+
function abort(request, reason) {
|
|
1578
|
+
if (request.status === "closed") return;
|
|
1579
|
+
request.cleanupAbortListener();
|
|
1580
|
+
request.status = "aborting";
|
|
1581
|
+
request.dataStore.dispose();
|
|
1582
|
+
const error = abortError(reason);
|
|
1583
|
+
request.fatalError = error;
|
|
1584
|
+
if (request.pendingRootTasks > 0) {
|
|
1585
|
+
fatalError(request, error);
|
|
1586
|
+
return;
|
|
1587
|
+
}
|
|
1588
|
+
for (const task of Array.from(request.abortableTasks)) {
|
|
1589
|
+
const boundary = task.boundary;
|
|
1590
|
+
if (boundary !== null) markBoundaryClientRendered(request, boundary, error, task.stack, {});
|
|
1591
|
+
}
|
|
1592
|
+
request.abortableTasks.clear();
|
|
1593
|
+
request.pendingTasks = 0;
|
|
1594
|
+
request.allReady.resolve(void 0);
|
|
1595
|
+
flushCompletedQueues(request);
|
|
1596
|
+
}
|
|
1597
|
+
function fatalError(request, error) {
|
|
1598
|
+
if (request.status === "closed") return;
|
|
1599
|
+
request.cleanupAbortListener();
|
|
1600
|
+
request.status = "closed";
|
|
1601
|
+
request.dataStore.dispose();
|
|
1602
|
+
request.fatalError = error;
|
|
1603
|
+
request.headReady.reject(error);
|
|
1604
|
+
request.shellReady.reject(error);
|
|
1605
|
+
request.allReady.reject(error);
|
|
1606
|
+
request.controller?.error(error);
|
|
1607
|
+
}
|
|
1608
|
+
function finishRootShell(request) {
|
|
1609
|
+
if (request.document !== null && !request.document.hasHead) {
|
|
1610
|
+
fatalError(request, invalidDocumentShellError());
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
if (!request.prerender) sealHead(request);
|
|
1614
|
+
request.shellReady.resolve(void 0);
|
|
1615
|
+
}
|
|
1616
|
+
function enqueueUnique(queue, item) {
|
|
1617
|
+
if (!queue.includes(item)) queue.push(item);
|
|
1618
|
+
}
|
|
1619
|
+
function reportBoundaryError(request, error, stack) {
|
|
1620
|
+
const info = { componentStack: componentStack(stackForError(error, stack)) };
|
|
1621
|
+
if (request.onError === void 0) return { message: errorMessage(error) };
|
|
1622
|
+
try {
|
|
1623
|
+
return request.onError(error, info) ?? {};
|
|
1624
|
+
} catch {
|
|
1625
|
+
return {};
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
function recordErrorStack(error, stack) {
|
|
1629
|
+
if (stack === null) return;
|
|
1630
|
+
if (typeof error !== "object" && typeof error !== "function") return;
|
|
1631
|
+
if (error === null || isThenable(error)) return;
|
|
1632
|
+
if (!errorStacks.has(error)) errorStacks.set(error, stack);
|
|
1633
|
+
}
|
|
1634
|
+
function stackForError(error, fallback) {
|
|
1635
|
+
if (typeof error !== "object" && typeof error !== "function" || error === null) return fallback;
|
|
1636
|
+
return errorStacks.get(error) ?? fallback;
|
|
1637
|
+
}
|
|
1638
|
+
function createRuntimeName(identifierPrefix) {
|
|
1639
|
+
const id = nextRuntimeId.toString(36);
|
|
1640
|
+
nextRuntimeId += 1;
|
|
1641
|
+
const prefix = identifierPrefix?.replace(/[^A-Za-z0-9_$]/g, "_") ?? "";
|
|
1642
|
+
return prefix === "" ? `__figSSR_${id}` : `__figSSR_${prefix}_${id}`;
|
|
1643
|
+
}
|
|
1644
|
+
function writeDocumentHeadMarker(segment) {
|
|
1645
|
+
segment.lastPushedText = false;
|
|
1646
|
+
segment.chunks.push(documentHeadMarker);
|
|
1647
|
+
}
|
|
1648
|
+
function consumePendingLeadingNewline(frame) {
|
|
1649
|
+
const pending = frame.pendingLeadingNewline;
|
|
1650
|
+
frame.pendingLeadingNewline = false;
|
|
1651
|
+
return pending;
|
|
1652
|
+
}
|
|
1653
|
+
function leadingNewlineStrippedHost(type) {
|
|
1654
|
+
return type === "pre" || type === "textarea";
|
|
1655
|
+
}
|
|
1656
|
+
function writeLeadingNewlineText(text, segment) {
|
|
1657
|
+
writeText(text, { write(value) {
|
|
1658
|
+
segment.write({ value });
|
|
1659
|
+
} });
|
|
1660
|
+
}
|
|
1661
|
+
function preserveParserStrippedLeadingNewline(text) {
|
|
1662
|
+
return text.startsWith("\n") ? `\n${text}` : text;
|
|
1663
|
+
}
|
|
1664
|
+
function invalidDocumentShellError() {
|
|
1665
|
+
return /* @__PURE__ */ new Error("renderToDocumentStream requires the root to render an <html> document with a <head>.");
|
|
1666
|
+
}
|
|
1667
|
+
function throwIfAborted(signal) {
|
|
1668
|
+
if (signal?.aborted === true) throw abortReason(signal.reason);
|
|
1669
|
+
}
|
|
1670
|
+
function throwIfAborting(request) {
|
|
1671
|
+
if (request.status === "aborting") throw abortReason(request.fatalError);
|
|
1672
|
+
}
|
|
1673
|
+
function abortError(reason) {
|
|
1674
|
+
if (reason instanceof Error) return reason;
|
|
1675
|
+
return new Error(typeof reason === "string" ? reason : "Server render was aborted.");
|
|
1676
|
+
}
|
|
1677
|
+
function abortReason(reason) {
|
|
1678
|
+
return reason ?? /* @__PURE__ */ new Error("Server render was aborted.");
|
|
1679
|
+
}
|
|
1680
|
+
function describeElementType(type) {
|
|
1681
|
+
if (typeof type === "symbol") return String(type);
|
|
1682
|
+
if (typeof type === "function") return type.name || "anonymous function";
|
|
1683
|
+
return typeof type;
|
|
1684
|
+
}
|
|
1685
|
+
//#endregion
|
|
1686
|
+
//#region src/render-tree.ts
|
|
1687
|
+
function createRenderTreeCollector() {
|
|
1688
|
+
return { tree: {
|
|
1689
|
+
children: [],
|
|
1690
|
+
key: null,
|
|
1691
|
+
kind: "root",
|
|
1692
|
+
name: "Root",
|
|
1693
|
+
props: {}
|
|
1694
|
+
} };
|
|
1695
|
+
}
|
|
1696
|
+
//#endregion
|
|
1697
|
+
//#region src/index.ts
|
|
1698
|
+
function renderToStream(node, options = {}) {
|
|
1699
|
+
return createServerRenderRequest(node, options);
|
|
1700
|
+
}
|
|
1701
|
+
function renderToDocumentStream(node, options = {}) {
|
|
1702
|
+
const request = createServerRenderRequest(node, options, { document: true });
|
|
1703
|
+
return {
|
|
1704
|
+
abort: (reason) => request.abort(reason),
|
|
1705
|
+
allReady: request.allReady,
|
|
1706
|
+
contentType: request.contentType,
|
|
1707
|
+
data: request.data,
|
|
1708
|
+
getData: () => request.getData(),
|
|
1709
|
+
getPreloadHeader: (headerOptions) => request.getPreloadHeader(headerOptions),
|
|
1710
|
+
shellReady: request.shellReady,
|
|
1711
|
+
stream: request.stream
|
|
1712
|
+
};
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* The streamed output, buffered: awaits `allReady` and concatenates exactly
|
|
1716
|
+
* the bytes a streaming client would have received — including the inline
|
|
1717
|
+
* streaming runtime and boundary-reveal scripts when the tree suspends past
|
|
1718
|
+
* the shell. Right for caching responses and snapshotting wire output; it is
|
|
1719
|
+
* NOT React's `renderToString` (use `prerender` for settled, script-free
|
|
1720
|
+
* static markup).
|
|
1721
|
+
*/
|
|
1722
|
+
async function renderToHtml(node, options = {}) {
|
|
1723
|
+
const result = renderToStream(node, options);
|
|
1724
|
+
await result.allReady;
|
|
1725
|
+
return readStreamToString(result.stream);
|
|
1726
|
+
}
|
|
1727
|
+
/** Document-mode {@link renderToHtml}: the streamed document, buffered. */
|
|
1728
|
+
async function renderToDocumentHtml(node, options = {}) {
|
|
1729
|
+
const result = renderToDocumentStream(node, options);
|
|
1730
|
+
await result.allReady;
|
|
1731
|
+
return readStreamToString(result.stream);
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Settled static HTML: waits for all async work before flushing, so completed
|
|
1735
|
+
* Suspense content is emitted in logical position without streaming scripts.
|
|
1736
|
+
*/
|
|
1737
|
+
async function prerender(node, options = {}) {
|
|
1738
|
+
const { document = false, ...renderOptions } = options;
|
|
1739
|
+
const result = createServerRenderRequest(node, renderOptions, {
|
|
1740
|
+
document,
|
|
1741
|
+
prerender: true
|
|
1742
|
+
});
|
|
1743
|
+
await result.allReady;
|
|
1744
|
+
const html = await readStreamToString(result.stream);
|
|
1745
|
+
return {
|
|
1746
|
+
data: result.getData(),
|
|
1747
|
+
head: document ? "" : result.getHead(),
|
|
1748
|
+
html
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
async function readStreamToString(stream) {
|
|
1752
|
+
const reader = stream.getReader();
|
|
1753
|
+
const textDecoder = new TextDecoder();
|
|
1754
|
+
let output = "";
|
|
1755
|
+
for (;;) {
|
|
1756
|
+
const { done, value } = await reader.read();
|
|
1757
|
+
if (done) return output + textDecoder.decode();
|
|
1758
|
+
output += textDecoder.decode(value, { stream: true });
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
//#endregion
|
|
1762
|
+
export { createRenderTreeCollector, prerender, renderToDocumentHtml, renderToDocumentStream, renderToHtml, renderToStream };
|
|
1763
|
+
|
|
1764
|
+
//# sourceMappingURL=index.js.map
|