@fictjs/ssr 0.20.0 → 0.22.0

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.cjs CHANGED
@@ -22,18 +22,20 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  createSSRDocument: () => createSSRDocument,
24
24
  renderToDocument: () => renderToDocument,
25
- renderToPartial: () => renderToPartial,
26
25
  renderToPipeableStream: () => renderToPipeableStream,
27
26
  renderToStream: () => renderToStream,
28
27
  renderToString: () => renderToString,
29
28
  renderToStringAsync: () => renderToStringAsync
30
29
  });
31
30
  module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/render-core.ts
32
33
  var import_runtime = require("@fictjs/runtime");
33
- var import_internal = require("@fictjs/runtime/internal");
34
+ var import_internal2 = require("@fictjs/runtime/internal");
34
35
  var import_linkedom = require("linkedom");
35
36
 
36
37
  // src/globals.ts
38
+ var import_internal = require("@fictjs/runtime/internal");
37
39
  function installGlobals(window, document) {
38
40
  const win = window;
39
41
  const required = {
@@ -83,6 +85,14 @@ function installManifest(manifest) {
83
85
  } else {
84
86
  resolved = manifest;
85
87
  }
88
+ const session = (0, import_internal.__fictGetCurrentSSRSession)();
89
+ if (session) {
90
+ const previous = session.manifest;
91
+ session.manifest = resolved;
92
+ return () => {
93
+ session.manifest = previous;
94
+ };
95
+ }
86
96
  const key = "__FICT_MANIFEST__";
87
97
  const snapshot = {
88
98
  exists: Object.prototype.hasOwnProperty.call(globalThis, key),
@@ -129,7 +139,7 @@ function readTextFileFromPath(path) {
129
139
  return fs.readFileSync(path, "utf8");
130
140
  }
131
141
  throw new Error(
132
- "[fict/ssr] `manifest` as file path is only supported in Node.js or Deno. Pass a manifest object in edge runtimes."
142
+ "[fict/ssr] `manifest` as file path is only supported when Deno.readTextFileSync or CommonJS require is available. Pass a manifest object in Node ESM or edge runtimes."
133
143
  );
134
144
  }
135
145
  function getNodeRequire() {
@@ -146,84 +156,6 @@ function getNodeRequire() {
146
156
  }
147
157
 
148
158
  // src/stream-bridge.ts
149
- function createQueuedTextStream(options = {}) {
150
- const encoder = new TextEncoder();
151
- const queue = [];
152
- let controller = null;
153
- let closed = false;
154
- let aborted;
155
- const readyResolvers = [];
156
- const resolveReady = () => {
157
- if (!controller || (controller.desiredSize ?? 1) <= 0) return;
158
- while (readyResolvers.length > 0) {
159
- readyResolvers.shift()?.();
160
- }
161
- };
162
- const drainReady = () => {
163
- while (readyResolvers.length > 0) {
164
- readyResolvers.shift()?.();
165
- }
166
- };
167
- const abortQueue = (reason, notifyController = true) => {
168
- if (closed || aborted !== void 0) return;
169
- aborted = reason ?? new Error("Stream aborted");
170
- queue.length = 0;
171
- drainReady();
172
- if (notifyController) {
173
- controller?.error(aborted);
174
- }
175
- };
176
- const stream = new ReadableStream({
177
- start(ctrl) {
178
- controller = ctrl;
179
- for (const chunk of queue) {
180
- ctrl.enqueue(chunk);
181
- }
182
- queue.length = 0;
183
- if (aborted !== void 0) {
184
- ctrl.error(aborted);
185
- return;
186
- }
187
- if (closed) {
188
- ctrl.close();
189
- }
190
- },
191
- pull() {
192
- resolveReady();
193
- },
194
- cancel(reason) {
195
- abortQueue(reason, false);
196
- options.onCancel?.(reason);
197
- }
198
- });
199
- const writer = {
200
- write(chunk) {
201
- if (closed || aborted !== void 0) return;
202
- const data = encoder.encode(chunk);
203
- if (controller) {
204
- controller.enqueue(data);
205
- if ((controller.desiredSize ?? 1) <= 0) {
206
- return new Promise((resolve) => {
207
- readyResolvers.push(resolve);
208
- });
209
- }
210
- } else {
211
- queue.push(data);
212
- }
213
- return void 0;
214
- },
215
- close() {
216
- if (closed || aborted !== void 0) return;
217
- closed = true;
218
- drainReady();
219
- controller?.close();
220
- },
221
- abort(reason) {
222
- abortQueue(reason);
223
- }
224
- };
225
- return { stream, writer };
226
- }
227
159
  function createPipeBridge() {
228
160
  const nodeBridge = createNodePipeBridge();
229
161
  if (nodeBridge) return nodeBridge;
@@ -231,6 +163,7 @@ function createPipeBridge() {
231
163
  const buffer = [];
232
164
  let state = "open";
233
165
  let abortReason = null;
166
+ let sinkErrorHandler;
234
167
  const safeWrite = (target, chunk) => {
235
168
  try {
236
169
  const ready = target.write(chunk);
@@ -244,7 +177,8 @@ function createPipeBridge() {
244
177
  }
245
178
  });
246
179
  }
247
- } catch {
180
+ } catch (error) {
181
+ sinkErrorHandler?.(error);
248
182
  }
249
183
  return void 0;
250
184
  };
@@ -266,8 +200,14 @@ function createPipeBridge() {
266
200
  safeEnd(target);
267
201
  };
268
202
  return {
269
- pipe(writable) {
203
+ pipe(writable, options) {
270
204
  targets.add(writable);
205
+ if (options?.onError) {
206
+ sinkErrorHandler = options.onError;
207
+ if (typeof writable.on === "function") {
208
+ writable.on("error", options.onError);
209
+ }
210
+ }
271
211
  if (buffer.length > 0) {
272
212
  for (const chunk of buffer) {
273
213
  safeWrite(writable, chunk);
@@ -325,14 +265,24 @@ function createNodePipeBridge() {
325
265
  let piped = false;
326
266
  let state = "open";
327
267
  let abortReason = null;
268
+ const pendingDrains = /* @__PURE__ */ new Set();
269
+ const flushDrains = () => {
270
+ for (const resolve of pendingDrains) resolve();
271
+ pendingDrains.clear();
272
+ };
328
273
  const writeToPassThrough = (chunk) => {
329
274
  if (passThrough.write(chunk) === false) {
330
275
  return new Promise((resolve) => {
276
+ const settle = () => {
277
+ pendingDrains.delete(settle);
278
+ resolve();
279
+ };
280
+ pendingDrains.add(settle);
331
281
  const withOnce = passThrough;
332
282
  if (typeof withOnce.once === "function") {
333
- withOnce.once("drain", resolve);
283
+ withOnce.once("drain", settle);
334
284
  } else {
335
- resolve();
285
+ settle();
336
286
  }
337
287
  });
338
288
  }
@@ -356,9 +306,16 @@ function createNodePipeBridge() {
356
306
  }
357
307
  };
358
308
  return {
359
- pipe(writable) {
309
+ pipe(writable, options) {
360
310
  piped = true;
361
311
  passThrough.pipe(writable);
312
+ const onError = options?.onError;
313
+ if (onError && typeof writable.on === "function") {
314
+ writable.on("error", (err) => {
315
+ flushDrains();
316
+ onError(err);
317
+ });
318
+ }
362
319
  if (state === "aborted") {
363
320
  destroyPassThrough(abortReason ?? new Error("Stream aborted"));
364
321
  return;
@@ -391,6 +348,7 @@ function createNodePipeBridge() {
391
348
  state = "aborted";
392
349
  abortReason = reason instanceof Error ? reason : new Error("Stream aborted");
393
350
  buffer.length = 0;
351
+ flushDrains();
394
352
  if (piped) {
395
353
  destroyPassThrough(abortReason);
396
354
  }
@@ -420,7 +378,7 @@ function createStreamRuntimeCode(options = {}) {
420
378
  }
421
379
  var FICT_STREAM_RUNTIME_CODE = createStreamRuntimeCode({ observerMode: true });
422
380
 
423
- // src/index.ts
381
+ // src/render-core.ts
424
382
  var DEFAULT_HTML = "<!doctype html><html><head></head><body></body></html>";
425
383
  function createSSRDocument(html = DEFAULT_HTML) {
426
384
  const window = (0, import_linkedom.parseHTML)(html);
@@ -431,12 +389,12 @@ function createSSRDocument(html = DEFAULT_HTML) {
431
389
  return { window, document };
432
390
  }
433
391
  function renderToDocument(view, options = {}) {
434
- const session = (0, import_internal.__fictCreateSSRSession)();
435
- return (0, import_internal.__fictRunWithSSRSession)(session, () => renderToDocumentInSession(view, options));
392
+ const session = (0, import_internal2.__fictCreateSSRSession)();
393
+ return (0, import_internal2.__fictRunWithSSRSession)(session, () => renderToDocumentInSession(view, options));
436
394
  }
437
395
  function renderToDocumentInSession(view, options) {
438
396
  const includeSnapshot = options.includeSnapshot !== false;
439
- (0, import_internal.__fictEnableSSR)();
397
+ (0, import_internal2.__fictEnableSSR)();
440
398
  let dom;
441
399
  let restoreGlobals2 = () => {
442
400
  };
@@ -448,23 +406,23 @@ function renderToDocumentInSession(view, options) {
448
406
  try {
449
407
  dom = resolveDom(options);
450
408
  const { document, window } = dom;
451
- const shouldExpose = options.exposeGlobals !== false;
409
+ const shouldExpose = options.exposeGlobals === true;
452
410
  restoreGlobals2 = shouldExpose ? installGlobals(window, document) : () => {
453
411
  };
454
412
  restoreManifest = installManifest(options.manifest);
455
413
  container = resolveContainer(document, options);
456
414
  teardown = (0, import_runtime.render)(view, container);
457
415
  if (includeSnapshot) {
458
- const state = (0, import_internal.__fictSerializeSSRState)();
416
+ const state = (0, import_internal2.__fictSerializeSSRState)();
459
417
  injectSnapshot(document, container, state, options);
460
418
  }
461
419
  } catch (error) {
462
- (0, import_internal.__fictDisableSSR)();
420
+ (0, import_internal2.__fictDisableSSR)();
463
421
  restoreGlobals2();
464
422
  restoreManifest();
465
423
  throw error;
466
424
  }
467
- (0, import_internal.__fictDisableSSR)();
425
+ (0, import_internal2.__fictDisableSSR)();
468
426
  const html = serializeOutput(dom.document, container, options);
469
427
  const dispose = () => {
470
428
  try {
@@ -571,61 +529,13 @@ function renderToPipeableStream(view, options = {}) {
571
529
  });
572
530
  return {
573
531
  pipe(writable) {
574
- bridge.pipe(writable);
532
+ bridge.pipe(writable, { onError: abort });
575
533
  },
576
534
  abort,
577
535
  shellReady,
578
536
  allReady
579
537
  };
580
538
  }
581
- function renderToPartial(view, options = {}) {
582
- const partialOptions = {
583
- ...options,
584
- mode: "shell",
585
- fullDocument: options.fullDocument ?? true
586
- };
587
- let shell = "";
588
- let shellPhase = true;
589
- let abortPartial = null;
590
- const queued = createQueuedTextStream({
591
- onCancel(reason) {
592
- abortPartial?.(reason ?? new Error("Stream canceled"));
593
- }
594
- });
595
- const { shellReady, allReady, abort } = startStreamingRender(
596
- view,
597
- partialOptions,
598
- {
599
- write(chunk) {
600
- if (shellPhase) {
601
- shell += chunk;
602
- return;
603
- }
604
- return queued.writer.write(chunk);
605
- },
606
- close() {
607
- queued.writer.close();
608
- },
609
- abort(reason) {
610
- queued.writer.abort(reason);
611
- }
612
- },
613
- {
614
- includeTailInShell: true,
615
- onShellFlushed() {
616
- shellPhase = false;
617
- }
618
- }
619
- );
620
- abortPartial = abort;
621
- return {
622
- shell,
623
- stream: queued.stream,
624
- shellReady,
625
- allReady,
626
- abort
627
- };
628
- }
629
539
  function resolveDom(options) {
630
540
  if (options.dom) {
631
541
  return options.dom;
@@ -651,14 +561,14 @@ function isPromiseLike(value) {
651
561
  return typeof value === "object" && value !== null && typeof value.then === "function";
652
562
  }
653
563
  function startStreamingRender(view, options, writer, control = {}) {
654
- const session = (0, import_internal.__fictCreateSSRSession)();
655
- return (0, import_internal.__fictRunWithSSRSession)(
564
+ const session = (0, import_internal2.__fictCreateSSRSession)();
565
+ return (0, import_internal2.__fictRunWithSSRSession)(
656
566
  session,
657
567
  () => startStreamingRenderInSession(session, view, options, writer, control)
658
568
  );
659
569
  }
660
570
  function startStreamingRenderInSession(session, view, options, writer, control = {}) {
661
- const runInSession = (fn) => (0, import_internal.__fictRunWithSSRSession)(session, fn);
571
+ const runInSession = (fn) => (0, import_internal2.__fictRunWithSSRSession)(session, fn);
662
572
  const resolvedOptions = {
663
573
  ...options,
664
574
  // Streaming requires a real document; default to fullDocument when unspecified.
@@ -779,10 +689,10 @@ function startStreamingRenderInSession(session, view, options, writer, control =
779
689
  const writeSnapshotForScopes = (scopeIds) => {
780
690
  runInSession(() => {
781
691
  if (!includeSnapshot || scopeIds.length === 0) return;
782
- const registry = (0, import_internal.__fictGetScopeRegistry)();
692
+ const registry = (0, import_internal2.__fictGetScopeRegistry)();
783
693
  const pending = scopeIds.filter((id) => registry.has(id) && !sentScopes.has(id));
784
694
  if (pending.length === 0) return;
785
- const snapshot = (0, import_internal.__fictSerializeSSRStateForScopes)(pending);
695
+ const snapshot = (0, import_internal2.__fictSerializeSSRStateForScopes)(pending);
786
696
  const ids = Object.keys(snapshot.scopes);
787
697
  if (ids.length === 0) return;
788
698
  const chunk = buildIncrementalSnapshotChunk(snapshot, resolvedOptions);
@@ -796,13 +706,13 @@ function startStreamingRenderInSession(session, view, options, writer, control =
796
706
  };
797
707
  const writeSnapshotForBoundary = (boundary) => {
798
708
  runInSession(() => {
799
- const scopes = (0, import_internal.__fictGetScopesForBoundary)(boundary);
709
+ const scopes = (0, import_internal2.__fictGetScopesForBoundary)(boundary);
800
710
  writeSnapshotForScopes(scopes);
801
711
  });
802
712
  };
803
713
  const writeRemainingSnapshots = () => {
804
714
  runInSession(() => {
805
- const scopes = Array.from((0, import_internal.__fictGetScopeRegistry)().keys());
715
+ const scopes = Array.from((0, import_internal2.__fictGetScopeRegistry)().keys());
806
716
  writeSnapshotForScopes(scopes);
807
717
  });
808
718
  };
@@ -811,14 +721,15 @@ function startStreamingRenderInSession(session, view, options, writer, control =
811
721
  removeAbortListener = () => {
812
722
  };
813
723
  runInSession(() => {
814
- (0, import_internal.__fictSetSSRStreamHooks)(null);
815
- (0, import_internal.__fictDisableSSR)();
724
+ (0, import_internal2.__fictSetSSRStreamHooks)(null);
725
+ (0, import_internal2.__fictDisableSSR)();
816
726
  });
817
- restoreGlobals2();
818
- restoreManifest();
819
727
  try {
820
728
  teardown();
821
729
  } catch {
730
+ } finally {
731
+ restoreGlobals2();
732
+ restoreManifest();
822
733
  }
823
734
  };
824
735
  const finalize = () => {
@@ -826,7 +737,7 @@ function startStreamingRenderInSession(session, view, options, writer, control =
826
737
  closed = true;
827
738
  if (mode === "all" && dom && container && !wroteShell) {
828
739
  if (includeSnapshot) {
829
- const snapshot = (0, import_internal.__fictSerializeSSRState)();
740
+ const snapshot = (0, import_internal2.__fictSerializeSSRState)();
830
741
  injectSnapshot(dom.document, container, snapshot, resolvedOptions);
831
742
  }
832
743
  const fullHtml = serializeOutput(dom.document, container, resolvedOptions);
@@ -891,12 +802,13 @@ function startStreamingRenderInSession(session, view, options, writer, control =
891
802
  }
892
803
  };
893
804
  const abort = (reason) => {
894
- if (closed) return;
895
- closed = true;
896
- writeFailed = true;
897
- writer.abort(reason);
898
- cleanup();
899
805
  const abortReason = reason ?? new Error("Stream aborted");
806
+ if (!closed) {
807
+ closed = true;
808
+ writeFailed = true;
809
+ writer.abort(reason);
810
+ cleanup();
811
+ }
900
812
  rejectShell(abortReason);
901
813
  rejectAll(abortReason);
902
814
  };
@@ -911,10 +823,10 @@ function startStreamingRenderInSession(session, view, options, writer, control =
911
823
  }
912
824
  }
913
825
  try {
914
- (0, import_internal.__fictEnableSSR)();
915
- (0, import_internal.__fictSetSSRStreamHooks)(hooks);
826
+ (0, import_internal2.__fictEnableSSR)();
827
+ (0, import_internal2.__fictSetSSRStreamHooks)(hooks);
916
828
  dom = resolveDom(resolvedOptions);
917
- restoreGlobals2 = resolvedOptions.exposeGlobals !== false ? installGlobals(dom.window, dom.document) : () => {
829
+ restoreGlobals2 = resolvedOptions.exposeGlobals === true ? installGlobals(dom.window, dom.document) : () => {
918
830
  };
919
831
  restoreManifest = installManifest(resolvedOptions.manifest);
920
832
  container = resolveContainer(dom.document, resolvedOptions);
@@ -944,7 +856,7 @@ function startStreamingRenderInSession(session, view, options, writer, control =
944
856
  enqueueWrite(shellHtml + streamRuntime);
945
857
  }
946
858
  wroteShell = true;
947
- writeSnapshotForScopes(Array.from((0, import_internal.__fictGetScopeRegistry)().keys()));
859
+ writeSnapshotForScopes(Array.from((0, import_internal2.__fictGetScopeRegistry)().keys()));
948
860
  if (shellCarriesTail && tailHtml) {
949
861
  enqueueWrite(tailHtml);
950
862
  tailHtml = "";
@@ -1107,7 +1019,6 @@ function serializeDoctype(document, override) {
1107
1019
  0 && (module.exports = {
1108
1020
  createSSRDocument,
1109
1021
  renderToDocument,
1110
- renderToPartial,
1111
1022
  renderToPipeableStream,
1112
1023
  renderToStream,
1113
1024
  renderToString,
package/dist/index.d.cts CHANGED
@@ -1,154 +1,2 @@
1
- import { FictNode } from '@fictjs/runtime';
2
-
3
- interface SSRDom {
4
- window: Window;
5
- document: Document;
6
- }
7
- interface RenderToStringOptions {
8
- /**
9
- * Provide a pre-created DOM (document + window). If omitted, a new DOM is
10
- * created per render using `html`.
11
- */
12
- dom?: SSRDom;
13
- /**
14
- * Provide a document directly. If `window` is omitted, `document.defaultView`
15
- * will be used when available.
16
- */
17
- document?: Document;
18
- /**
19
- * Provide a window directly. If `document` is omitted, `window.document` is used.
20
- */
21
- window?: Window;
22
- /**
23
- * HTML template used when creating a new DOM.
24
- */
25
- html?: string;
26
- /**
27
- * Provide a container element to render into.
28
- */
29
- container?: HTMLElement;
30
- /**
31
- * Tag name for the auto-created container.
32
- */
33
- containerTag?: string;
34
- /**
35
- * id applied to the auto-created container.
36
- */
37
- containerId?: string;
38
- /**
39
- * Additional attributes applied to the auto-created container.
40
- */
41
- containerAttributes?: Record<string, string | number | boolean | null | undefined>;
42
- /**
43
- * Return the container element including its outer tag.
44
- */
45
- includeContainer?: boolean;
46
- /**
47
- * Return a full HTML document string (doctype + documentElement.outerHTML).
48
- */
49
- fullDocument?: boolean;
50
- /**
51
- * Override doctype when `fullDocument` is true. Use `null` to omit.
52
- */
53
- doctype?: string | null;
54
- /**
55
- * Expose DOM globals (window/document/Node/Element/etc) during render.
56
- * Defaults to true.
57
- */
58
- exposeGlobals?: boolean;
59
- /**
60
- * Manifest mapping module URLs to built client chunk URLs.
61
- * Can be an object or a path to a JSON file.
62
- * File path mode requires Node.js or Deno filesystem access.
63
- */
64
- manifest?: Record<string, string> | string;
65
- /**
66
- * Include the SSR snapshot script for resumability.
67
- * Defaults to true.
68
- */
69
- includeSnapshot?: boolean;
70
- /**
71
- * Script element id for the snapshot.
72
- */
73
- snapshotScriptId?: string;
74
- /**
75
- * Where to append the snapshot script when not returning full document.
76
- * Defaults to 'container'.
77
- */
78
- snapshotTarget?: 'container' | 'body' | 'head';
79
- /**
80
- * Nonce applied to generated <script> tags for CSP compatibility.
81
- */
82
- scriptNonce?: string;
83
- }
84
- interface RenderToStreamOptions extends RenderToStringOptions {
85
- /**
86
- * Streaming mode:
87
- * - 'shell': send fallback shell first, then patch resolved boundaries
88
- * - 'all': wait for all suspense boundaries, then send full HTML
89
- */
90
- mode?: 'shell' | 'all';
91
- /**
92
- * Called once the initial shell has been written.
93
- */
94
- onShellReady?: () => void;
95
- /**
96
- * Called once all pending boundaries resolve and the stream completes.
97
- */
98
- onAllReady?: () => void;
99
- /**
100
- * Called when an error occurs during streaming.
101
- */
102
- onError?: (err: unknown) => void;
103
- /**
104
- * Abort signal to cancel the stream.
105
- */
106
- signal?: AbortSignal;
107
- /**
108
- * How to load the streaming patch runtime.
109
- * Defaults to 'inline'. Use 'external' with streamRuntimeSrc for strict CSP.
110
- */
111
- streamRuntime?: 'inline' | 'external';
112
- /**
113
- * External streaming patch runtime URL when streamRuntime is 'external'.
114
- */
115
- streamRuntimeSrc?: string;
116
- /**
117
- * How resolved Suspense patch chunks are applied.
118
- * Defaults to 'inline' for inline runtimes and 'observer' for external runtimes.
119
- */
120
- streamPatchMode?: 'inline' | 'observer';
121
- }
122
- interface PipeableStream {
123
- pipe: (writable: NodeJS.WritableStream) => void;
124
- abort: (reason?: unknown) => void;
125
- shellReady: Promise<void>;
126
- allReady: Promise<void>;
127
- }
128
- interface PartialPrerenderResult {
129
- /**
130
- * Complete shell HTML (fallbacks + markers + initial snapshot scripts).
131
- */
132
- shell: string;
133
- /**
134
- * Stream of deferred patch chunks and incremental snapshots.
135
- */
136
- stream: ReadableStream<Uint8Array>;
137
- shellReady: Promise<void>;
138
- allReady: Promise<void>;
139
- abort: (reason?: unknown) => void;
140
- }
141
- interface RenderToDocumentResult extends SSRDom {
142
- html: string;
143
- container: HTMLElement;
144
- dispose: () => void;
145
- }
146
- declare function createSSRDocument(html?: string): SSRDom;
147
- declare function renderToDocument(view: () => FictNode, options?: RenderToStringOptions): RenderToDocumentResult;
148
- declare function renderToString(view: () => FictNode, options?: RenderToStringOptions): string;
149
- declare function renderToStringAsync(view: () => FictNode, options?: RenderToStringOptions): Promise<string>;
150
- declare function renderToStream(view: () => FictNode, options?: RenderToStreamOptions): ReadableStream<Uint8Array>;
151
- declare function renderToPipeableStream(view: () => FictNode, options?: RenderToStreamOptions): PipeableStream;
152
- declare function renderToPartial(view: () => FictNode, options?: RenderToStreamOptions): PartialPrerenderResult;
153
-
154
- export { type PartialPrerenderResult, type PipeableStream, type RenderToDocumentResult, type RenderToStreamOptions, type RenderToStringOptions, type SSRDom, createSSRDocument, renderToDocument, renderToPartial, renderToPipeableStream, renderToStream, renderToString, renderToStringAsync };
1
+ export { P as PipeableStream, g as RenderToDocumentResult, f as RenderToStreamOptions, R as RenderToStringOptions, S as SSRDom, c as createSSRDocument, r as renderToDocument, e as renderToPipeableStream, d as renderToStream, a as renderToString, b as renderToStringAsync } from './experimental.cjs';
2
+ import '@fictjs/runtime';