@bgub/fig-server 0.0.1

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 ADDED
@@ -0,0 +1,1429 @@
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";
4
+ //#region src/html.ts
5
+ const voidElements = /* @__PURE__ */ new Set([
6
+ "area",
7
+ "base",
8
+ "br",
9
+ "col",
10
+ "embed",
11
+ "hr",
12
+ "img",
13
+ "input",
14
+ "link",
15
+ "meta",
16
+ "param",
17
+ "source",
18
+ "track",
19
+ "wbr"
20
+ ]);
21
+ function writeText(value, sink) {
22
+ sink.write(escapeText(value));
23
+ }
24
+ function writeElementStart(type, props, sink, inheritedProps = {}) {
25
+ validateTagName(type);
26
+ sink.write(`<${type}`);
27
+ writeAttributes(type, props, inheritedProps, sink);
28
+ sink.write(">");
29
+ }
30
+ function writeElementEnd(type, sink) {
31
+ sink.write(`</${type}>`);
32
+ }
33
+ function isVoidElement(type) {
34
+ return voidElements.has(type);
35
+ }
36
+ function hasRenderableChild(node) {
37
+ if (Array.isArray(node)) return node.some(hasRenderableChild);
38
+ if (isPortal(node)) return false;
39
+ return !emptyChild(node);
40
+ }
41
+ function formTextContent(type, props) {
42
+ if (type !== "textarea") return null;
43
+ return formString(props.value !== void 0 ? props.value : props.defaultValue);
44
+ }
45
+ function unsafeHTMLContent(props) {
46
+ const value = props.unsafeHTML;
47
+ if (emptyValue(value)) return null;
48
+ if (typeof value === "string") return value;
49
+ throw new Error("The unsafeHTML prop must be a string during server render.");
50
+ }
51
+ function writeAttributes(type, props, inheritedProps, sink) {
52
+ for (const [name, value] of Object.entries(props)) {
53
+ if (reservedProp(name)) continue;
54
+ if (name === "value" && props.defaultValue !== void 0) continue;
55
+ if (name === "checked" && props.defaultChecked !== void 0) continue;
56
+ if (name === "style") {
57
+ const style = serializeStyle(value);
58
+ if (style !== "") writeAttribute(sink, "style", style);
59
+ continue;
60
+ }
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];
91
+ }
92
+ function optionSelected(value, selectProps) {
93
+ const selectValue = selectProps.value !== void 0 ? selectProps.value : selectProps.defaultValue;
94
+ if (emptyValue(selectValue)) return false;
95
+ const optionValue = formString(value);
96
+ if (optionValue === null) return false;
97
+ return selectedValueSet(selectValue).has(optionValue);
98
+ }
99
+ function optionValue(props) {
100
+ return props.value === void 0 ? optionTextValue(props.children) : formString(props.value);
101
+ }
102
+ function optionTextValue(node) {
103
+ if (typeof node === "string" || typeof node === "number") return String(node);
104
+ if (Array.isArray(node)) {
105
+ let text = "";
106
+ for (const child of node) {
107
+ const childText = optionTextValue(child);
108
+ if (childText === null) return null;
109
+ text += childText;
110
+ }
111
+ return text;
112
+ }
113
+ return null;
114
+ }
115
+ function formString(value) {
116
+ if (emptyValue(value)) return null;
117
+ if (serializableAttributeValue(value)) return String(value);
118
+ return null;
119
+ }
120
+ function selectedValueSet(value) {
121
+ return new Set(Array.isArray(value) ? value.map(String) : [String(value)]);
122
+ }
123
+ function serializableAttributeValue(value) {
124
+ return value === true || typeof value === "string" || typeof value === "number" || typeof value === "bigint";
125
+ }
126
+ function emptyValue(value) {
127
+ return value === null || value === void 0 || value === false;
128
+ }
129
+ function emptyChild(value) {
130
+ return value === null || value === void 0 || typeof value === "boolean";
131
+ }
132
+ function writeAttribute(sink, name, value) {
133
+ sink.write(` ${name}="${escapeAttribute(value)}"`);
134
+ }
135
+ function serializeStyle(value) {
136
+ if (emptyValue(value)) return "";
137
+ if (typeof value !== "object" || value === null) throw new Error("The style prop must be an object during server render.");
138
+ const declarations = [];
139
+ for (const [name, item] of Object.entries(value)) {
140
+ if (emptyValue(item)) continue;
141
+ 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)}`);
143
+ }
144
+ return declarations.join(";");
145
+ }
146
+ function reservedProp(name) {
147
+ return name === "children" || name === "key" || name === "events" || name === "bind" || name === "suppressHydrationWarning" || name === "unsafeHTML" || /^on[A-Z]/.test(name);
148
+ }
149
+ function valueProp(name) {
150
+ return name === "value" || name === "defaultValue";
151
+ }
152
+ function styleName(name) {
153
+ if (name.startsWith("--")) return name;
154
+ return name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
155
+ }
156
+ function validateTagName(name) {
157
+ if (!/^[A-Za-z][A-Za-z0-9:._-]*$/.test(name)) throw new Error(`Invalid HTML tag name "${name}".`);
158
+ }
159
+ function validateAttributeName(name) {
160
+ if (/[\s"'<>/=]/.test(name)) throw new Error(`Invalid HTML attribute name "${name}".`);
161
+ }
162
+ function escapeText(value) {
163
+ return value.replace(/[&<>]/g, (character) => {
164
+ if (character === "&") return "&amp;";
165
+ if (character === "<") return "&lt;";
166
+ return "&gt;";
167
+ });
168
+ }
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
+ });
176
+ }
177
+ //#endregion
178
+ //#region src/asset-registry.ts
179
+ var AssetResourceRegistry = class {
180
+ identifierPrefix;
181
+ emittedResources = /* @__PURE__ */ new Set();
182
+ resources = /* @__PURE__ */ new Map();
183
+ stylesheetIds = /* @__PURE__ */ new Map();
184
+ nextStylesheetId = 0;
185
+ constructor(identifierPrefix) {
186
+ this.identifierPrefix = identifierPrefix;
187
+ }
188
+ register(resource) {
189
+ return this.canonical(resource).added;
190
+ }
191
+ write(resource, sink) {
192
+ const { key, resource: current } = this.canonical(resource);
193
+ const id = this.revealBlockerId(key, current);
194
+ if (assetResourceDestination(current) === "head") return id;
195
+ if (this.emittedResources.has(key)) return id;
196
+ this.emittedResources.add(key);
197
+ writeAssetTag(sink, current, id);
198
+ return id;
199
+ }
200
+ headHtml(nonce) {
201
+ let html = "";
202
+ const sink = {
203
+ nonce,
204
+ write(chunk) {
205
+ html += chunk;
206
+ }
207
+ };
208
+ for (const resource of this.resources.values()) if (assetResourceDestination(resource) === "head") writeAssetTag(sink, resource, null);
209
+ return html;
210
+ }
211
+ canonical(resource) {
212
+ const key = assetResourceKey(resource);
213
+ const current = this.resources.get(key);
214
+ if (current !== void 0) {
215
+ 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);
225
+ }
226
+ return {
227
+ added: false,
228
+ key,
229
+ resource: current
230
+ };
231
+ }
232
+ this.resources.set(key, resource);
233
+ return {
234
+ added: true,
235
+ key,
236
+ resource
237
+ };
238
+ }
239
+ revealBlockerId(key, resource) {
240
+ if (resource.kind !== "stylesheet") return null;
241
+ if (resource.blocking === "none") return null;
242
+ return this.stylesheetIdFor(key);
243
+ }
244
+ stylesheetIdFor(key) {
245
+ const current = this.stylesheetIds.get(key);
246
+ if (current !== void 0) return current;
247
+ const id = this.identifierPrefix === "" ? `r-${this.nextStylesheetId}` : `${this.identifierPrefix}-r-${this.nextStylesheetId}`;
248
+ this.nextStylesheetId += 1;
249
+ this.stylesheetIds.set(key, id);
250
+ return id;
251
+ }
252
+ };
253
+ var AssetResourceConflictError = class extends Error {
254
+ constructor(key, current, incoming) {
255
+ super(`Conflicting Fig resource for key "${key}". Existing: ${JSON.stringify(current)}. Incoming: ${JSON.stringify(incoming)}.`);
256
+ }
257
+ };
258
+ function writeAssetTag(sink, resource, id) {
259
+ switch (resource.kind) {
260
+ case "title":
261
+ writeElementStart("title", {}, sink);
262
+ writeText(resource.value, sink);
263
+ writeElementEnd("title", sink);
264
+ return;
265
+ case "meta":
266
+ writeElementStart("meta", {
267
+ charset: resource.charset,
268
+ name: resource.name,
269
+ property: resource.property,
270
+ "http-equiv": resource.httpEquiv,
271
+ content: resource.content,
272
+ "data-fig-resource-key": resource.key
273
+ }, sink);
274
+ return;
275
+ default: {
276
+ const props = Object.fromEntries(assetResourceHostAttributes(resource));
277
+ if (resource.kind === "stylesheet" && id !== null) props.id = id;
278
+ const tag = resource.kind === "script" ? "script" : "link";
279
+ writeElementStart(tag, withNonce(sink, props), sink);
280
+ if (tag === "script") writeElementEnd("script", sink);
281
+ }
282
+ }
283
+ }
284
+ function withNonce(sink, props) {
285
+ return sink.nonce === void 0 ? props : {
286
+ ...props,
287
+ nonce: sink.nonce
288
+ };
289
+ }
290
+ function assetSignature(resource) {
291
+ 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 ?? "");
298
+ 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 ?? "");
300
+ }
301
+ return unsupportedAssetResource(resource);
302
+ }
303
+ function unsupportedAssetResource(resource) {
304
+ throw new Error(`Unsupported asset resource kind: ${resource.kind}`);
305
+ }
306
+ function signature(...values) {
307
+ return JSON.stringify(values);
308
+ }
309
+ //#endregion
310
+ //#region src/protocol.ts
311
+ 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)}}`;
313
+ }
314
+ function writeRuntime$1(request, write) {
315
+ if (request.runtimeWritten) return;
316
+ request.runtimeWritten = true;
317
+ writeScript$1(request, serverRuntimeCodeFor(request.runtimeName), write);
318
+ }
319
+ function writeScript$1(request, code, write) {
320
+ write(`<script${request.nonce === void 0 ? "" : ` nonce="${escapeAttribute(request.nonce)}"`}>${code}<\/script>`);
321
+ }
322
+ function earlyEventCaptureCode() {
323
+ 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
+ }
325
+ function earlyEventCaptureMarkup(request) {
326
+ let markup = "";
327
+ writeScript$1(request, earlyEventCaptureCode(), (chunk) => {
328
+ markup += chunk;
329
+ });
330
+ return markup;
331
+ }
332
+ function placeholderMarkup(request, id) {
333
+ return templateMarkup(placeholderId(request, id));
334
+ }
335
+ function boundaryPlaceholderMarkup(request, id) {
336
+ return templateMarkup(boundaryId(request, id));
337
+ }
338
+ function templateMarkup(id) {
339
+ return `<template id="${escapeAttribute(id)}"></template>`;
340
+ }
341
+ function segmentContainerStartMarkup(request, id) {
342
+ return `<div hidden id="${escapeAttribute(segmentId(request, id))}">`;
343
+ }
344
+ function activityId(request, id) {
345
+ return prefixedId(request, "a", id);
346
+ }
347
+ function placeholderId(request, id) {
348
+ return prefixedId(request, "p", id);
349
+ }
350
+ function segmentId(request, id) {
351
+ return prefixedId(request, "s", id);
352
+ }
353
+ function boundaryId(request, id) {
354
+ return prefixedId(request, "b", id);
355
+ }
356
+ function jsString(value) {
357
+ return JSON.stringify(value).replace(/</g, "\\u003C");
358
+ }
359
+ function prefixedId(request, kind, id) {
360
+ return request.identifierPrefix === "" ? `${kind}-${id}` : `${request.identifierPrefix}-${kind}-${id}`;
361
+ }
362
+ //#endregion
363
+ //#region src/renderer.ts
364
+ const errorStacks = /* @__PURE__ */ new WeakMap();
365
+ const textEncoder = new TextEncoder();
366
+ const documentHeadMarker = Symbol("fig.document-head");
367
+ const RUNTIME_REF = "__figSSR";
368
+ const TEXT_SEPARATOR = "<!--,-->";
369
+ let nextRuntimeId = 0;
370
+ function createServerRenderRequest(node, options = {}, mode = {}) {
371
+ throwIfAborted(options.signal);
372
+ const shellReady = deferred();
373
+ const headReady = deferred();
374
+ const allReady = deferred();
375
+ shellReady.promise.catch(() => void 0);
376
+ headReady.promise.catch(() => void 0);
377
+ allReady.promise.catch(() => void 0);
378
+ const rootSegment = createSegment(0, null);
379
+ const request = {
380
+ abortableTasks: /* @__PURE__ */ new Set(),
381
+ abortListener: null,
382
+ abortSignal: options.signal ?? null,
383
+ allReady,
384
+ completedBoundaries: /* @__PURE__ */ new Set(),
385
+ completedRootSegment: null,
386
+ controller: null,
387
+ dataStore: createDataStore({
388
+ getLane: () => null,
389
+ partition: options.dataPartition,
390
+ schedule: () => void 0
391
+ }),
392
+ fatalError: null,
393
+ identifierPrefix: options.identifierPrefix ?? "",
394
+ nextBoundaryId: 0,
395
+ nextSegmentId: 0,
396
+ nextActivityId: 0,
397
+ nextViewTransitionId: 0,
398
+ nonce: options.nonce,
399
+ onError: options.onError,
400
+ onAssetError: options.onAssetError,
401
+ pendingRootTasks: 0,
402
+ pendingTasks: 0,
403
+ pingedTasks: [],
404
+ assetSink: null,
405
+ rootSegment,
406
+ runtimeName: createRuntimeName(options.identifierPrefix),
407
+ runtimeWritten: false,
408
+ headReady,
409
+ headSnapshot: null,
410
+ shellReady,
411
+ status: "opening",
412
+ stream: null,
413
+ clientRenderedBoundaries: /* @__PURE__ */ new Set(),
414
+ clientReferenceFallback: options.clientReferenceFallback,
415
+ partialBoundaries: /* @__PURE__ */ new Set(),
416
+ prerender: mode.prerender === true,
417
+ componentAssets: options.assets,
418
+ document: mode.document === true ? { hasHead: false } : null,
419
+ assetRegistry: new AssetResourceRegistry(options.identifierPrefix ?? ""),
420
+ resolveAssetKey: options.resolveAssetKey,
421
+ 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);
435
+ }
436
+ });
437
+ request.stream = stream;
438
+ rootSegment.parentFlushed = true;
439
+ const rootTask = createTask(request, node, rootSegment, {
440
+ abortSet: request.abortableTasks,
441
+ boundary: null,
442
+ contextValues: /* @__PURE__ */ new Map(),
443
+ hiddenActivityId: null,
444
+ hostAncestors: [],
445
+ idPath: "",
446
+ selectProps: null,
447
+ stack: null,
448
+ treeParent: options.renderTree?.tree ?? null,
449
+ viewTransition: null
450
+ });
451
+ request.pingedTasks.push(rootTask);
452
+ 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 });
456
+ }
457
+ request.workScheduled = true;
458
+ queueMicrotask(() => {
459
+ request.workScheduled = false;
460
+ performWork(request);
461
+ });
462
+ return {
463
+ abort: (reason) => abort(request, reason),
464
+ allReady: allReady.promise,
465
+ contentType: "text/html; charset=utf-8",
466
+ getData: () => request.dataStore.snapshot(),
467
+ getHead: () => request.headSnapshot ?? request.assetRegistry.headHtml(request.nonce),
468
+ headReady: headReady.promise,
469
+ shellReady: shellReady.promise,
470
+ stream
471
+ };
472
+ }
473
+ function createTask(request, node, segment, scope, childIndexBase = 0) {
474
+ request.pendingTasks += 1;
475
+ if (scope.boundary === null) request.pendingRootTasks += 1;
476
+ else scope.boundary.pendingTasks += 1;
477
+ const task = {
478
+ ...scope,
479
+ childIndexBase,
480
+ node,
481
+ segment
482
+ };
483
+ request.abortableTasks.add(task);
484
+ scope.abortSet.add(task);
485
+ return task;
486
+ }
487
+ function forkScope(scope) {
488
+ return {
489
+ abortSet: scope.abortSet,
490
+ boundary: scope.boundary,
491
+ contextValues: cloneContextValues(scope.contextValues),
492
+ hiddenActivityId: scope.hiddenActivityId,
493
+ hostAncestors: scope.hostAncestors,
494
+ idPath: scope.idPath,
495
+ selectProps: scope.selectProps,
496
+ stack: scope.stack,
497
+ treeParent: scope.treeParent,
498
+ viewTransition: scope.viewTransition === null ? null : { ...scope.viewTransition }
499
+ };
500
+ }
501
+ function createSegment(index, boundary, textSeams = {
502
+ lastPushedText: false,
503
+ textEmbedded: false
504
+ }) {
505
+ return {
506
+ boundary,
507
+ children: [],
508
+ chunks: [],
509
+ id: null,
510
+ index,
511
+ lastPushedText: textSeams.lastPushedText,
512
+ parentFlushed: false,
513
+ assetResources: [],
514
+ status: "pending",
515
+ textEmbedded: textSeams.textEmbedded,
516
+ write(chunk) {
517
+ this.lastPushedText = false;
518
+ this.chunks.push(chunk);
519
+ }
520
+ };
521
+ }
522
+ function createBoundary(fallbackAbortableTasks, contentSegment) {
523
+ return {
524
+ activityId: null,
525
+ completedSegments: [],
526
+ contentSegment,
527
+ error: null,
528
+ fallbackAbortableTasks,
529
+ id: null,
530
+ parentFlushed: false,
531
+ pendingTasks: 0,
532
+ status: "pending"
533
+ };
534
+ }
535
+ function performWork(request) {
536
+ if (request.status === "closed") return;
537
+ if (request.status === "opening") request.status = "open";
538
+ const tasks = request.pingedTasks;
539
+ request.pingedTasks = [];
540
+ for (const task of tasks) retryTask(request, task);
541
+ flushCompletedQueues(request);
542
+ }
543
+ function retryTask(request, task) {
544
+ if (task.segment.status !== "pending") return;
545
+ task.segment.status = "rendering";
546
+ const frame = createRenderFrame(request, task.segment, forkScope(task));
547
+ try {
548
+ renderChildSequence(collectChildren(task.node), frame, task.childIndexBase);
549
+ completeSegmentText(task.segment);
550
+ task.segment.status = "completed";
551
+ detachTask(request, task);
552
+ finishedTask(request, task, task.segment);
553
+ } catch (error) {
554
+ detachTask(request, task);
555
+ task.segment.status = "completed";
556
+ erroredTask(request, task, error);
557
+ }
558
+ }
559
+ function createRenderFrame(request, segment, scope) {
560
+ const frame = {
561
+ ...scope,
562
+ dispatcher: null,
563
+ localIdCounter: 0,
564
+ pendingLeadingNewlineHost: null,
565
+ request,
566
+ segment
567
+ };
568
+ frame.dispatcher = createServerDispatcher(frame);
569
+ return frame;
570
+ }
571
+ function createServerDispatcher(frame) {
572
+ return createStaticDispatcher({
573
+ contextValues: frame.contextValues,
574
+ externalStoreError: "useSyncExternalStore requires getServerSnapshot during server render.",
575
+ readPromise(promise) {
576
+ throwIfAborting(frame.request);
577
+ return readThenable(promise);
578
+ },
579
+ readData(resource, args) {
580
+ throwIfAborting(frame.request);
581
+ return frame.request.dataStore.readData(resource, args, frame);
582
+ },
583
+ preloadData(resource, args) {
584
+ throwIfAborting(frame.request);
585
+ frame.request.dataStore.preloadData(resource, ...args);
586
+ },
587
+ useId() {
588
+ const id = `${frame.request.identifierPrefix}fig-${frame.idPath}-${frame.localIdCounter.toString(32)}`;
589
+ frame.localIdCounter += 1;
590
+ return id;
591
+ },
592
+ updateError: "State updates are not allowed during server render."
593
+ });
594
+ }
595
+ function renderNode(node, frame) {
596
+ if (Array.isArray(node)) {
597
+ renderChildren(node, frame);
598
+ return;
599
+ }
600
+ if (node === null || node === void 0 || typeof node === "boolean") return;
601
+ if (typeof node === "string" || typeof node === "number") {
602
+ const text = String(node);
603
+ if (frame.request.document !== null && !frame.request.document.hasHead) {
604
+ if (text.trim() !== "") throw invalidDocumentShellError();
605
+ }
606
+ if (text !== "") {
607
+ if (frame.treeParent !== null) frame.treeParent.children.push({
608
+ children: [],
609
+ key: null,
610
+ kind: "text",
611
+ name: "#text",
612
+ props: { nodeValue: text }
613
+ });
614
+ const output = consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(text) : text;
615
+ if (frame.segment.lastPushedText) frame.segment.write(TEXT_SEPARATOR);
616
+ writeText(output, frame.segment);
617
+ frame.segment.lastPushedText = true;
618
+ }
619
+ return;
620
+ }
621
+ if (isPortal(node)) return;
622
+ if (!isValidElement(node)) throw invalidChildError(node);
623
+ renderElement(node, frame);
624
+ }
625
+ function renderChildren(node, frame) {
626
+ renderChildSequence(collectChildren(node), frame);
627
+ }
628
+ 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;
635
+ }
636
+ throw error;
637
+ }
638
+ }
639
+ function completeSegmentText(segment) {
640
+ if (segment.textEmbedded && segment.lastPushedText) segment.write(TEXT_SEPARATOR);
641
+ }
642
+ function withIdSegment(frame, index, callback) {
643
+ const previousIdPath = frame.idPath;
644
+ const segment = index.toString(32);
645
+ frame.idPath = previousIdPath === "" ? segment : `${previousIdPath}-${segment}`;
646
+ try {
647
+ return callback();
648
+ } finally {
649
+ frame.idPath = previousIdPath;
650
+ }
651
+ }
652
+ function renderElement(element, frame) {
653
+ if (frame.treeParent === null) {
654
+ renderElementKind(element, frame);
655
+ return;
656
+ }
657
+ const treeNode = collectedTreeNode(element);
658
+ frame.treeParent.children.push(treeNode);
659
+ const previousTreeParent = frame.treeParent;
660
+ frame.treeParent = treeNode;
661
+ try {
662
+ renderElementKind(element, frame);
663
+ } finally {
664
+ frame.treeParent = previousTreeParent;
665
+ }
666
+ }
667
+ function collectedTreeNode(element) {
668
+ const { children: _children, ...ownProps } = element.props;
669
+ const [name, kind] = collectedNameAndKind(element.type);
670
+ return {
671
+ children: [],
672
+ key: element.key ?? null,
673
+ kind,
674
+ name,
675
+ props: ownProps
676
+ };
677
+ }
678
+ function collectedNameAndKind(type) {
679
+ if (typeof type === "string") return [type, "host"];
680
+ 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
+ }
685
+ if (isAssets(type)) return ["Assets", "assets"];
686
+ if (isSuspense(type)) return ["Suspense", "suspense"];
687
+ if (isErrorBoundary(type)) return ["ErrorBoundary", "error-boundary"];
688
+ if (isActivity(type)) return ["Activity", "activity"];
689
+ 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
+ }
695
+ if (typeof type === "function") return [type.name === "" ? "Anonymous" : type.name, "function"];
696
+ return ["Anonymous", "function"];
697
+ }
698
+ function renderElementKind(element, frame) {
699
+ const type = element.type;
700
+ if (typeof type === "string") {
701
+ renderHostElement(type, element.props, frame);
702
+ return;
703
+ }
704
+ if (type === Fragment) {
705
+ renderChildren(element.props.children, frame);
706
+ return;
707
+ }
708
+ if (isContext(type)) {
709
+ renderContextProvider(type, element.props, frame);
710
+ return;
711
+ }
712
+ if (isAssets(type)) {
713
+ renderAssets(element.props, frame);
714
+ return;
715
+ }
716
+ if (isSuspense(type)) {
717
+ renderSuspense(element.props, frame);
718
+ return;
719
+ }
720
+ if (isErrorBoundary(type)) {
721
+ renderChildren(element.props.children, frame);
722
+ return;
723
+ }
724
+ if (isClientReference(type)) {
725
+ renderClientReference(type, element.props, frame);
726
+ return;
727
+ }
728
+ if (isActivity(type)) {
729
+ renderActivity(element.props, frame);
730
+ return;
731
+ }
732
+ if (isViewTransition(type)) {
733
+ renderViewTransition(element.props, frame);
734
+ return;
735
+ }
736
+ if (typeof type === "function") {
737
+ renderFunctionComponent(type, element.props, frame);
738
+ return;
739
+ }
740
+ throw new Error(`Unsupported Fig element type: ${describeElementType(type)}.`);
741
+ }
742
+ function renderFunctionComponent(type, props, frame) {
743
+ const previousDispatcher = setCurrentDispatcher(frame.dispatcher);
744
+ const previousDataStore = setCurrentDataStore(frame.request.dataStore);
745
+ const previousStack = frame.stack;
746
+ const previousLocalIdCounter = frame.localIdCounter;
747
+ frame.stack = {
748
+ name: type.name || "Anonymous",
749
+ parent: previousStack
750
+ };
751
+ frame.localIdCounter = 0;
752
+ try {
753
+ renderComponentAssets(type, frame);
754
+ renderChildren(type(props), frame);
755
+ } catch (error) {
756
+ recordErrorStack(error, frame.stack);
757
+ throw error;
758
+ } finally {
759
+ frame.stack = previousStack;
760
+ frame.localIdCounter = previousLocalIdCounter;
761
+ setCurrentDataStore(previousDataStore);
762
+ setCurrentDispatcher(previousDispatcher);
763
+ }
764
+ }
765
+ function renderClientReference(type, props, frame) {
766
+ if (type.ssr !== void 0) {
767
+ renderComponentAssets(type, frame);
768
+ renderElement(createElement(type.ssr, props), frame);
769
+ return;
770
+ }
771
+ const fallback = frame.request.clientReferenceFallback;
772
+ if (fallback === void 0) {
773
+ renderFunctionComponent(type, props, frame);
774
+ return;
775
+ }
776
+ renderComponentAssets(type, frame);
777
+ renderChildren(fallback(type, props), frame);
778
+ }
779
+ function renderComponentAssets(type, frame) {
780
+ const key = isClientReference(type) ? type.id : frame.request.resolveAssetKey?.(type);
781
+ if (key !== void 0) renderAssetValue(frame.request.componentAssets?.[key], frame);
782
+ }
783
+ function renderContextProvider(context, props, frame) {
784
+ withContextValue(frame.contextValues, context, props.value, () => renderChildren(props.children, frame));
785
+ }
786
+ function renderAssets(props, frame) {
787
+ renderAssetValue(props.assets, frame);
788
+ renderChildren(props.children, frame);
789
+ }
790
+ function renderAssetValue(value, frame) {
791
+ if (value === void 0 || value === null || value === false) return;
792
+ for (const resource of Array.isArray(value) ? value : [value]) {
793
+ if (!isFigAssetResource(resource)) throw new Error("The assets prop must contain Fig asset resources.");
794
+ try {
795
+ if (frame.request.assetRegistry.register(resource)) reportLateHeadAsset(frame.request, resource, frame.stack);
796
+ } catch (error) {
797
+ recordErrorStack(error, frame.stack);
798
+ throw error;
799
+ }
800
+ frame.segment.assetResources.push(resource);
801
+ }
802
+ }
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().`);
807
+ try {
808
+ request.onAssetError?.(error, {
809
+ componentStack: componentStack(stack),
810
+ destination: "head",
811
+ key,
812
+ resource
813
+ });
814
+ } catch {}
815
+ }
816
+ function renderSuspense(props, frame) {
817
+ consumePendingLeadingNewline(frame);
818
+ const fallbackAbortableTasks = /* @__PURE__ */ new Set();
819
+ const contentSegment = createSegment(0, null);
820
+ const boundary = createBoundary(fallbackAbortableTasks, contentSegment);
821
+ boundary.activityId = frame.hiddenActivityId;
822
+ const parentSegment = frame.segment;
823
+ const boundarySegment = createSegment(parentSegment.chunks.length, boundary);
824
+ parentSegment.children.push(boundarySegment);
825
+ parentSegment.lastPushedText = false;
826
+ contentSegment.parentFlushed = true;
827
+ const contentFrame = createRenderFrame(frame.request, contentSegment, {
828
+ ...forkScope(frame),
829
+ boundary
830
+ });
831
+ try {
832
+ renderChildren(props.children, contentFrame);
833
+ contentSegment.status = "completed";
834
+ boundary.completedSegments.push(contentSegment);
835
+ if (boundary.pendingTasks === 0) boundary.status = "completed";
836
+ } catch (error) {
837
+ contentSegment.status = "completed";
838
+ markBoundaryClientRendered(frame.request, boundary, error, frame.stack);
839
+ }
840
+ const advanceSurfaceWatermark = (branch) => {
841
+ if (frame.viewTransition !== null && branch.viewTransition !== null) frame.viewTransition.index = Math.max(frame.viewTransition.index, branch.viewTransition.index);
842
+ };
843
+ advanceSurfaceWatermark(contentFrame);
844
+ if (boundary.status === "completed") return;
845
+ const fallbackFrame = createRenderFrame(frame.request, boundarySegment, {
846
+ ...forkScope(frame),
847
+ abortSet: fallbackAbortableTasks
848
+ });
849
+ try {
850
+ renderChildren(props.fallback, fallbackFrame);
851
+ boundarySegment.status = "completed";
852
+ } catch (error) {
853
+ if (boundary.pendingTasks > 0) for (const task of Array.from(boundary.fallbackAbortableTasks)) abortTask(frame.request, task);
854
+ throw error;
855
+ } finally {
856
+ advanceSurfaceWatermark(fallbackFrame);
857
+ }
858
+ }
859
+ function renderViewTransition(props, frame) {
860
+ const previousViewTransition = frame.viewTransition;
861
+ frame.viewTransition = createServerViewTransition(props, frame.request);
862
+ try {
863
+ renderChildren(props.children, frame);
864
+ } finally {
865
+ frame.viewTransition = previousViewTransition;
866
+ }
867
+ }
868
+ function createServerViewTransition(props, request) {
869
+ return {
870
+ className: serverViewTransitionClass(props),
871
+ index: 0,
872
+ name: props.name === void 0 || props.name === "auto" ? `fig-vt-${request.nextViewTransitionId++}` : props.name
873
+ };
874
+ }
875
+ function serverViewTransitionClass(props) {
876
+ const className = props.default;
877
+ if (className === void 0 || className === "auto" || className === "none") return null;
878
+ return className;
879
+ }
880
+ function renderActivity(props, frame) {
881
+ if (props.mode !== "hidden") {
882
+ renderChildren(props.children, frame);
883
+ return;
884
+ }
885
+ const id = activityId(frame.request, frame.request.nextActivityId++);
886
+ frame.segment.write(`<template ${ACTIVITY_TEMPLATE_ATTRIBUTE}="" id="${escapeAttribute(id)}">`);
887
+ const previousHiddenActivityId = frame.hiddenActivityId;
888
+ frame.hiddenActivityId = id;
889
+ try {
890
+ renderChildren(props.children, frame);
891
+ } finally {
892
+ frame.hiddenActivityId = previousHiddenActivityId;
893
+ }
894
+ frame.segment.write("</template>");
895
+ }
896
+ function renderHostElement(type, props, frame) {
897
+ if (renderHostAsset(type, props, frame)) return;
898
+ const document = frame.request.document;
899
+ if (document !== null && !document.hasHead) {
900
+ if (type !== "html" && type !== "head") throw invalidDocumentShellError();
901
+ }
902
+ if (document !== null && type === "html") frame.segment.write("<!doctype html>");
903
+ if (document !== null && type === "head") document.hasHead = true;
904
+ const isVoid = isVoidElement(type);
905
+ const unsafeHTML = unsafeHTMLContent(props);
906
+ if (isVoid && hasRenderableChild(props.children)) throw new Error(`Void element <${type}> cannot have children.`);
907
+ if (isVoid && unsafeHTML !== null) throw new Error(`Void element <${type}> cannot have unsafeHTML.`);
908
+ if (unsafeHTML !== null && hasRenderableChild(props.children)) throw new Error("Host elements cannot have both unsafeHTML and children.");
909
+ consumePendingLeadingNewline(frame);
910
+ const viewTransition = frame.viewTransition;
911
+ writeElementStart(type, viewTransition === null ? props : viewTransitionHostProps(props, viewTransition), frame.segment, frame.selectProps ?? {});
912
+ if (document !== null && type === "head") frame.segment.write(earlyEventCaptureMarkup(frame.request));
913
+ if (isVoid) return;
914
+ const previousPendingLeadingNewlineHost = frame.pendingLeadingNewlineHost;
915
+ frame.pendingLeadingNewlineHost = leadingNewlineStrippedHost(type) ? type : null;
916
+ if (unsafeHTML !== null) {
917
+ frame.segment.write(consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(unsafeHTML) : unsafeHTML);
918
+ frame.pendingLeadingNewlineHost = previousPendingLeadingNewlineHost;
919
+ writeElementEnd(type, frame.segment);
920
+ return;
921
+ }
922
+ const formText = formTextContent(type, props);
923
+ if (formText !== null) {
924
+ writeText(consumePendingLeadingNewline(frame) ? preserveParserStrippedLeadingNewline(formText) : formText, frame.segment);
925
+ frame.pendingLeadingNewlineHost = previousPendingLeadingNewlineHost;
926
+ writeElementEnd(type, frame.segment);
927
+ return;
928
+ }
929
+ const previousSelectProps = frame.selectProps;
930
+ if (type === "select") frame.selectProps = props;
931
+ const previousHostAncestors = frame.hostAncestors;
932
+ const previousViewTransition = frame.viewTransition;
933
+ if (viewTransition !== null) frame.viewTransition = null;
934
+ try {
935
+ renderChildren(props.children, frame);
936
+ } finally {
937
+ frame.selectProps = previousSelectProps;
938
+ frame.hostAncestors = previousHostAncestors;
939
+ frame.viewTransition = previousViewTransition;
940
+ frame.pendingLeadingNewlineHost = previousPendingLeadingNewlineHost;
941
+ }
942
+ if (document !== null && type === "head") writeDocumentHeadMarker(frame.segment);
943
+ writeElementEnd(type, frame.segment);
944
+ }
945
+ function renderHostAsset(type, props, frame) {
946
+ const resource = assetResourceFromHostProps(type, props);
947
+ if (resource === null) return false;
948
+ renderAssetValue(resource, frame);
949
+ return true;
950
+ }
951
+ function viewTransitionHostProps(props, viewTransition) {
952
+ const index = viewTransition.index++;
953
+ const name = index === 0 ? viewTransition.name : `${viewTransition.name}_${index}`;
954
+ const nextProps = {
955
+ ...props,
956
+ [VIEW_TRANSITION_NAME_ATTRIBUTE]: name
957
+ };
958
+ if (viewTransition.className !== null) nextProps[VIEW_TRANSITION_CLASS_ATTRIBUTE] = viewTransition.className;
959
+ return nextProps;
960
+ }
961
+ function spawnSuspendedTask(frame, node, thenable, childIndexBase) {
962
+ const request = frame.request;
963
+ const segment = createSegment(frame.segment.chunks.length, null, {
964
+ lastPushedText: frame.segment.lastPushedText,
965
+ textEmbedded: true
966
+ });
967
+ frame.segment.lastPushedText = false;
968
+ frame.segment.children.push(segment);
969
+ const task = createTask(request, node, segment, forkScope(frame), childIndexBase);
970
+ thenable.then(() => pingTask(request, task), () => pingTask(request, task));
971
+ }
972
+ function pingTask(request, task) {
973
+ if (request.status === "closed" || request.status === "aborting") return;
974
+ request.pingedTasks.push(task);
975
+ if (request.workScheduled) return;
976
+ request.workScheduled = true;
977
+ queueMicrotask(() => {
978
+ request.workScheduled = false;
979
+ performWork(request);
980
+ });
981
+ }
982
+ function finishedTask(request, task, segment) {
983
+ request.pendingTasks -= 1;
984
+ const boundary = task.boundary;
985
+ if (boundary === null) {
986
+ request.pendingRootTasks -= 1;
987
+ if (segment === request.rootSegment || request.completedRootSegment === null) request.completedRootSegment = request.rootSegment;
988
+ if (request.pendingRootTasks === 0) finishRootShell(request);
989
+ } else {
990
+ boundary.pendingTasks -= 1;
991
+ if (segment.parentFlushed) enqueueUnique(boundary.completedSegments, segment);
992
+ if (!completeBoundaryIfReady(request, boundary) && boundary.parentFlushed) request.partialBoundaries.add(boundary);
993
+ }
994
+ if (request.pendingTasks === 0) request.allReady.resolve(void 0);
995
+ }
996
+ function erroredTask(request, task, error) {
997
+ request.pendingTasks -= 1;
998
+ const boundary = task.boundary;
999
+ if (boundary === null) {
1000
+ request.pendingRootTasks -= 1;
1001
+ fatalError(request, error);
1002
+ return;
1003
+ }
1004
+ boundary.pendingTasks -= 1;
1005
+ markBoundaryClientRendered(request, boundary, error, task.stack);
1006
+ if (request.pendingTasks === 0) request.allReady.resolve(void 0);
1007
+ }
1008
+ function detachTask(request, task) {
1009
+ task.abortSet.delete(task);
1010
+ request.abortableTasks.delete(task);
1011
+ }
1012
+ function abortTask(request, task) {
1013
+ if (!request.abortableTasks.delete(task)) return;
1014
+ task.segment.status = "completed";
1015
+ task.abortSet.delete(task);
1016
+ request.pendingTasks -= 1;
1017
+ const boundary = task.boundary;
1018
+ if (boundary === null) {
1019
+ request.pendingRootTasks -= 1;
1020
+ if (request.pendingRootTasks === 0) finishRootShell(request);
1021
+ } else {
1022
+ boundary.pendingTasks -= 1;
1023
+ completeBoundaryIfReady(request, boundary);
1024
+ }
1025
+ if (request.pendingTasks === 0) request.allReady.resolve(void 0);
1026
+ }
1027
+ function completeBoundaryIfReady(request, boundary) {
1028
+ if (boundary.pendingTasks !== 0 || boundary.status !== "pending") return false;
1029
+ boundary.status = "completed";
1030
+ abortFallbackTasks(request, boundary);
1031
+ if (boundary.parentFlushed) request.completedBoundaries.add(boundary);
1032
+ return true;
1033
+ }
1034
+ function abortFallbackTasks(request, boundary) {
1035
+ for (const fallbackTask of Array.from(boundary.fallbackAbortableTasks)) abortTask(request, fallbackTask);
1036
+ }
1037
+ function markBoundaryClientRendered(request, boundary, error, stack, payload) {
1038
+ if (boundary.status !== "client-rendered") {
1039
+ boundary.status = "client-rendered";
1040
+ boundary.error = payload ?? reportBoundaryError(request, error, stack);
1041
+ }
1042
+ boundary.completedSegments = [];
1043
+ request.completedBoundaries.delete(boundary);
1044
+ request.partialBoundaries.delete(boundary);
1045
+ for (const task of Array.from(request.abortableTasks)) if (task.boundary === boundary) abortTask(request, task);
1046
+ for (const task of Array.from(boundary.fallbackAbortableTasks)) abortTask(request, task);
1047
+ if (boundary.parentFlushed) request.clientRenderedBoundaries.add(boundary);
1048
+ }
1049
+ function abort(request, reason) {
1050
+ if (request.status === "closed") return;
1051
+ cleanupAbortListener(request);
1052
+ request.status = "aborting";
1053
+ request.dataStore.dispose();
1054
+ const error = abortError(reason);
1055
+ request.fatalError = error;
1056
+ if (request.pendingRootTasks > 0) {
1057
+ fatalError(request, error);
1058
+ return;
1059
+ }
1060
+ for (const task of Array.from(request.abortableTasks)) {
1061
+ const boundary = task.boundary;
1062
+ if (boundary !== null) markBoundaryClientRendered(request, boundary, error, task.stack, {});
1063
+ }
1064
+ request.abortableTasks.clear();
1065
+ request.pendingTasks = 0;
1066
+ request.allReady.resolve(void 0);
1067
+ flushCompletedQueues(request);
1068
+ }
1069
+ function fatalError(request, error) {
1070
+ if (request.status === "closed") return;
1071
+ cleanupAbortListener(request);
1072
+ request.status = "closed";
1073
+ request.dataStore.dispose();
1074
+ request.fatalError = error;
1075
+ request.headReady.reject(error);
1076
+ request.shellReady.reject(error);
1077
+ request.allReady.reject(error);
1078
+ request.controller?.error(error);
1079
+ }
1080
+ function finishRootShell(request) {
1081
+ if (request.document !== null && !request.document.hasHead) {
1082
+ fatalError(request, invalidDocumentShellError());
1083
+ return;
1084
+ }
1085
+ if (!request.prerender) sealHead(request);
1086
+ request.shellReady.resolve(void 0);
1087
+ }
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
+ function enqueueUnique(queue, item) {
1247
+ if (!queue.includes(item)) queue.push(item);
1248
+ }
1249
+ function reportBoundaryError(request, error, stack) {
1250
+ const info = { componentStack: componentStack(stackForError(error, stack)) };
1251
+ if (request.onError === void 0) return {};
1252
+ try {
1253
+ return request.onError(error, info) ?? {};
1254
+ } catch {
1255
+ return {};
1256
+ }
1257
+ }
1258
+ function recordErrorStack(error, stack) {
1259
+ if (stack === null) return;
1260
+ if (typeof error !== "object" && typeof error !== "function") return;
1261
+ if (error === null || isThenable(error)) return;
1262
+ if (!errorStacks.has(error)) errorStacks.set(error, stack);
1263
+ }
1264
+ function stackForError(error, fallback) {
1265
+ if (typeof error !== "object" && typeof error !== "function" || error === null) return fallback;
1266
+ return errorStacks.get(error) ?? fallback;
1267
+ }
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
+ function createRuntimeName(identifierPrefix) {
1275
+ const id = nextRuntimeId.toString(36);
1276
+ nextRuntimeId += 1;
1277
+ const prefix = identifierPrefix?.replace(/[^A-Za-z0-9_$]/g, "_") ?? "";
1278
+ return prefix === "" ? `__figSSR_${id}` : `__figSSR_${prefix}_${id}`;
1279
+ }
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
+ function writeDocumentHeadMarker(segment) {
1293
+ segment.lastPushedText = false;
1294
+ segment.chunks.push(documentHeadMarker);
1295
+ }
1296
+ function consumePendingLeadingNewline(frame) {
1297
+ const pending = frame.pendingLeadingNewlineHost !== null;
1298
+ frame.pendingLeadingNewlineHost = null;
1299
+ return pending;
1300
+ }
1301
+ function leadingNewlineStrippedHost(type) {
1302
+ return type === "pre" || type === "textarea";
1303
+ }
1304
+ function preserveParserStrippedLeadingNewline(text) {
1305
+ return text.startsWith("\n") ? `\n${text}` : text;
1306
+ }
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
+ function invalidDocumentShellError() {
1319
+ return /* @__PURE__ */ new Error("renderToDocumentStream requires the root to render an <html> document with a <head>.");
1320
+ }
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
+ function throwIfAborted(signal) {
1335
+ if (signal?.aborted === true) throw abortReason(signal.reason);
1336
+ }
1337
+ function throwIfAborting(request) {
1338
+ if (request.status === "aborting") throw abortReason(request.fatalError);
1339
+ }
1340
+ function abortError(reason) {
1341
+ if (reason instanceof Error) return reason;
1342
+ return new Error(typeof reason === "string" ? reason : "Server render was aborted.");
1343
+ }
1344
+ function abortReason(reason) {
1345
+ return reason ?? /* @__PURE__ */ new Error("Server render was aborted.");
1346
+ }
1347
+ function describeElementType(type) {
1348
+ if (typeof type === "symbol") return String(type);
1349
+ if (typeof type === "function") return type.name || "anonymous function";
1350
+ return typeof type;
1351
+ }
1352
+ //#endregion
1353
+ //#region src/render-tree.ts
1354
+ function createRenderTreeCollector() {
1355
+ return { tree: {
1356
+ children: [],
1357
+ key: null,
1358
+ kind: "root",
1359
+ name: "Root",
1360
+ props: {}
1361
+ } };
1362
+ }
1363
+ //#endregion
1364
+ //#region src/index.ts
1365
+ function renderToStream(node, options = {}) {
1366
+ return createServerRenderRequest(node, options);
1367
+ }
1368
+ function renderToDocumentStream(node, options = {}) {
1369
+ const request = createServerRenderRequest(node, options, { document: true });
1370
+ return {
1371
+ abort: (reason) => request.abort(reason),
1372
+ allReady: request.allReady,
1373
+ contentType: request.contentType,
1374
+ getData: () => request.getData(),
1375
+ shellReady: request.shellReady,
1376
+ stream: request.stream
1377
+ };
1378
+ }
1379
+ /**
1380
+ * The streamed output, buffered: awaits `allReady` and concatenates exactly
1381
+ * the bytes a streaming client would have received — including the inline
1382
+ * streaming runtime and boundary-reveal scripts when the tree suspends past
1383
+ * the shell. Right for caching responses and snapshotting wire output; it is
1384
+ * NOT React's `renderToString` (use `prerender` for settled, script-free
1385
+ * static markup).
1386
+ */
1387
+ async function renderToHtml(node, options = {}) {
1388
+ const result = renderToStream(node, options);
1389
+ await result.allReady;
1390
+ return readStreamToString(result.stream);
1391
+ }
1392
+ /** Document-mode {@link renderToHtml}: the streamed document, buffered. */
1393
+ async function renderToDocumentHtml(node, options = {}) {
1394
+ const result = renderToDocumentStream(node, options);
1395
+ await result.allReady;
1396
+ return readStreamToString(result.stream);
1397
+ }
1398
+ /**
1399
+ * Settled static HTML: waits for all async work before flushing, so completed
1400
+ * Suspense content is emitted in logical position without streaming scripts.
1401
+ */
1402
+ async function prerender(node, options = {}) {
1403
+ const { document = false, ...renderOptions } = options;
1404
+ const result = createServerRenderRequest(node, renderOptions, {
1405
+ document,
1406
+ prerender: true
1407
+ });
1408
+ await result.allReady;
1409
+ const html = await readStreamToString(result.stream);
1410
+ return {
1411
+ data: result.getData(),
1412
+ head: document ? "" : result.getHead(),
1413
+ html
1414
+ };
1415
+ }
1416
+ async function readStreamToString(stream) {
1417
+ const reader = stream.getReader();
1418
+ const textDecoder = new TextDecoder();
1419
+ let output = "";
1420
+ for (;;) {
1421
+ const { done, value } = await reader.read();
1422
+ if (done) return output + textDecoder.decode();
1423
+ output += textDecoder.decode(value, { stream: true });
1424
+ }
1425
+ }
1426
+ //#endregion
1427
+ export { createRenderTreeCollector, escapeAttribute, escapeText, prerender, renderToDocumentHtml, renderToDocumentStream, renderToHtml, renderToStream };
1428
+
1429
+ //# sourceMappingURL=index.js.map