@bgub/fig-server 0.1.0-alpha.0 → 0.1.0-alpha.2

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/index.js CHANGED
@@ -1,6 +1,7 @@
1
- import { i as withContextValue, n as createStaticDispatcher, r as deferred, t as cloneContextValues } from "./shared-CQn6Dje6.js";
2
- import { Fragment, createElement } from "@bgub/fig";
3
- import { ACTIVITY_TEMPLATE_ATTRIBUTE, EARLY_EVENT_HANDLER_PROPERTY, EARLY_EVENT_QUEUE_PROPERTY, REPLAYABLE_EVENT_TYPES, SUSPENSE_CLIENT_MARKER, SUSPENSE_COMPLETED_MARKER, SUSPENSE_END_MARKER, SUSPENSE_MARKER_PREFIX, SUSPENSE_PENDING_PREFIX, VIEW_TRANSITION_CLASS_ATTRIBUTE, VIEW_TRANSITION_NAME_ATTRIBUTE, VIEW_TRANSITION_PENDING_PROPERTY, assetResourceDestination, assetResourceFromHostProps, assetResourceHostAttributes, assetResourceKey, collectChildren, createDataStore, invalidChildError, isActivity, isAssets, isClientReference, isContext, isErrorBoundary, isFigAssetResource, isPortal, isSuspense, isThenable, isValidElement, isViewTransition, readThenable, setCurrentDataStore, setCurrentDispatcher } from "@bgub/fig/internal";
1
+ import { i as escapeText, n as escapeScriptJson, t as escapeAttribute } from "./escaping-DAot8sFu.js";
2
+ import { a as componentStack, c as nonceAttribute, d as withContextValue, i as cloneContextValues, l as streamFlowBlocked, n as suppressesImagePreloads, o as createStaticDispatcher, r as STREAMED_METADATA_ATTRIBUTE, s as deferred, t as imagePreloadFromHostProps, u as streamHighWaterMark } from "./image-preloads-BIFcrqm9.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 } from "@bgub/fig/internal";
4
5
  //#region src/html.ts
5
6
  const voidElements = /* @__PURE__ */ new Set([
6
7
  "area",
@@ -23,9 +24,7 @@ function writeText(value, sink) {
23
24
  }
24
25
  function writeElementStart(type, props, sink, inheritedProps = {}) {
25
26
  validateTagName(type);
26
- sink.write(`<${type}`);
27
- writeAttributes(type, props, inheritedProps, sink);
28
- sink.write(">");
27
+ sink.write(`<${type}${serializeAttributes(type, props, inheritedProps)}>`);
29
28
  }
30
29
  function writeElementEnd(type, sink) {
31
30
  sink.write(`</${type}>`);
@@ -48,46 +47,39 @@ function unsafeHTMLContent(props) {
48
47
  if (typeof value === "string") return value;
49
48
  throw new Error("The unsafeHTML prop must be a string during server render.");
50
49
  }
51
- function writeAttributes(type, props, inheritedProps, sink) {
52
- for (const [name, value] of Object.entries(props)) {
50
+ function serializeAttributes(type, props, inheritedProps) {
51
+ let attributes = "";
52
+ for (const name of Object.keys(props)) {
53
+ const value = props[name];
53
54
  if (reservedProp(name)) continue;
54
55
  if (name === "value" && props.defaultValue !== void 0) continue;
55
56
  if (name === "checked" && props.defaultChecked !== void 0) continue;
56
57
  if (name === "style") {
57
58
  const style = serializeStyle(value);
58
- if (style !== "") writeAttribute(sink, "style", style);
59
+ if (style !== "") attributes += serializeAttribute("style", style);
59
60
  continue;
60
61
  }
61
- const attribute = formAttribute(type, name, value);
62
- if (attribute === null) continue;
63
- const [attributeNameValue, attributeValue] = attribute;
64
- validateAttributeName(attributeNameValue);
65
- if (attributeValue === true) {
66
- sink.write(` ${attributeNameValue}`);
67
- continue;
68
- }
69
- if (serializableAttributeValue(attributeValue)) {
70
- writeAttribute(sink, attributeNameValue, String(attributeValue));
71
- continue;
72
- }
73
- throw new Error(`Cannot serialize prop "${name}" to HTML.`);
74
- }
75
- if (type === "option" && props.selected === void 0 && optionSelected(optionValue(props), inheritedProps)) sink.write(" selected");
76
- }
77
- function formAttribute(type, name, value) {
78
- if ((type === "textarea" || type === "select") && valueProp(name)) return null;
79
- if (valueProp(name)) return valueAttribute(value);
80
- if (name === "defaultChecked") return value === true ? ["checked", true] : null;
81
- if (type === "option" && name === "selected") return value === true ? ["selected", true] : null;
82
- return attributeValue(name, value);
83
- }
84
- function attributeValue(name, value) {
85
- return emptyValue(value) ? null : [name, value];
86
- }
87
- function valueAttribute(value) {
88
- if (emptyValue(value)) return null;
89
- if (serializableAttributeValue(value)) return ["value", String(value)];
90
- return ["value", value];
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.`);
91
83
  }
92
84
  function optionSelected(value, selectProps) {
93
85
  const selectValue = selectProps.value !== void 0 ? selectProps.value : selectProps.defaultValue;
@@ -129,22 +121,23 @@ function emptyValue(value) {
129
121
  function emptyChild(value) {
130
122
  return value === null || value === void 0 || typeof value === "boolean";
131
123
  }
132
- function writeAttribute(sink, name, value) {
133
- sink.write(` ${name}="${escapeAttribute(value)}"`);
124
+ function serializeAttribute(name, value) {
125
+ return ` ${name}="${escapeAttribute(value)}"`;
134
126
  }
135
127
  function serializeStyle(value) {
136
128
  if (emptyValue(value)) return "";
137
129
  if (typeof value !== "object" || value === null) throw new Error("The style prop must be an object during server render.");
138
- const declarations = [];
130
+ let serialized = "";
139
131
  for (const [name, item] of Object.entries(value)) {
140
132
  if (emptyValue(item)) continue;
141
133
  if (typeof item !== "string" && typeof item !== "number" && typeof item !== "bigint") throw new Error(`Cannot serialize style property "${name}" to HTML.`);
142
- declarations.push(`${styleName(name)}:${String(item)}`);
134
+ if (serialized !== "") serialized += ";";
135
+ serialized += `${styleName(name)}:${String(item)}`;
143
136
  }
144
- return declarations.join(";");
137
+ return serialized;
145
138
  }
146
139
  function reservedProp(name) {
147
- return name === "children" || name === "key" || name === "events" || name === "bind" || name === "suppressHydrationWarning" || name === "unsafeHTML" || /^on[A-Z]/.test(name);
140
+ return name === "children" || name === "key" || name === "mix" || name === "bind" || name === "suppressHydrationWarning" || name === "unsafeHTML" || /^on[A-Z]/.test(name);
148
141
  }
149
142
  function valueProp(name) {
150
143
  return name === "value" || name === "defaultValue";
@@ -159,79 +152,261 @@ function validateTagName(name) {
159
152
  function validateAttributeName(name) {
160
153
  if (/[\s"'<>/=]/.test(name)) throw new Error(`Invalid HTML attribute name "${name}".`);
161
154
  }
162
- function escapeText(value) {
163
- return value.replace(/[&<>]/g, (character) => {
164
- if (character === "&") return "&amp;";
165
- if (character === "<") return "&lt;";
166
- return "&gt;";
167
- });
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;
168
284
  }
169
- function escapeAttribute(value) {
170
- return value.replace(/[&"<>]/g, (character) => {
171
- if (character === "&") return "&amp;";
172
- if (character === "\"") return "&quot;";
173
- if (character === "<") return "&lt;";
174
- return "&gt;";
175
- });
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));
176
295
  }
177
296
  //#endregion
178
297
  //#region src/asset-registry.ts
179
298
  var AssetResourceRegistry = class {
180
299
  identifierPrefix;
300
+ earlyImageKeys = /* @__PURE__ */ new Set();
181
301
  emittedResources = /* @__PURE__ */ new Set();
182
- resources = /* @__PURE__ */ new Map();
302
+ deliveryResources = /* @__PURE__ */ new Map();
303
+ metadataByOwner = /* @__PURE__ */ new Map();
183
304
  stylesheetIds = /* @__PURE__ */ new Map();
184
305
  nextStylesheetId = 0;
185
306
  constructor(identifierPrefix) {
186
307
  this.identifierPrefix = identifierPrefix;
187
308
  }
188
309
  register(resource) {
189
- return this.canonical(resource).added;
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);
190
330
  }
191
331
  write(resource, sink) {
332
+ if (isMetadataResource(resource)) return null;
192
333
  const { key, resource: current } = this.canonical(resource);
193
334
  const id = this.revealBlockerId(key, current);
194
- if (assetResourceDestination(current) === "head") return id;
195
335
  if (this.emittedResources.has(key)) return id;
196
336
  this.emittedResources.add(key);
197
337
  writeAssetTag(sink, current, id);
198
338
  return id;
199
339
  }
200
- headHtml(nonce) {
201
- let html = "";
202
- const sink = {
203
- nonce,
204
- write(chunk) {
205
- html += chunk;
206
- }
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: []
207
350
  };
208
- for (const resource of this.resources.values()) if (assetResourceDestination(resource) === "head") writeAssetTag(sink, resource, null);
209
- return html;
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;
210
389
  }
211
390
  canonical(resource) {
212
391
  const key = assetResourceKey(resource);
213
- const current = this.resources.get(key);
392
+ const current = this.deliveryResources.get(key);
214
393
  if (current !== void 0) {
215
394
  if (assetSignature(current) !== assetSignature(resource)) {
216
- if (resource.kind === "title") {
217
- this.resources.set(key, resource);
218
- return {
219
- added: false,
220
- key,
221
- resource
222
- };
223
- }
224
- throw new AssetResourceConflictError(key, current, 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
+ };
225
402
  }
226
403
  return {
227
- added: false,
228
404
  key,
229
405
  resource: current
230
406
  };
231
407
  }
232
- this.resources.set(key, resource);
408
+ this.deliveryResources.set(key, resource);
233
409
  return {
234
- added: true,
235
410
  key,
236
411
  resource
237
412
  };
@@ -258,7 +433,10 @@ var AssetResourceConflictError = class extends Error {
258
433
  function writeAssetTag(sink, resource, id) {
259
434
  switch (resource.kind) {
260
435
  case "title":
261
- writeElementStart("title", {}, sink);
436
+ writeElementStart("title", {
437
+ [HYDRATION_SKIP_ATTRIBUTE]: true,
438
+ [STREAMED_METADATA_ATTRIBUTE]: sink.streamMetadata ? assetResourceKey(resource) : void 0
439
+ }, sink);
262
440
  writeText(resource.value, sink);
263
441
  writeElementEnd("title", sink);
264
442
  return;
@@ -267,13 +445,18 @@ function writeAssetTag(sink, resource, id) {
267
445
  charset: resource.charset,
268
446
  name: resource.name,
269
447
  property: resource.property,
270
- "http-equiv": resource.httpEquiv,
448
+ "http-equiv": resource["http-equiv"],
271
449
  content: resource.content,
450
+ [HYDRATION_SKIP_ATTRIBUTE]: true,
451
+ [STREAMED_METADATA_ATTRIBUTE]: sink.streamMetadata ? assetResourceKey(resource) : void 0,
272
452
  "data-fig-resource-key": resource.key
273
453
  }, sink);
274
454
  return;
275
455
  default: {
276
- const props = Object.fromEntries(assetResourceHostAttributes(resource));
456
+ const props = {
457
+ [HYDRATION_SKIP_ATTRIBUTE]: true,
458
+ ...Object.fromEntries(assetResourceHostAttributes(resource))
459
+ };
277
460
  if (resource.kind === "stylesheet" && id !== null) props.id = id;
278
461
  const tag = resource.kind === "script" ? "script" : "link";
279
462
  writeElementStart(tag, withNonce(sink, props), sink);
@@ -281,6 +464,29 @@ function writeAssetTag(sink, resource, id) {
281
464
  }
282
465
  }
283
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
+ }
284
490
  function withNonce(sink, props) {
285
491
  return sink.nonce === void 0 ? props : {
286
492
  ...props,
@@ -289,17 +495,34 @@ function withNonce(sink, props) {
289
495
  }
290
496
  function assetSignature(resource) {
291
497
  switch (resource.kind) {
292
- case "stylesheet": return signature(resource.kind, resource.href, resource.media ?? "", resource.precedence ?? "", resource.crossOrigin ?? "", resource.blocking ?? "reveal");
293
- case "preload": return signature(resource.kind, resource.href, resource.as, resource.type ?? "", resource.crossOrigin ?? "", resource.fetchPriority ?? "");
294
- case "modulepreload": return signature(resource.kind, resource.href, resource.crossOrigin ?? "", resource.fetchPriority ?? "");
295
- case "font": return signature("preload", resource.href, "font", resource.type, resource.crossOrigin ?? "anonymous", resource.fetchPriority ?? "");
296
- case "preconnect": return signature(resource.kind, resource.href, resource.crossOrigin ?? "");
297
- case "script": return signature(resource.kind, resource.src, resource.module === true, resource.async !== false, resource.defer === true, resource.crossOrigin ?? "");
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 ?? "");
298
507
  case "title": return signature(resource.kind, resource.value);
299
- case "meta": return signature(resource.kind, resource.charset ?? "", resource.name ?? "", resource.property ?? "", resource.httpEquiv ?? "", resource.content ?? "");
508
+ case "meta": return signature(resource.kind, resource.charset ?? "", resource.name ?? "", resource.property ?? "", resource["http-equiv"] ?? "", resource.content ?? "");
300
509
  }
301
510
  return unsupportedAssetResource(resource);
302
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
+ }
303
526
  function unsupportedAssetResource(resource) {
304
527
  throw new Error(`Unsupported asset resource kind: ${resource.kind}`);
305
528
  }
@@ -309,7 +532,7 @@ function signature(...values) {
309
532
  //#endregion
310
533
  //#region src/protocol.ts
311
534
  function serverRuntimeCodeFor(runtimeName) {
312
- 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 g=()=>this.v(b,s,f);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()}},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){let x=document.getElementById(b),y=document.getElementById(s);this.v(x,y,r=>this.o(x,y,r))},o(b,s,l){if(!b||!s)return;let a=b.previousSibling||b,p=a.parentNode,c=s.content||s;if(!p)return;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}';let r=a.__figRetry;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){let x=this.b(t,b),y=document.getElementById(s);this.v(x,y,r=>this.o(x,y,r))},ax(t,b,d,m){this.y(this.b(t,b),d,m)}}`;
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)}}`;
313
536
  }
314
537
  function writeRuntime$1(request, write) {
315
538
  if (request.runtimeWritten) return;
@@ -317,17 +540,13 @@ function writeRuntime$1(request, write) {
317
540
  writeScript$1(request, serverRuntimeCodeFor(request.runtimeName), write);
318
541
  }
319
542
  function writeScript$1(request, code, write) {
320
- write(`<script${request.nonce === void 0 ? "" : ` nonce="${escapeAttribute(request.nonce)}"`}>${code}<\/script>`);
543
+ write(`<script ${HYDRATION_SKIP_ATTRIBUTE}=""${nonceAttribute(request.nonce)}>${code}<\/script>`);
321
544
  }
322
545
  function earlyEventCaptureCode() {
323
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)`;
324
547
  }
325
548
  function earlyEventCaptureMarkup(request) {
326
- let markup = "";
327
- writeScript$1(request, earlyEventCaptureCode(), (chunk) => {
328
- markup += chunk;
329
- });
330
- return markup;
549
+ return `<script ${HYDRATION_SKIP_ATTRIBUTE}=""${nonceAttribute(request.nonce)}>${earlyEventCaptureCode()}<\/script>`;
331
550
  }
332
551
  function placeholderMarkup(request, id) {
333
552
  return templateMarkup(placeholderId(request, id));
@@ -354,18 +573,281 @@ function boundaryId(request, id) {
354
573
  return prefixedId(request, "b", id);
355
574
  }
356
575
  function jsString(value) {
357
- return JSON.stringify(value).replace(/</g, "\\u003C");
576
+ return escapeScriptJson(value);
358
577
  }
359
578
  function prefixedId(request, kind, id) {
360
579
  return request.identifierPrefix === "" ? `${kind}-${id}` : `${request.identifierPrefix}-${kind}-${id}`;
361
580
  }
362
581
  //#endregion
363
- //#region src/renderer.ts
364
- const errorStacks = /* @__PURE__ */ new WeakMap();
365
- const textEncoder = new TextEncoder();
582
+ //#region src/renderer-flush.ts
366
583
  const documentHeadMarker = Symbol("fig.document-head");
584
+ const leadingNewlineStartMarker = Symbol("fig.leading-newline-start");
585
+ const leadingNewlineEndMarker = Symbol("fig.leading-newline-end");
367
586
  const RUNTIME_REF = "__figSSR";
368
- const TEXT_SEPARATOR = "<!--,-->";
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}-->`;
369
851
  let nextRuntimeId = 0;
370
852
  function createServerRenderRequest(node, options = {}, mode = {}) {
371
853
  throwIfAborted(options.signal);
@@ -376,40 +858,39 @@ function createServerRenderRequest(node, options = {}, mode = {}) {
376
858
  headReady.promise.catch(() => void 0);
377
859
  allReady.promise.catch(() => void 0);
378
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);
379
867
  const request = {
380
868
  abortableTasks: /* @__PURE__ */ new Set(),
381
- abortListener: null,
382
- abortSignal: options.signal ?? null,
383
869
  allReady,
870
+ cleanupAbortListener: () => void 0,
384
871
  completedBoundaries: /* @__PURE__ */ new Set(),
385
872
  completedRootSegment: null,
386
873
  controller: null,
387
- dataStore: createDataStore({
388
- getLane: () => null,
389
- partition: options.dataPartition,
390
- schedule: () => void 0
391
- }),
874
+ dataStore,
392
875
  fatalError: null,
393
876
  identifierPrefix: options.identifierPrefix ?? "",
877
+ leadingNewlineStack: [],
394
878
  nextBoundaryId: 0,
395
879
  nextSegmentId: 0,
396
880
  nextActivityId: 0,
397
881
  nextViewTransitionId: 0,
398
882
  nonce: options.nonce,
399
883
  onError: options.onError,
400
- onAssetError: options.onAssetError,
401
884
  pendingRootTasks: 0,
402
885
  pendingTasks: 0,
403
886
  pingedTasks: [],
404
- assetSink: null,
405
887
  rootSegment,
406
888
  runtimeName: createRuntimeName(options.identifierPrefix),
407
889
  runtimeWritten: false,
408
890
  headReady,
409
891
  headSnapshot: null,
410
892
  shellReady,
411
- status: "opening",
412
- stream: null,
893
+ status: "open",
413
894
  clientRenderedBoundaries: /* @__PURE__ */ new Set(),
414
895
  clientReferenceFallback: options.clientReferenceFallback,
415
896
  partialBoundaries: /* @__PURE__ */ new Set(),
@@ -419,22 +900,14 @@ function createServerRenderRequest(node, options = {}, mode = {}) {
419
900
  assetRegistry: new AssetResourceRegistry(options.identifierPrefix ?? ""),
420
901
  resolveAssetKey: options.resolveAssetKey,
421
902
  workScheduled: false,
422
- writeBuffer: []
423
- };
424
- request.assetSink = {
425
- nonce: options.nonce,
426
- write: (chunk) => write(request, chunk)
427
- };
428
- const stream = new ReadableStream({
429
- start(streamController) {
430
- request.controller = streamController;
431
- flushCompletedQueues(request);
432
- },
433
- cancel(reason) {
434
- abort(request, reason);
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);
435
908
  }
436
- });
437
- request.stream = stream;
909
+ };
910
+ if (options.dataStore === void 0 && options.initialData !== void 0) request.dataStore.hydrate(options.initialData);
438
911
  rootSegment.parentFlushed = true;
439
912
  const rootTask = createTask(request, node, rootSegment, {
440
913
  abortSet: request.abortableTasks,
@@ -442,17 +915,39 @@ function createServerRenderRequest(node, options = {}, mode = {}) {
442
915
  contextValues: /* @__PURE__ */ new Map(),
443
916
  hiddenActivityId: null,
444
917
  hostAncestors: [],
918
+ hostNamespace: "html",
919
+ imagePreloadsSuppressed: false,
445
920
  idPath: "",
921
+ pendingLeadingNewline: false,
446
922
  selectProps: null,
447
923
  stack: null,
448
924
  treeParent: options.renderTree?.tree ?? null,
449
925
  viewTransition: null
450
926
  });
451
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) }));
452
943
  if (options.signal !== void 0) {
453
- const abortListener = () => abort(request, options.signal?.reason);
454
- request.abortListener = abortListener;
455
- options.signal.addEventListener("abort", abortListener, { once: true });
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
+ };
456
951
  }
457
952
  request.workScheduled = true;
458
953
  queueMicrotask(() => {
@@ -463,8 +958,13 @@ function createServerRenderRequest(node, options = {}, mode = {}) {
463
958
  abort: (reason) => abort(request, reason),
464
959
  allReady: allReady.promise,
465
960
  contentType: "text/html; charset=utf-8",
961
+ data: request.dataStore,
466
962
  getData: () => request.dataStore.snapshot(),
467
- getHead: () => request.headSnapshot ?? request.assetRegistry.headHtml(request.nonce),
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
+ },
468
968
  headReady: headReady.promise,
469
969
  shellReady: shellReady.promise,
470
970
  stream
@@ -491,7 +991,10 @@ function forkScope(scope) {
491
991
  contextValues: cloneContextValues(scope.contextValues),
492
992
  hiddenActivityId: scope.hiddenActivityId,
493
993
  hostAncestors: scope.hostAncestors,
994
+ hostNamespace: scope.hostNamespace,
995
+ imagePreloadsSuppressed: scope.imagePreloadsSuppressed,
494
996
  idPath: scope.idPath,
997
+ pendingLeadingNewline: scope.pendingLeadingNewline,
495
998
  selectProps: scope.selectProps,
496
999
  stack: scope.stack,
497
1000
  treeParent: scope.treeParent,
@@ -525,16 +1028,17 @@ function createBoundary(fallbackAbortableTasks, contentSegment) {
525
1028
  completedSegments: [],
526
1029
  contentSegment,
527
1030
  error: null,
1031
+ fallbackSegment: null,
528
1032
  fallbackAbortableTasks,
529
1033
  id: null,
530
1034
  parentFlushed: false,
531
1035
  pendingTasks: 0,
532
- status: "pending"
1036
+ status: "pending",
1037
+ metadataVisible: false
533
1038
  };
534
1039
  }
535
1040
  function performWork(request) {
536
1041
  if (request.status === "closed") return;
537
- if (request.status === "opening") request.status = "open";
538
1042
  const tasks = request.pingedTasks;
539
1043
  request.pingedTasks = [];
540
1044
  for (const task of tasks) retryTask(request, task);
@@ -549,7 +1053,7 @@ function retryTask(request, task) {
549
1053
  completeSegmentText(task.segment);
550
1054
  task.segment.status = "completed";
551
1055
  detachTask(request, task);
552
- finishedTask(request, task, task.segment);
1056
+ finishedTask(request, task);
553
1057
  } catch (error) {
554
1058
  detachTask(request, task);
555
1059
  task.segment.status = "completed";
@@ -557,16 +1061,13 @@ function retryTask(request, task) {
557
1061
  }
558
1062
  }
559
1063
  function createRenderFrame(request, segment, scope) {
560
- const frame = {
1064
+ return {
561
1065
  ...scope,
562
1066
  dispatcher: null,
563
1067
  localIdCounter: 0,
564
- pendingLeadingNewlineHost: null,
565
1068
  request,
566
1069
  segment
567
1070
  };
568
- frame.dispatcher = createServerDispatcher(frame);
569
- return frame;
570
1071
  }
571
1072
  function createServerDispatcher(frame) {
572
1073
  return createStaticDispatcher({
@@ -611,29 +1112,39 @@ function renderNode(node, frame) {
611
1112
  name: "#text",
612
1113
  props: { nodeValue: text }
613
1114
  });
614
- const output = consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(text) : text;
615
1115
  if (frame.segment.lastPushedText) frame.segment.write(TEXT_SEPARATOR);
616
- writeText(output, frame.segment);
1116
+ if (consumePendingLeadingNewline(frame)) writeLeadingNewlineText(text, frame.segment);
1117
+ else writeText(text, frame.segment);
617
1118
  frame.segment.lastPushedText = true;
618
1119
  }
619
1120
  return;
620
1121
  }
621
1122
  if (isPortal(node)) return;
622
- if (!isValidElement(node)) throw invalidChildError(node);
623
- renderElement(node, frame);
1123
+ if (isValidElement(node)) {
1124
+ renderElement(node, frame);
1125
+ return;
1126
+ }
1127
+ if (isThenable(node)) {
1128
+ renderChildren(readThenable(node), frame);
1129
+ return;
1130
+ }
1131
+ throw invalidChildError(node);
624
1132
  }
625
1133
  function renderChildren(node, frame) {
626
1134
  renderChildSequence(collectChildren(node), frame);
627
1135
  }
628
1136
  function renderChildSequence(children, frame, indexBase = 0) {
629
- for (let index = 0; index < children.length; index += 1) try {
630
- withIdSegment(frame, indexBase + index, () => renderNode(children[index], frame));
631
- } catch (error) {
632
- if (isThenable(error)) {
633
- spawnSuspendedTask(frame, children[index], error, indexBase + index);
634
- continue;
1137
+ for (let index = 0; index < children.length; index += 1) {
1138
+ const child = children[index];
1139
+ try {
1140
+ withIdSegment(frame, indexBase + index, () => renderNode(child, frame));
1141
+ } catch (error) {
1142
+ if (isThenable(error)) {
1143
+ spawnSuspendedTask(frame, child, error, indexBase + index);
1144
+ continue;
1145
+ }
1146
+ throw error;
635
1147
  }
636
- throw error;
637
1148
  }
638
1149
  }
639
1150
  function completeSegmentText(segment) {
@@ -678,20 +1189,13 @@ function collectedTreeNode(element) {
678
1189
  function collectedNameAndKind(type) {
679
1190
  if (typeof type === "string") return [type, "host"];
680
1191
  if (type === Fragment) return ["Fragment", "fragment"];
681
- if (isContext(type)) {
682
- const named = type;
683
- return [`${typeof named.displayName === "string" && named.displayName !== "" ? named.displayName : "Context"}.Provider`, "context-provider"];
684
- }
1192
+ if (isContext(type)) return ["Context.Provider", "context-provider"];
685
1193
  if (isAssets(type)) return ["Assets", "assets"];
686
1194
  if (isSuspense(type)) return ["Suspense", "suspense"];
687
1195
  if (isErrorBoundary(type)) return ["ErrorBoundary", "error-boundary"];
688
1196
  if (isActivity(type)) return ["Activity", "activity"];
689
1197
  if (isViewTransition(type)) return ["ViewTransition", "view-transition"];
690
- if (isClientReference(type)) {
691
- const id = type.id;
692
- const exportName = id.slice(id.lastIndexOf("#") + 1);
693
- return [exportName === "" ? "ClientReference" : exportName, "client-reference"];
694
- }
1198
+ if (isClientReference(type)) return [type.id.slice(type.id.lastIndexOf("#") + 1) || "ClientReference", "client-reference"];
695
1199
  if (typeof type === "function") return [type.name === "" ? "Anonymous" : type.name, "function"];
696
1200
  return ["Anonymous", "function"];
697
1201
  }
@@ -740,6 +1244,7 @@ function renderElementKind(element, frame) {
740
1244
  throw new Error(`Unsupported Fig element type: ${describeElementType(type)}.`);
741
1245
  }
742
1246
  function renderFunctionComponent(type, props, frame) {
1247
+ frame.dispatcher ??= createServerDispatcher(frame);
743
1248
  const previousDispatcher = setCurrentDispatcher(frame.dispatcher);
744
1249
  const previousDataStore = setCurrentDataStore(frame.request.dataStore);
745
1250
  const previousStack = frame.stack;
@@ -792,7 +1297,7 @@ function renderAssetValue(value, frame) {
792
1297
  for (const resource of Array.isArray(value) ? value : [value]) {
793
1298
  if (!isFigAssetResource(resource)) throw new Error("The assets prop must contain Fig asset resources.");
794
1299
  try {
795
- if (frame.request.assetRegistry.register(resource)) reportLateHeadAsset(frame.request, resource, frame.stack);
1300
+ frame.request.assetRegistry.register(resource);
796
1301
  } catch (error) {
797
1302
  recordErrorStack(error, frame.stack);
798
1303
  throw error;
@@ -800,18 +1305,14 @@ function renderAssetValue(value, frame) {
800
1305
  frame.segment.assetResources.push(resource);
801
1306
  }
802
1307
  }
803
- function reportLateHeadAsset(request, resource, stack) {
804
- if (request.headSnapshot === null || assetResourceDestination(resource) !== "head") return;
805
- const key = assetResourceKey(resource);
806
- const error = /* @__PURE__ */ new Error(`Fig head resource "${key}" was discovered after headReady. Move required metadata outside pending Suspense boundaries, or wait for allReady before reading getHead().`);
1308
+ function renderAutomaticImagePreload(resource, frame) {
807
1309
  try {
808
- request.onAssetError?.(error, {
809
- componentStack: componentStack(stack),
810
- destination: "head",
811
- key,
812
- resource
813
- });
814
- } catch {}
1310
+ frame.request.assetRegistry.registerAutomaticImage(resource);
1311
+ } catch (error) {
1312
+ recordErrorStack(error, frame.stack);
1313
+ throw error;
1314
+ }
1315
+ frame.segment.assetResources.push(resource);
815
1316
  }
816
1317
  function renderSuspense(props, frame) {
817
1318
  consumePendingLeadingNewline(frame);
@@ -821,6 +1322,7 @@ function renderSuspense(props, frame) {
821
1322
  boundary.activityId = frame.hiddenActivityId;
822
1323
  const parentSegment = frame.segment;
823
1324
  const boundarySegment = createSegment(parentSegment.chunks.length, boundary);
1325
+ boundary.fallbackSegment = boundarySegment;
824
1326
  parentSegment.children.push(boundarySegment);
825
1327
  parentSegment.lastPushedText = false;
826
1328
  contentSegment.parentFlushed = true;
@@ -894,54 +1396,77 @@ function renderActivity(props, frame) {
894
1396
  frame.segment.write("</template>");
895
1397
  }
896
1398
  function renderHostElement(type, props, frame) {
897
- if (renderHostAsset(type, props, frame)) return;
1399
+ const namespace = hostElementNamespace(type, frame.hostNamespace);
1400
+ if (namespace === "html" && renderHostAsset(type, props, frame)) return;
898
1401
  const document = frame.request.document;
899
1402
  if (document !== null && !document.hasHead) {
900
1403
  if (type !== "html" && type !== "head") throw invalidDocumentShellError();
901
1404
  }
902
1405
  if (document !== null && type === "html") frame.segment.write("<!doctype html>");
903
1406
  if (document !== null && type === "head") document.hasHead = true;
904
- const isVoid = isVoidElement(type);
1407
+ const isVoid = namespace === "html" && isVoidElement(type);
905
1408
  const unsafeHTML = unsafeHTMLContent(props);
906
1409
  if (isVoid && hasRenderableChild(props.children)) throw new Error(`Void element <${type}> cannot have children.`);
907
1410
  if (isVoid && unsafeHTML !== null) throw new Error(`Void element <${type}> cannot have unsafeHTML.`);
908
1411
  if (unsafeHTML !== null && hasRenderableChild(props.children)) throw new Error("Host elements cannot have both unsafeHTML and children.");
1412
+ if (namespace === "html") {
1413
+ const imagePreload = imagePreloadFromHostProps(type, props, frame.imagePreloadsSuppressed);
1414
+ if (imagePreload !== null) renderAutomaticImagePreload(imagePreload, frame);
1415
+ }
909
1416
  consumePendingLeadingNewline(frame);
910
1417
  const viewTransition = frame.viewTransition;
911
1418
  writeElementStart(type, viewTransition === null ? props : viewTransitionHostProps(props, viewTransition), frame.segment, frame.selectProps ?? {});
912
1419
  if (document !== null && type === "head") frame.segment.write(earlyEventCaptureMarkup(frame.request));
913
1420
  if (isVoid) return;
914
- const previousPendingLeadingNewlineHost = frame.pendingLeadingNewlineHost;
915
- frame.pendingLeadingNewlineHost = leadingNewlineStrippedHost(type) ? type : null;
1421
+ const previousPendingLeadingNewline = frame.pendingLeadingNewline;
1422
+ const tracksLeadingNewline = leadingNewlineStrippedHost(type);
1423
+ frame.pendingLeadingNewline = tracksLeadingNewline;
916
1424
  if (unsafeHTML !== null) {
917
1425
  frame.segment.write(consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(unsafeHTML) : unsafeHTML);
918
- frame.pendingLeadingNewlineHost = previousPendingLeadingNewlineHost;
1426
+ frame.pendingLeadingNewline = previousPendingLeadingNewline;
919
1427
  writeElementEnd(type, frame.segment);
920
1428
  return;
921
1429
  }
922
- const formText = formTextContent(type, props);
1430
+ const formText = namespace === "html" ? formTextContent(type, props) : null;
923
1431
  if (formText !== null) {
924
1432
  writeText(consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(formText) : formText, frame.segment);
925
- frame.pendingLeadingNewlineHost = previousPendingLeadingNewlineHost;
1433
+ frame.pendingLeadingNewline = previousPendingLeadingNewline;
926
1434
  writeElementEnd(type, frame.segment);
927
1435
  return;
928
1436
  }
929
1437
  const previousSelectProps = frame.selectProps;
930
- if (type === "select") frame.selectProps = props;
1438
+ if (namespace === "html" && type === "select") frame.selectProps = props;
931
1439
  const previousHostAncestors = frame.hostAncestors;
1440
+ const previousHostNamespace = frame.hostNamespace;
1441
+ const previousImagePreloadsSuppressed = frame.imagePreloadsSuppressed;
932
1442
  const previousViewTransition = frame.viewTransition;
933
1443
  if (viewTransition !== null) frame.viewTransition = null;
1444
+ frame.hostNamespace = childHostNamespace(type, namespace);
1445
+ frame.imagePreloadsSuppressed = previousImagePreloadsSuppressed || namespace === "html" && suppressesImagePreloads(type);
1446
+ if (tracksLeadingNewline) frame.segment.chunks.push(leadingNewlineStartMarker);
934
1447
  try {
935
1448
  renderChildren(props.children, frame);
936
1449
  } finally {
937
1450
  frame.selectProps = previousSelectProps;
938
1451
  frame.hostAncestors = previousHostAncestors;
1452
+ frame.hostNamespace = previousHostNamespace;
1453
+ frame.imagePreloadsSuppressed = previousImagePreloadsSuppressed;
939
1454
  frame.viewTransition = previousViewTransition;
940
- frame.pendingLeadingNewlineHost = previousPendingLeadingNewlineHost;
1455
+ frame.pendingLeadingNewline = previousPendingLeadingNewline;
941
1456
  }
1457
+ if (tracksLeadingNewline) frame.segment.chunks.push(leadingNewlineEndMarker);
942
1458
  if (document !== null && type === "head") writeDocumentHeadMarker(frame.segment);
943
1459
  writeElementEnd(type, frame.segment);
944
1460
  }
1461
+ function hostElementNamespace(type, parent) {
1462
+ const normalizedType = type.toLowerCase();
1463
+ if (normalizedType === "svg") return "svg";
1464
+ if (normalizedType === "math") return "mathml";
1465
+ return parent;
1466
+ }
1467
+ function childHostNamespace(type, namespace) {
1468
+ return namespace === "svg" && type.toLowerCase() === "foreignobject" ? "html" : namespace;
1469
+ }
945
1470
  function renderHostAsset(type, props, frame) {
946
1471
  const resource = assetResourceFromHostProps(type, props);
947
1472
  if (resource === null) return false;
@@ -979,16 +1504,16 @@ function pingTask(request, task) {
979
1504
  performWork(request);
980
1505
  });
981
1506
  }
982
- function finishedTask(request, task, segment) {
1507
+ function finishedTask(request, task) {
983
1508
  request.pendingTasks -= 1;
984
1509
  const boundary = task.boundary;
985
1510
  if (boundary === null) {
986
1511
  request.pendingRootTasks -= 1;
987
- if (segment === request.rootSegment || request.completedRootSegment === null) request.completedRootSegment = request.rootSegment;
1512
+ if (task.segment === request.rootSegment || request.completedRootSegment === null) request.completedRootSegment = request.rootSegment;
988
1513
  if (request.pendingRootTasks === 0) finishRootShell(request);
989
1514
  } else {
990
1515
  boundary.pendingTasks -= 1;
991
- if (segment.parentFlushed) enqueueUnique(boundary.completedSegments, segment);
1516
+ if (task.segment.parentFlushed) enqueueUnique(boundary.completedSegments, task.segment);
992
1517
  if (!completeBoundaryIfReady(request, boundary) && boundary.parentFlushed) request.partialBoundaries.add(boundary);
993
1518
  }
994
1519
  if (request.pendingTasks === 0) request.allReady.resolve(void 0);
@@ -1048,7 +1573,7 @@ function markBoundaryClientRendered(request, boundary, error, stack, payload) {
1048
1573
  }
1049
1574
  function abort(request, reason) {
1050
1575
  if (request.status === "closed") return;
1051
- cleanupAbortListener(request);
1576
+ request.cleanupAbortListener();
1052
1577
  request.status = "aborting";
1053
1578
  request.dataStore.dispose();
1054
1579
  const error = abortError(reason);
@@ -1068,7 +1593,7 @@ function abort(request, reason) {
1068
1593
  }
1069
1594
  function fatalError(request, error) {
1070
1595
  if (request.status === "closed") return;
1071
- cleanupAbortListener(request);
1596
+ request.cleanupAbortListener();
1072
1597
  request.status = "closed";
1073
1598
  request.dataStore.dispose();
1074
1599
  request.fatalError = error;
@@ -1085,164 +1610,6 @@ function finishRootShell(request) {
1085
1610
  if (!request.prerender) sealHead(request);
1086
1611
  request.shellReady.resolve(void 0);
1087
1612
  }
1088
- function flushCompletedQueues(request) {
1089
- if (request.controller === null || request.status === "closed") return;
1090
- if (request.status === "opening") return;
1091
- if (request.pendingRootTasks > 0) return;
1092
- if (request.prerender && request.pendingTasks > 0) return;
1093
- sealHead(request);
1094
- if (request.completedRootSegment !== null) {
1095
- flushSegment(request, request.completedRootSegment);
1096
- request.completedRootSegment = null;
1097
- flushWriteBuffer(request);
1098
- }
1099
- drainBoundaryQueue(request, request.clientRenderedBoundaries, flushClientRenderedBoundary);
1100
- drainBoundaryQueue(request, request.completedBoundaries, flushCompletedBoundary);
1101
- drainBoundaryQueue(request, request.partialBoundaries, flushPartialBoundary);
1102
- flushWriteBuffer(request);
1103
- if (request.pendingTasks === 0 && request.completedBoundaries.size === 0 && request.clientRenderedBoundaries.size === 0 && request.partialBoundaries.size === 0) {
1104
- cleanupAbortListener(request);
1105
- request.status = "closed";
1106
- request.dataStore.dispose();
1107
- request.controller.close();
1108
- }
1109
- }
1110
- function flushSegment(request, segment) {
1111
- if (segment.boundary !== null) {
1112
- flushSuspenseBoundary(request, segment, segment.boundary);
1113
- return;
1114
- }
1115
- flushSubtree(request, segment);
1116
- }
1117
- function flushSubtree(request, segment) {
1118
- segment.parentFlushed = true;
1119
- if (segment.status === "pending" || segment.status === "rendering") {
1120
- write(request, placeholderMarkup(request, ensureSegmentId(request, segment)));
1121
- return;
1122
- }
1123
- if (segment.status === "flushed") return;
1124
- segment.status = "flushed";
1125
- if (request.document === null || segment !== request.rootSegment) flushSegmentAssets(request, segment);
1126
- let chunkIndex = 0;
1127
- for (const child of segment.children) {
1128
- for (; chunkIndex < child.index; chunkIndex += 1) writeChunk(request, segment.chunks[chunkIndex], segment);
1129
- flushSegment(request, child);
1130
- }
1131
- for (; chunkIndex < segment.chunks.length; chunkIndex += 1) writeChunk(request, segment.chunks[chunkIndex], segment);
1132
- }
1133
- function flushSuspenseBoundary(request, segment, boundary) {
1134
- segment.boundary = null;
1135
- boundary.parentFlushed = true;
1136
- if (boundary.status === "completed") {
1137
- write(request, `<!--${SUSPENSE_COMPLETED_MARKER}-->`);
1138
- flushBoundaryContent(request, boundary);
1139
- write(request, `<!--${SUSPENSE_END_MARKER}-->`);
1140
- return;
1141
- }
1142
- if (request.prerender && boundary.status === "client-rendered") {
1143
- write(request, `<!--${SUSPENSE_CLIENT_MARKER}-->`);
1144
- write(request, clientRenderedBoundaryPlaceholderMarkup(request, boundary));
1145
- flushSubtree(request, segment);
1146
- write(request, `<!--${SUSPENSE_END_MARKER}-->`);
1147
- return;
1148
- }
1149
- const boundaryIdValue = ensureBoundaryId(request, boundary);
1150
- flushSegmentAssets(request, boundary.contentSegment);
1151
- write(request, `<!--${SUSPENSE_PENDING_PREFIX}${boundaryIdValue}-->`);
1152
- write(request, boundaryPlaceholderMarkup(request, boundaryIdValue));
1153
- flushSubtree(request, segment);
1154
- write(request, `<!--${SUSPENSE_END_MARKER}-->`);
1155
- if (boundary.status === "client-rendered") request.clientRenderedBoundaries.add(boundary);
1156
- else if (boundary.completedSegments.length > 0) request.partialBoundaries.add(boundary);
1157
- }
1158
- function flushBoundaryContent(request, boundary) {
1159
- for (const segment of boundary.completedSegments) flushSegment(request, segment);
1160
- boundary.completedSegments = [];
1161
- }
1162
- function clientRenderedBoundaryPlaceholderMarkup(request, boundary) {
1163
- const id = escapeAttribute(boundaryId(request, ensureBoundaryId(request, boundary)));
1164
- const digest = boundary.error?.digest;
1165
- const message = boundary.error?.message;
1166
- return `<template id="${id}"${digest === void 0 || digest === "" ? "" : ` data-dgst="${escapeAttribute(digest)}"`}${message === void 0 || message === "" ? "" : ` data-msg="${escapeAttribute(message)}"`}></template>`;
1167
- }
1168
- function sealHead(request) {
1169
- if (request.headSnapshot !== null) return;
1170
- const head = request.assetRegistry.headHtml(request.nonce);
1171
- request.headSnapshot = head;
1172
- request.headReady.resolve(head);
1173
- }
1174
- function flushCompletedBoundary(request, boundary) {
1175
- flushPartialBoundary(request, boundary);
1176
- writeBoundaryRevealScript(request, boundary);
1177
- }
1178
- function flushPartialBoundary(request, boundary) {
1179
- for (const segment of boundary.completedSegments) flushBoundarySegment(request, boundary, segment);
1180
- boundary.completedSegments = [];
1181
- }
1182
- function flushBoundarySegment(request, boundary, segment) {
1183
- ensureBoundaryId(request, boundary);
1184
- ensureSegmentId(request, segment);
1185
- const blockingIds = flushSegmentContainer(request, segment);
1186
- if (segment !== boundary.contentSegment) writeSegmentRevealScript(request, segment, blockingIds);
1187
- }
1188
- function writeSegmentRevealScript(request, segment, blockingIds) {
1189
- const id = ensureSegmentId(request, segment);
1190
- writeRuntime(request);
1191
- writeScript(request, withAssetGate(request, blockingIds, `${RUNTIME_REF}.s(${jsString(placeholderId(request, id))},${jsString(segmentId(request, id))})`));
1192
- }
1193
- function writeBoundaryRevealScript(request, boundary) {
1194
- const blockingIds = flushSegmentAssets(request, boundary.contentSegment);
1195
- writeRuntime(request);
1196
- const boundaryRef = jsString(boundaryId(request, ensureBoundaryId(request, boundary)));
1197
- const contentRef = jsString(segmentId(request, ensureSegmentId(request, boundary.contentSegment)));
1198
- const runtime = RUNTIME_REF;
1199
- writeScript(request, withAssetGate(request, blockingIds, boundary.activityId === null ? `${runtime}.c(${boundaryRef},${contentRef})` : `${runtime}.ac(${jsString(boundary.activityId)},${boundaryRef},${contentRef})`));
1200
- }
1201
- function flushSegmentContainer(request, segment) {
1202
- if (segment.status === "flushed") return [];
1203
- const blockingIds = flushSegmentAssets(request, segment);
1204
- write(request, segmentContainerStartMarkup(request, ensureSegmentId(request, segment)));
1205
- flushSegment(request, segment);
1206
- write(request, "</div>");
1207
- return blockingIds;
1208
- }
1209
- function flushSegmentAssets(request, segment) {
1210
- const blockingIds = /* @__PURE__ */ new Set();
1211
- collectSegmentAssets(request, segment, request.assetSink, blockingIds);
1212
- return [...blockingIds];
1213
- }
1214
- function collectSegmentAssets(request, segment, sink, blockingIds) {
1215
- if (segment.status !== "pending" && segment.status !== "rendering") flushAssetList(request, segment.assetResources, sink, blockingIds);
1216
- for (const child of segment.children) collectSegmentAssets(request, child, sink, blockingIds);
1217
- }
1218
- function flushAssetList(request, resources, sink, blockingIds) {
1219
- for (const resource of resources) {
1220
- const id = request.assetRegistry.write(resource, sink);
1221
- if (id !== null) blockingIds.add(id);
1222
- }
1223
- }
1224
- function withAssetGate(request, blockingIds, call) {
1225
- if (blockingIds.length === 0) return call;
1226
- return `${RUNTIME_REF}.r([${blockingIds.map(jsString).join(",")}],()=>{${call}})`;
1227
- }
1228
- function flushClientRenderedBoundary(request, boundary) {
1229
- if (boundary.id === null) return;
1230
- writeRuntime(request);
1231
- const boundaryRef = jsString(boundaryId(request, boundary.id));
1232
- const digest = jsString(boundary.error?.digest ?? "");
1233
- const message = jsString(boundary.error?.message ?? "");
1234
- const runtime = RUNTIME_REF;
1235
- writeScript(request, boundary.activityId === null ? `${runtime}.x(${boundaryRef},${digest},${message})` : `${runtime}.ax(${jsString(boundary.activityId)},${boundaryRef},${digest},${message})`);
1236
- }
1237
- function drainBoundaryQueue(request, queue, flush) {
1238
- for (;;) {
1239
- const first = queue.values().next();
1240
- if (first.done === true) return;
1241
- flush(request, first.value);
1242
- queue.delete(first.value);
1243
- flushWriteBuffer(request);
1244
- }
1245
- }
1246
1613
  function enqueueUnique(queue, item) {
1247
1614
  if (!queue.includes(item)) queue.push(item);
1248
1615
  }
@@ -1265,72 +1632,35 @@ function stackForError(error, fallback) {
1265
1632
  if (typeof error !== "object" && typeof error !== "function" || error === null) return fallback;
1266
1633
  return errorStacks.get(error) ?? fallback;
1267
1634
  }
1268
- function writeRuntime(request) {
1269
- writeRuntime$1(request, (chunk) => write(request, chunk));
1270
- }
1271
- function writeScript(request, code) {
1272
- writeScript$1(request, `(__figSSR=>{${code}})(globalThis[${jsString(request.runtimeName)}])`, (chunk) => write(request, chunk));
1273
- }
1274
1635
  function createRuntimeName(identifierPrefix) {
1275
1636
  const id = nextRuntimeId.toString(36);
1276
1637
  nextRuntimeId += 1;
1277
1638
  const prefix = identifierPrefix?.replace(/[^A-Za-z0-9_$]/g, "_") ?? "";
1278
1639
  return prefix === "" ? `__figSSR_${id}` : `__figSSR_${prefix}_${id}`;
1279
1640
  }
1280
- function writeChunk(request, chunk, segment) {
1281
- if (chunk !== documentHeadMarker) {
1282
- write(request, chunk);
1283
- return;
1284
- }
1285
- if (request.document === null) return;
1286
- write(request, request.assetRegistry.headHtml(request.nonce));
1287
- flushAssetList(request, segment.assetResources, request.assetSink, /* @__PURE__ */ new Set());
1288
- }
1289
- function write(request, chunk) {
1290
- request.writeBuffer.push(chunk);
1291
- }
1292
1641
  function writeDocumentHeadMarker(segment) {
1293
1642
  segment.lastPushedText = false;
1294
1643
  segment.chunks.push(documentHeadMarker);
1295
1644
  }
1296
1645
  function consumePendingLeadingNewline(frame) {
1297
- const pending = frame.pendingLeadingNewlineHost !== null;
1298
- frame.pendingLeadingNewlineHost = null;
1646
+ const pending = frame.pendingLeadingNewline;
1647
+ frame.pendingLeadingNewline = false;
1299
1648
  return pending;
1300
1649
  }
1301
1650
  function leadingNewlineStrippedHost(type) {
1302
1651
  return type === "pre" || type === "textarea";
1303
1652
  }
1653
+ function writeLeadingNewlineText(text, segment) {
1654
+ writeText(text, { write(value) {
1655
+ segment.write({ value });
1656
+ } });
1657
+ }
1304
1658
  function preserveParserStrippedLeadingNewline(text) {
1305
1659
  return text.startsWith("\n") ? `\n${text}` : text;
1306
1660
  }
1307
- function cleanupAbortListener(request) {
1308
- if (request.abortListener === null || request.abortSignal === null) return;
1309
- request.abortSignal.removeEventListener("abort", request.abortListener);
1310
- request.abortListener = null;
1311
- request.abortSignal = null;
1312
- }
1313
- function flushWriteBuffer(request) {
1314
- if (request.writeBuffer.length === 0 || request.controller === null) return;
1315
- request.controller.enqueue(textEncoder.encode(request.writeBuffer.join("")));
1316
- request.writeBuffer = [];
1317
- }
1318
1661
  function invalidDocumentShellError() {
1319
1662
  return /* @__PURE__ */ new Error("renderToDocumentStream requires the root to render an <html> document with a <head>.");
1320
1663
  }
1321
- function ensureSegmentId(request, segment) {
1322
- segment.id ??= request.nextSegmentId++;
1323
- return segment.id;
1324
- }
1325
- function ensureBoundaryId(request, boundary) {
1326
- boundary.id ??= request.nextBoundaryId++;
1327
- return boundary.id;
1328
- }
1329
- function componentStack(stack) {
1330
- const frames = [];
1331
- for (let frame = stack; frame !== null; frame = frame.parent) frames.push(` at ${frame.name}`);
1332
- return frames.length === 0 ? "" : `\n${frames.join("\n")}`;
1333
- }
1334
1664
  function throwIfAborted(signal) {
1335
1665
  if (signal?.aborted === true) throw abortReason(signal.reason);
1336
1666
  }
@@ -1371,7 +1701,9 @@ function renderToDocumentStream(node, options = {}) {
1371
1701
  abort: (reason) => request.abort(reason),
1372
1702
  allReady: request.allReady,
1373
1703
  contentType: request.contentType,
1704
+ data: request.data,
1374
1705
  getData: () => request.getData(),
1706
+ getPreloadHeader: (headerOptions) => request.getPreloadHeader(headerOptions),
1375
1707
  shellReady: request.shellReady,
1376
1708
  stream: request.stream
1377
1709
  };
@@ -1424,6 +1756,6 @@ async function readStreamToString(stream) {
1424
1756
  }
1425
1757
  }
1426
1758
  //#endregion
1427
- export { createRenderTreeCollector, escapeAttribute, escapeText, prerender, renderToDocumentHtml, renderToDocumentStream, renderToHtml, renderToStream };
1759
+ export { createRenderTreeCollector, prerender, renderToDocumentHtml, renderToDocumentStream, renderToHtml, renderToStream };
1428
1760
 
1429
1761
  //# sourceMappingURL=index.js.map