@sigx/server-renderer 0.1.26 → 0.2.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.
@@ -1,20 +1,50 @@
1
- import { n as internals_exports, r as __commonJSMin } from "./types-CkI_lB93.js";
1
+ import { n as internals_exports, r as __commonJSMin } from "./types-DYlI_C8F.js";
2
2
  import { show } from "@sigx/runtime-dom";
3
- import { Fragment, Text, getCurrentInstance, isComponent, isDirective, signal } from "sigx";
3
+ import { Comment, Fragment, Text, getCurrentInstance, isComponent, isDirective, signal } from "sigx";
4
+ //#region src/builtin-ssr-directives.ts
5
+ /**
6
+ * Built-in directive SSR support — lazy patching.
7
+ *
8
+ * This module patches `getSSRProps` onto built-in directives (like `show`)
9
+ * at runtime, keeping `@sigx/runtime-dom` free of SSR knowledge.
10
+ *
11
+ * Mirrors Vue 3's `initVShowForSSR()` / `initDirectivesForSSR()` pattern.
12
+ *
13
+ * @internal
14
+ */
4
15
  var _initialized = false;
16
+ /**
17
+ * Patch `getSSRProps` onto the `show` directive for SSR support.
18
+ *
19
+ * Called lazily from `initDirectivesForSSR()` — not at import time,
20
+ * so tree-shaking can eliminate this in client-only builds.
21
+ */
5
22
  function initShowForSSR() {
6
23
  show.getSSRProps = ({ value }) => {
7
24
  if (!value) return { style: { display: "none" } };
8
25
  };
9
26
  }
27
+ /**
28
+ * Initialize SSR support for all built-in directives.
29
+ *
30
+ * Must be called before any SSR rendering occurs.
31
+ * Safe to call multiple times — only patches once.
32
+ */
10
33
  function initDirectivesForSSR() {
11
34
  if (_initialized) return;
12
35
  _initialized = true;
13
36
  initShowForSSR();
14
37
  }
38
+ //#endregion
39
+ //#region __vite-browser-external
15
40
  var require___vite_browser_external = /* @__PURE__ */ __commonJSMin(((exports, module) => {
16
41
  module.exports = {};
17
42
  }));
43
+ //#endregion
44
+ //#region src/server/context.ts
45
+ /**
46
+ * Create a new SSR context for rendering
47
+ */
18
48
  function createSSRContext(options = {}) {
19
49
  let componentId = 0;
20
50
  const componentStack = [];
@@ -51,6 +81,19 @@ function createSSRContext(options = {}) {
51
81
  }
52
82
  };
53
83
  }
84
+ //#endregion
85
+ //#region src/server/render-core.ts
86
+ /**
87
+ * Core rendering logic for SSR
88
+ *
89
+ * The async generator `renderToChunks` walks a VNode tree and yields HTML strings.
90
+ * Handles text, fragments, host elements, and delegates components to the
91
+ * component renderer.
92
+ *
93
+ * This module is strategy-agnostic. Island-specific logic (signal tracking,
94
+ * hydration directives, async streaming) lives in @sigx/ssr-islands and is
95
+ * injected through the SSRPlugin hooks.
96
+ */
54
97
  var ESCAPE = {
55
98
  "&": "&",
56
99
  "<": "&lt;",
@@ -61,7 +104,9 @@ var ESCAPE = {
61
104
  function escapeHtml$1(s) {
62
105
  return s.replace(/[&<>"']/g, (c) => ESCAPE[c]);
63
106
  }
107
+ /** Cache for camelCase → kebab-case conversions (same properties repeat across elements) */
64
108
  var kebabCache = {};
109
+ /** Void elements that cannot have children — hoisted to module scope as a Set for O(1) lookup */
65
110
  var VOID_ELEMENTS = new Set([
66
111
  "area",
67
112
  "base",
@@ -82,6 +127,15 @@ function camelToKebab(str) {
82
127
  if (str.startsWith("--")) return str;
83
128
  return kebabCache[str] ||= str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
84
129
  }
130
+ /**
131
+ * Parse a CSS string into a style object.
132
+ *
133
+ * Handles edge cases: parens in values (e.g., `linear-gradient(...)`),
134
+ * CSS comments, and colons in values.
135
+ *
136
+ * Adapted from Vue 3's `parseStringStyle` — battle-tested, split-based,
137
+ * fast in V8.
138
+ */
85
139
  var listDelimiterRE = /;(?![^(]*\))/g;
86
140
  var propertyDelimiterRE = /:([^]+)/;
87
141
  var styleCommentRE = /\/\*[^]*?\*\//g;
@@ -95,6 +149,12 @@ function parseStringStyle(cssText) {
95
149
  });
96
150
  return ret;
97
151
  }
152
+ /**
153
+ * Serialize a style object to a CSS string.
154
+ *
155
+ * Uses for...in + string concat (avoids Object.entries/map/join allocations)
156
+ * and cached kebab-case conversion.
157
+ */
98
158
  function stringifyStyle(style) {
99
159
  let ret = "";
100
160
  for (const key in style) {
@@ -103,11 +163,15 @@ function stringifyStyle(style) {
103
163
  }
104
164
  return ret;
105
165
  }
166
+ /**
167
+ * Check if element will render as text content
168
+ */
106
169
  function isTextContent(element) {
107
170
  if (element == null || element === false || element === true) return false;
108
171
  if (typeof element === "string" || typeof element === "number") return true;
109
172
  return element.type === Text;
110
173
  }
174
+ /** Check if all children are leaf types (text, number, null, bool, Text vnode) */
111
175
  function allChildrenAreLeaves(children) {
112
176
  for (const child of children) {
113
177
  if (child == null || child === false || child === true) continue;
@@ -117,6 +181,11 @@ function allChildrenAreLeaves(children) {
117
181
  }
118
182
  return true;
119
183
  }
184
+ /**
185
+ * Merge style values for SSR (element style + directive SSR style).
186
+ * Either value can be an object, string, or undefined.
187
+ * String styles are parsed into objects before merging.
188
+ */
120
189
  function mergeSSRStyles(elementStyle, directiveStyle) {
121
190
  if (!elementStyle) return directiveStyle;
122
191
  if (!directiveStyle) return elementStyle;
@@ -127,8 +196,19 @@ function mergeSSRStyles(elementStyle, directiveStyle) {
127
196
  ...b
128
197
  };
129
198
  }
199
+ /**
200
+ * Render element to string chunks (generator for streaming)
201
+ * @param element - The JSX element to render
202
+ * @param ctx - The SSR context for tracking state
203
+ * @param parentCtx - The parent component context for provide/inject
204
+ * @param appContext - The app context for app-level provides (from defineApp)
205
+ */
130
206
  async function* renderToChunks(element, ctx, parentCtx = null, appContext = null) {
131
207
  if (element == null || element === false || element === true) return;
208
+ if (element.type === Comment) {
209
+ yield "<!---->";
210
+ return;
211
+ }
132
212
  if (typeof element === "string" || typeof element === "number") {
133
213
  yield escapeHtml$1(String(element));
134
214
  return;
@@ -345,13 +425,28 @@ async function* renderToChunks(element, ctx, parentCtx = null, appContext = null
345
425
  yield `</${tagName}>`;
346
426
  }
347
427
  }
428
+ /**
429
+ * Helper to render a VNode to string (for deferred async content)
430
+ */
348
431
  async function renderVNodeToString(element, ctx, appContext = null) {
349
432
  let result = "";
350
433
  for await (const chunk of renderToChunks(element, ctx, null, appContext)) result += chunk;
351
434
  return result;
352
435
  }
436
+ /**
437
+ * Synchronous render-to-string that avoids async generator overhead.
438
+ * Returns null if any async operation is encountered (caller should fall back
439
+ * to the async generator path).
440
+ *
441
+ * For purely synchronous component trees this eliminates thousands of
442
+ * microtask/Promise allocations from the AsyncGenerator protocol.
443
+ */
353
444
  function renderToStringSync(element, ctx, parentCtx, appContext, buf) {
354
445
  if (element == null || element === false || element === true) return true;
446
+ if (element.type === Comment) {
447
+ buf.push("<!---->");
448
+ return true;
449
+ }
355
450
  if (typeof element === "string" || typeof element === "number") {
356
451
  buf.push(escapeHtml$1(String(element)));
357
452
  return true;
@@ -528,9 +623,28 @@ function renderToStringSync(element, ctx, parentCtx, appContext, buf) {
528
623
  }
529
624
  return true;
530
625
  }
626
+ //#endregion
627
+ //#region src/server/streaming.ts
628
+ /**
629
+ * Core streaming utilities for async SSR
630
+ *
631
+ * Provides the client-side `$SIGX_REPLACE` function and replacement script
632
+ * generation used by core async streaming. These are strategy-agnostic —
633
+ * any async component with `ssr.load()` gets streamed without needing a plugin.
634
+ *
635
+ * Plugins (e.g., islands) can augment replacements via `onAsyncComponentResolved`.
636
+ */
637
+ /**
638
+ * Escape a JSON string for safe embedding inside <script> tags.
639
+ * Prevents XSS by replacing characters that could break out of the script context.
640
+ */
531
641
  function escapeJsonForScript(json) {
532
642
  return json.replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
533
643
  }
644
+ /**
645
+ * Generate the streaming bootstrap script (injected once before any replacements).
646
+ * Defines `window.$SIGX_REPLACE` which swaps async placeholders with rendered HTML.
647
+ */
534
648
  function generateStreamingScript() {
535
649
  return `
536
650
  <script>
@@ -548,24 +662,67 @@ window.$SIGX_REPLACE = function(id, html) {
548
662
  };
549
663
  <\/script>`;
550
664
  }
665
+ /**
666
+ * Generate a replacement script for a resolved async component.
667
+ */
551
668
  function generateReplacementScript(id, html, extraScript) {
552
669
  let script = `<script>$SIGX_REPLACE(${id}, ${escapeJsonForScript(JSON.stringify(html))});`;
553
670
  if (extraScript) script += extraScript;
554
671
  script += `<\/script>`;
555
672
  return script;
556
673
  }
674
+ //#endregion
675
+ //#region src/head.ts
676
+ /**
677
+ * Head management composable for SSR and client-side.
678
+ *
679
+ * Provides `useHead()` for managing `<head>` elements (title, meta, link, script)
680
+ * from within components. Works during SSR (collects into SSRContext._head) and
681
+ * on the client (updates DOM directly).
682
+ *
683
+ * @example
684
+ * ```tsx
685
+ * import { useHead } from '@sigx/server-renderer/head';
686
+ *
687
+ * function MyPage(ctx) {
688
+ * useHead({
689
+ * title: 'My Page',
690
+ * meta: [
691
+ * { name: 'description', content: 'A great page' },
692
+ * { property: 'og:title', content: 'My Page' }
693
+ * ],
694
+ * link: [
695
+ * { rel: 'canonical', href: 'https://example.com/my-page' }
696
+ * ]
697
+ * });
698
+ *
699
+ * return () => <div>Page content</div>;
700
+ * }
701
+ * ```
702
+ */
557
703
  var _ssrHeadConfigs = [];
558
704
  var _isSSR = false;
705
+ /**
706
+ * Enable SSR mode for head management.
707
+ * Called by the SSR renderer before rendering starts.
708
+ */
559
709
  function enableSSRHead() {
560
710
  _isSSR = true;
561
711
  _ssrHeadConfigs = [];
562
712
  }
713
+ /**
714
+ * Disable SSR mode and return collected configs.
715
+ */
563
716
  function collectSSRHead() {
564
717
  _isSSR = false;
565
718
  const configs = _ssrHeadConfigs;
566
719
  _ssrHeadConfigs = [];
567
720
  return configs;
568
721
  }
722
+ /**
723
+ * Render collected head configs to an HTML string.
724
+ * Deduplicates meta tags by name/property and uses the last title.
725
+ */
569
726
  function renderHeadToString(configs) {
570
727
  const parts = [];
571
728
  const seenMeta = /* @__PURE__ */ new Map();
@@ -647,6 +804,14 @@ function applyHeadClient(config) {
647
804
  for (const el of managed) el.remove();
648
805
  };
649
806
  }
807
+ /**
808
+ * Manage `<head>` elements from within a component.
809
+ *
810
+ * During SSR, collects head configs for later rendering with `renderHeadToString()`.
811
+ * On the client, updates the DOM directly. Cleans up on component unmount.
812
+ *
813
+ * @param config - Head configuration (title, meta, link, script, etc.)
814
+ */
650
815
  function useHead(config) {
651
816
  if (_isSSR) {
652
817
  _ssrHeadConfigs.push(config);
@@ -662,10 +827,18 @@ function escapeHtml(s) {
662
827
  function escapeAttr(s) {
663
828
  return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
664
829
  }
830
+ //#endregion
831
+ //#region src/ssr.ts
665
832
  var import___vite_browser_external = require___vite_browser_external();
833
+ /**
834
+ * Check if the input is an App instance (created via defineApp)
835
+ */
666
836
  function isApp(input) {
667
837
  return input && typeof input === "object" && "_rootComponent" in input && "_context" in input;
668
838
  }
839
+ /**
840
+ * Extract the JSX element and optional AppContext from a render input.
841
+ */
669
842
  function extractInput(input) {
670
843
  if (isApp(input)) return {
671
844
  element: input._rootComponent,
@@ -676,6 +849,15 @@ function extractInput(input) {
676
849
  appContext: null
677
850
  };
678
851
  }
852
+ /**
853
+ * Yield all async streaming chunks — core-managed and plugin-managed — interleaved
854
+ * so the fastest component streams first regardless of who manages it.
855
+ *
856
+ * Core-managed: ctx._pendingAsync (from render-core when no plugin overrides)
857
+ * Plugin-managed: plugin.server.getStreamingChunks() async generators
858
+ *
859
+ * Both are raced together using a unified promise race loop.
860
+ */
679
861
  async function* streamAllAsyncChunks(ctx, plugins) {
680
862
  const hasCoreAsync = ctx._pendingAsync.length > 0;
681
863
  const pluginGenerators = [];
@@ -752,6 +934,9 @@ async function* streamAllAsyncChunks(ctx, plugins) {
752
934
  if (winner.index < totalCore) resolvedCore.add(winner.index);
753
935
  }
754
936
  }
937
+ /**
938
+ * Create an SSR instance with plugin support.
939
+ */
755
940
  function createSSR() {
756
941
  const plugins = [];
757
942
  function makeContext(options) {
@@ -893,20 +1078,80 @@ function createSSR() {
893
1078
  }
894
1079
  };
895
1080
  }
1081
+ //#endregion
1082
+ //#region src/server/render-api.ts
1083
+ /** Shared no-plugin instance — created once, reused for all standalone calls. */
896
1084
  var _defaultSSR = createSSR();
1085
+ /**
1086
+ * Render JSX element or App to a ReadableStream.
1087
+ *
1088
+ * Internally delegates to `createSSR().renderStream()`.
1089
+ *
1090
+ * @example
1091
+ * ```tsx
1092
+ * // Simple usage with JSX
1093
+ * renderToStream(<App />)
1094
+ *
1095
+ * // With App instance for DI/plugins
1096
+ * const app = defineApp(<App />).use(router);
1097
+ * renderToStream(app)
1098
+ * ```
1099
+ */
897
1100
  function renderToStream(input, context) {
898
1101
  return _defaultSSR.renderStream(input, context);
899
1102
  }
1103
+ /**
1104
+ * Render JSX element or App to a Node.js Readable stream.
1105
+ *
1106
+ * Faster than `renderToStream()` on Node.js because it bypasses WebStream
1107
+ * overhead entirely. Recommended for Express, Fastify, H3, and other
1108
+ * Node.js HTTP frameworks.
1109
+ *
1110
+ * @example
1111
+ * ```tsx
1112
+ * import { renderToNodeStream } from '@sigx/server-renderer/server';
1113
+ *
1114
+ * const stream = renderToNodeStream(<App />);
1115
+ * stream.pipe(res);
1116
+ * ```
1117
+ */
900
1118
  function renderToNodeStream(input, context) {
901
1119
  return _defaultSSR.renderNodeStream(input, context);
902
1120
  }
1121
+ /**
1122
+ * Render with callbacks for fine-grained streaming control.
1123
+ *
1124
+ * Internally delegates to `createSSR().renderStreamWithCallbacks()`.
1125
+ *
1126
+ * @example
1127
+ * ```tsx
1128
+ * const app = defineApp(<App />).use(router);
1129
+ * await renderToStreamWithCallbacks(app, callbacks)
1130
+ * ```
1131
+ */
903
1132
  async function renderToStreamWithCallbacks(input, callbacks, context) {
904
1133
  return _defaultSSR.renderStreamWithCallbacks(input, callbacks, context);
905
1134
  }
1135
+ /**
1136
+ * Render JSX element or App to string.
1137
+ *
1138
+ * Internally delegates to `createSSR().render()`.
1139
+ *
1140
+ * @example
1141
+ * ```tsx
1142
+ * const html = await renderToString(<App />);
1143
+ *
1144
+ * const app = defineApp(<App />).use(router);
1145
+ * const html = await renderToString(app);
1146
+ * ```
1147
+ */
906
1148
  async function renderToString(input, context) {
907
1149
  return _defaultSSR.render(input, context);
908
1150
  }
1151
+ //#endregion
1152
+ //#region src/server/index.ts
909
1153
  initDirectivesForSSR();
1154
+ //#endregion
910
1155
  export { createSSR as a, renderHeadToString as c, generateReplacementScript as d, generateStreamingScript as f, initDirectivesForSSR as h, renderToString as i, useHead as l, createSSRContext as m, renderToStream as n, collectSSRHead as o, renderVNodeToString as p, renderToStreamWithCallbacks as r, enableSSRHead as s, renderToNodeStream as t, escapeJsonForScript as u };
911
1156
 
912
- //# sourceMappingURL=server-pSrHP504.js.map
1157
+ //# sourceMappingURL=server-CiZxVKV9.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-CiZxVKV9.js","names":[],"sources":["../src/builtin-ssr-directives.ts","../__vite-browser-external","../src/server/context.ts","../src/server/render-core.ts","../src/server/streaming.ts","../src/head.ts","../src/ssr.ts","../src/server/render-api.ts","../src/server/index.ts"],"sourcesContent":["/**\r\n * Built-in directive SSR support — lazy patching.\r\n *\r\n * This module patches `getSSRProps` onto built-in directives (like `show`)\r\n * at runtime, keeping `@sigx/runtime-dom` free of SSR knowledge.\r\n *\r\n * Mirrors Vue 3's `initVShowForSSR()` / `initDirectivesForSSR()` pattern.\r\n *\r\n * @internal\r\n */\r\nimport { show } from '@sigx/runtime-dom';\r\n\r\nlet _initialized = false;\r\n\r\n/**\r\n * Patch `getSSRProps` onto the `show` directive for SSR support.\r\n *\r\n * Called lazily from `initDirectivesForSSR()` — not at import time,\r\n * so tree-shaking can eliminate this in client-only builds.\r\n */\r\nfunction initShowForSSR(): void {\r\n (show as any).getSSRProps = ({ value }: { value: boolean }) => {\r\n if (!value) {\r\n return { style: { display: 'none' } };\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Initialize SSR support for all built-in directives.\r\n *\r\n * Must be called before any SSR rendering occurs.\r\n * Safe to call multiple times — only patches once.\r\n */\r\nexport function initDirectivesForSSR(): void {\r\n if (_initialized) return;\r\n _initialized = true;\r\n initShowForSSR();\r\n}\r\n","module.exports = {}","/**\r\n * SSR Context — tracks component boundaries and rendering state.\r\n *\r\n * This is the core SSR context, free of any strategy-specific logic (islands, etc.).\r\n * Plugins extend it via the generic `_pluginData` map.\r\n */\r\n\r\nimport type { SSRPlugin } from '../plugin';\r\n\r\n/**\r\n * Core-managed pending async component.\r\n * Created by render-core when streaming mode is active and no plugin overrides.\r\n */\r\nexport interface CorePendingAsync {\r\n /** Component ID */\r\n id: number;\r\n /** Resolves to rendered HTML when ssr.load() completes */\r\n promise: Promise<string>;\r\n}\r\n\r\nexport interface SSRContextOptions {\r\n /**\r\n * Enable streaming mode (default: true)\r\n */\r\n streaming?: boolean;\r\n\r\n /**\r\n * Called when a component's setup() throws during SSR.\r\n *\r\n * Return a fallback HTML string to render in place of the failed component,\r\n * or `null` to use the default error placeholder.\r\n *\r\n * @param error - The error thrown during rendering\r\n * @param componentName - The component's `__name` (or 'Anonymous')\r\n * @param componentId - The numeric component ID assigned by the SSR context\r\n */\r\n onComponentError?: (error: Error, componentName: string, componentId: number) => string | null;\r\n}\r\n\r\nexport interface RenderOptions {\r\n /**\r\n * Custom SSR context (created automatically if not provided)\r\n */\r\n context?: SSRContext;\r\n}\r\n\r\nexport interface SSRContext {\r\n /**\r\n * Unique ID counter for component markers\r\n */\r\n _componentId: number;\r\n\r\n /**\r\n * Stack of component IDs for nested tracking\r\n */\r\n _componentStack: number[];\r\n\r\n /**\r\n * Collected head elements (scripts, styles, etc.)\r\n */\r\n _head: string[];\r\n\r\n /**\r\n * Error callback for component rendering failures\r\n */\r\n _onComponentError?: (error: Error, componentName: string, componentId: number) => string | null;\r\n\r\n /**\r\n * Registered SSR plugins\r\n */\r\n _plugins?: SSRPlugin[];\r\n\r\n /**\r\n * Plugin-specific data storage, keyed by plugin name.\r\n * Plugins store their own state here via `getPluginData` / `setPluginData`.\r\n */\r\n _pluginData: Map<string, any>;\r\n\r\n /**\r\n * Whether streaming mode is active.\r\n * When true, async components default to streaming (placeholder + deferred render)\r\n * instead of blocking. Set by renderStream / renderStreamWithCallbacks.\r\n */\r\n _streaming: boolean;\r\n\r\n /**\r\n * Core-managed pending async components.\r\n * Populated by render-core when async components are streamed without a plugin override.\r\n */\r\n _pendingAsync: CorePendingAsync[];\r\n\r\n /**\r\n * Generate next component ID\r\n */\r\n nextId(): number;\r\n\r\n /**\r\n * Push a component onto the stack\r\n */\r\n pushComponent(id: number): void;\r\n\r\n /**\r\n * Pop the current component from stack\r\n */\r\n popComponent(): number | undefined;\r\n\r\n /**\r\n * Add a head element\r\n */\r\n addHead(html: string): void;\r\n\r\n /**\r\n * Get collected head HTML\r\n */\r\n getHead(): string;\r\n\r\n /**\r\n * Get plugin-specific data by plugin name.\r\n */\r\n getPluginData<T>(pluginName: string): T | undefined;\r\n\r\n /**\r\n * Set plugin-specific data by plugin name.\r\n */\r\n setPluginData<T>(pluginName: string, data: T): void;\r\n}\r\n\r\n/**\r\n * Create a new SSR context for rendering\r\n */\r\nexport function createSSRContext(options: SSRContextOptions = {}): SSRContext {\r\n let componentId = 0;\r\n const componentStack: number[] = [];\r\n const head: string[] = [];\r\n const pluginData = new Map<string, any>();\r\n\r\n return {\r\n _componentId: componentId,\r\n _componentStack: componentStack,\r\n _head: head,\r\n _pluginData: pluginData,\r\n _onComponentError: options.onComponentError,\r\n _streaming: false,\r\n _pendingAsync: [],\r\n\r\n nextId() {\r\n return ++componentId;\r\n },\r\n\r\n pushComponent(id: number) {\r\n componentStack.push(id);\r\n },\r\n\r\n popComponent() {\r\n return componentStack.pop();\r\n },\r\n\r\n addHead(html: string) {\r\n head.push(html);\r\n },\r\n\r\n getHead() {\r\n return head.join('\\n');\r\n },\r\n\r\n getPluginData<T>(pluginName: string): T | undefined {\r\n return pluginData.get(pluginName);\r\n },\r\n\r\n setPluginData<T>(pluginName: string, data: T): void {\r\n pluginData.set(pluginName, data);\r\n }\r\n };\r\n}\r\n","/**\r\n * Core rendering logic for SSR\r\n *\r\n * The async generator `renderToChunks` walks a VNode tree and yields HTML strings.\r\n * Handles text, fragments, host elements, and delegates components to the\r\n * component renderer.\r\n *\r\n * This module is strategy-agnostic. Island-specific logic (signal tracking,\r\n * hydration directives, async streaming) lives in @sigx/ssr-islands and is\r\n * injected through the SSRPlugin hooks.\r\n */\r\n\r\nimport {\r\n VNode,\r\n Fragment,\r\n signal,\r\n Text,\r\n Comment,\r\n isComponent,\r\n isDirective\r\n} from 'sigx';\r\nimport type { JSXElement, ComponentSetupContext, SlotsObject, DirectiveDefinition, AppContext } from 'sigx';\r\nimport {\r\n setCurrentInstance,\r\n createPropsAccessor,\r\n provideAppContext,\r\n resolveBuiltInDirective,\r\n} from 'sigx/internals';\r\nimport type { SSRContext } from './context';\r\n\r\n// ============= HTML Utilities =============\r\n\r\nconst ESCAPE: Record<string, string> = {\r\n '&': '&amp;',\r\n '<': '&lt;',\r\n '>': '&gt;',\r\n '\"': '&quot;',\r\n \"'\": '&#39;'\r\n};\r\n\r\nexport function escapeHtml(s: string): string {\r\n return s.replace(/[&<>\"']/g, c => ESCAPE[c]);\r\n}\r\n\r\n/** Cache for camelCase → kebab-case conversions (same properties repeat across elements) */\r\nconst kebabCache: Record<string, string> = {};\r\n\r\n/** Void elements that cannot have children — hoisted to module scope as a Set for O(1) lookup */\r\nconst VOID_ELEMENTS = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);\r\n\r\nexport function camelToKebab(str: string): string {\r\n // CSS custom properties (--foo) are already kebab-case\r\n if (str.startsWith('--')) return str;\r\n return kebabCache[str] ||= str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\r\n}\r\n\r\n// ============= Style Parsing =============\r\n\r\n/**\r\n * Parse a CSS string into a style object.\r\n *\r\n * Handles edge cases: parens in values (e.g., `linear-gradient(...)`),\r\n * CSS comments, and colons in values.\r\n *\r\n * Adapted from Vue 3's `parseStringStyle` — battle-tested, split-based,\r\n * fast in V8.\r\n */\r\nconst listDelimiterRE = /;(?![^(]*\\))/g;\r\nconst propertyDelimiterRE = /:([^]+)/;\r\nconst styleCommentRE = /\\/\\*[^]*?\\*\\//g;\r\n\r\nexport function parseStringStyle(cssText: string): Record<string, string> {\r\n const ret: Record<string, string> = {};\r\n cssText\r\n .replace(styleCommentRE, '')\r\n .split(listDelimiterRE)\r\n .forEach(item => {\r\n if (item) {\r\n const tmp = item.split(propertyDelimiterRE);\r\n if (tmp.length > 1) {\r\n ret[tmp[0].trim()] = tmp[1].trim();\r\n }\r\n }\r\n });\r\n return ret;\r\n}\r\n\r\n/**\r\n * Serialize a style object to a CSS string.\r\n *\r\n * Uses for...in + string concat (avoids Object.entries/map/join allocations)\r\n * and cached kebab-case conversion.\r\n */\r\nexport function stringifyStyle(style: Record<string, any>): string {\r\n let ret = '';\r\n for (const key in style) {\r\n const value = style[key];\r\n if (value != null && value !== '') {\r\n ret += `${camelToKebab(key)}:${value};`;\r\n }\r\n }\r\n return ret;\r\n}\r\n\r\n/**\r\n * Check if element will render as text content\r\n */\r\nfunction isTextContent(element: JSXElement): boolean {\r\n if (element == null || element === false || element === true) return false;\r\n if (typeof element === 'string' || typeof element === 'number') return true;\r\n const vnode = element as VNode;\r\n return vnode.type === Text;\r\n}\r\n\r\n/** Check if all children are leaf types (text, number, null, bool, Text vnode) */\r\nfunction allChildrenAreLeaves(children: any[]): boolean {\r\n for (const child of children) {\r\n if (child == null || child === false || child === true) continue;\r\n if (typeof child === 'string' || typeof child === 'number') continue;\r\n const vnode = child as VNode;\r\n if (vnode.type === Text) continue;\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Merge style values for SSR (element style + directive SSR style).\r\n * Either value can be an object, string, or undefined.\r\n * String styles are parsed into objects before merging.\r\n */\r\nfunction mergeSSRStyles(elementStyle: any, directiveStyle: any): Record<string, any> {\r\n if (!elementStyle) return directiveStyle;\r\n if (!directiveStyle) return elementStyle;\r\n // Normalize both to objects — parse CSS strings if needed\r\n const a = typeof elementStyle === 'string' ? parseStringStyle(elementStyle)\r\n : (typeof elementStyle === 'object' ? elementStyle : {});\r\n const b = typeof directiveStyle === 'string' ? parseStringStyle(directiveStyle)\r\n : (typeof directiveStyle === 'object' ? directiveStyle : {});\r\n return { ...a, ...b };\r\n}\r\n\r\n/**\r\n * Render element to string chunks (generator for streaming)\r\n * @param element - The JSX element to render\r\n * @param ctx - The SSR context for tracking state\r\n * @param parentCtx - The parent component context for provide/inject\r\n * @param appContext - The app context for app-level provides (from defineApp)\r\n */\r\nexport async function* renderToChunks(\r\n element: JSXElement,\r\n ctx: SSRContext,\r\n parentCtx: ComponentSetupContext | null = null,\r\n appContext: AppContext | null = null\r\n): AsyncGenerator<string> {\r\n if (element == null || element === false || element === true) {\r\n return;\r\n }\r\n\r\n // Explicit Comment VNode (normalizeChildren creates these for falsy array items)\r\n if ((element as VNode).type === Comment) {\r\n yield '<!---->';\r\n return;\r\n }\r\n\r\n if (typeof element === 'string' || typeof element === 'number') {\r\n yield escapeHtml(String(element));\r\n return;\r\n }\r\n\r\n const vnode = element as VNode;\r\n\r\n if (vnode.type === Text) {\r\n yield escapeHtml(String(vnode.text));\r\n return;\r\n }\r\n\r\n if (vnode.type === Fragment) {\r\n for (const child of vnode.children) {\r\n yield* renderToChunks(child, ctx, parentCtx, appContext);\r\n }\r\n return;\r\n }\r\n\r\n // Handle Components\r\n if (isComponent(vnode.type)) {\r\n const setup = vnode.type.__setup;\r\n const componentName = vnode.type.__name || 'Anonymous';\r\n const allProps = vnode.props || {};\r\n\r\n // Destructure props (filter out framework-internal keys)\r\n const { children, slots: slotsFromProps, $models: modelsData, ...propsData } = allProps;\r\n\r\n const id = ctx.nextId();\r\n ctx.pushComponent(id);\r\n\r\n // Create slots from children\r\n const slots: SlotsObject<any> = {\r\n default: () => children ? (Array.isArray(children) ? children : [children]) : [],\r\n ...slotsFromProps\r\n };\r\n\r\n // Track SSR loads for this component\r\n const ssrLoads: Promise<void>[] = [];\r\n\r\n // Create SSR helper for async data loading\r\n const ssrHelper = {\r\n load(fn: () => Promise<void>): void {\r\n ssrLoads.push(fn());\r\n },\r\n isServer: true,\r\n isHydrating: false\r\n };\r\n\r\n let componentCtx: ComponentSetupContext = {\r\n el: null as any,\r\n signal: signal,\r\n props: createPropsAccessor(propsData),\r\n slots: slots,\r\n emit: () => { },\r\n parent: parentCtx,\r\n onMounted: () => { },\r\n onUnmounted: () => { },\r\n onCreated: () => { },\r\n onUpdated: () => { },\r\n expose: () => { },\r\n renderFn: null,\r\n update: () => { },\r\n ssr: ssrHelper,\r\n _ssrLoads: ssrLoads\r\n };\r\n\r\n // Plugin hook: transformComponentContext\r\n // Allows plugins (e.g., islands) to swap signal fn, filter props, set up tracking, etc.\r\n if (ctx._plugins) {\r\n for (const plugin of ctx._plugins) {\r\n const transformed = plugin.server?.transformComponentContext?.(ctx, vnode, componentCtx);\r\n if (transformed) {\r\n componentCtx = transformed;\r\n }\r\n }\r\n }\r\n\r\n // For ROOT component only (no parent), provide the AppContext\r\n if (!parentCtx && appContext) {\r\n provideAppContext(componentCtx, appContext);\r\n }\r\n\r\n const prev = setCurrentInstance(componentCtx);\r\n try {\r\n // Run setup synchronously — it registers ssr.load() callbacks\r\n let renderFn = setup(componentCtx);\r\n\r\n // Support legacy async setup — await if it returns a promise\r\n if (renderFn && typeof (renderFn as any).then === 'function') {\r\n renderFn = await (renderFn as Promise<any>);\r\n }\r\n\r\n // Check if we have pending ssr.load() calls\r\n if (ssrLoads.length > 0) {\r\n // Plugin hook: handleAsyncSetup\r\n // Plugins can override the async mode.\r\n // Default: 'stream' in streaming mode, 'block' in string mode.\r\n let asyncMode: 'block' | 'stream' | 'skip' = ctx._streaming ? 'stream' : 'block';\r\n let asyncPlaceholder: string | undefined;\r\n let pluginHandled = false;\r\n\r\n if (ctx._plugins) {\r\n for (const plugin of ctx._plugins) {\r\n const result = plugin.server?.handleAsyncSetup?.(id, ssrLoads, renderFn as () => any, ctx);\r\n if (result) {\r\n asyncMode = result.mode;\r\n asyncPlaceholder = result.placeholder;\r\n pluginHandled = true;\r\n break; // First plugin to handle wins\r\n }\r\n }\r\n }\r\n\r\n if (asyncMode === 'stream') {\r\n // Use default placeholder if none provided by plugin\r\n const placeholder = asyncPlaceholder || `<div data-async-placeholder=\"${id}\" style=\"display:contents;\">`;\r\n\r\n // Render placeholder immediately\r\n yield placeholder;\r\n\r\n // Render with initial state (before data loads)\r\n if (renderFn) {\r\n const result = (renderFn as () => any)();\r\n if (result) {\r\n if (Array.isArray(result)) {\r\n for (const item of result) {\r\n yield* renderToChunks(item, ctx, componentCtx, appContext);\r\n }\r\n } else {\r\n yield* renderToChunks(result, ctx, componentCtx, appContext);\r\n }\r\n }\r\n }\r\n\r\n yield `</div>`;\r\n\r\n // If no plugin handled this, core manages the deferred render\r\n if (!pluginHandled) {\r\n const capturedRenderFn = renderFn;\r\n const capturedCtx = ctx;\r\n const capturedAppContext = appContext;\r\n\r\n const deferredRender = (async () => {\r\n await Promise.all(ssrLoads);\r\n\r\n let html = '';\r\n if (capturedRenderFn) {\r\n const result = (capturedRenderFn as () => any)();\r\n if (result) {\r\n html = await renderVNodeToString(result, capturedCtx, capturedAppContext);\r\n }\r\n }\r\n\r\n return html;\r\n })();\r\n\r\n ctx._pendingAsync.push({ id, promise: deferredRender });\r\n }\r\n } else if (asyncMode === 'skip') {\r\n // Plugin says skip — don't render content\r\n } else {\r\n // Default: block — wait for all async loads\r\n await Promise.all(ssrLoads);\r\n\r\n if (renderFn) {\r\n const result = (renderFn as () => any)();\r\n if (result) {\r\n if (Array.isArray(result)) {\r\n for (const item of result) {\r\n yield* renderToChunks(item, ctx, componentCtx, appContext);\r\n }\r\n } else {\r\n yield* renderToChunks(result, ctx, componentCtx, appContext);\r\n }\r\n }\r\n }\r\n }\r\n } else {\r\n // No async loads — render synchronously\r\n if (renderFn) {\r\n const result = (renderFn as () => any)();\r\n if (result) {\r\n if (Array.isArray(result)) {\r\n for (const item of result) {\r\n yield* renderToChunks(item, ctx, componentCtx, appContext);\r\n }\r\n } else {\r\n yield* renderToChunks(result, ctx, componentCtx, appContext);\r\n }\r\n }\r\n }\r\n }\r\n } catch (e) {\r\n const error = e instanceof Error ? e : new Error(String(e));\r\n let fallbackHtml: string | null = null;\r\n\r\n if (ctx._onComponentError) {\r\n fallbackHtml = ctx._onComponentError(error, componentName, id);\r\n }\r\n\r\n if (fallbackHtml === null || fallbackHtml === undefined) {\r\n fallbackHtml = `<!--ssr-error:${id}-->`;\r\n }\r\n\r\n if (fallbackHtml) {\r\n yield fallbackHtml;\r\n }\r\n\r\n if (process.env.NODE_ENV !== 'production') {\r\n console.error(`Error rendering component ${componentName}:`, e);\r\n }\r\n } finally {\r\n setCurrentInstance(prev || null);\r\n }\r\n\r\n // Collect rendered HTML for plugin post-processing\r\n // Note: For streaming, afterRenderComponent receives empty string\r\n // since chunks were already yielded. Plugins that need to wrap\r\n // content should use transformComponentContext to set up wrapping.\r\n\r\n // Plugin hook: afterRenderComponent\r\n if (ctx._plugins) {\r\n for (const plugin of ctx._plugins) {\r\n const transformed = plugin.server?.afterRenderComponent?.(id, vnode, '', ctx);\r\n if (transformed) {\r\n yield transformed;\r\n }\r\n }\r\n }\r\n\r\n // Emit trailing component marker\r\n yield `<!--$c:${id}-->`;\r\n ctx.popComponent();\r\n return;\r\n }\r\n\r\n // Handle host elements\r\n if (typeof vnode.type === 'string') {\r\n const tagName = vnode.type;\r\n let props = '';\r\n\r\n // Collect SSR props from use:* directive props (getSSRProps hook)\r\n let directiveSSRProps: Record<string, any> | null = null;\r\n if (vnode.props) {\r\n for (const key in vnode.props) {\r\n if (key.startsWith('use:')) {\r\n const propValue = vnode.props[key];\r\n let def: DirectiveDefinition | undefined;\r\n let value: any;\r\n\r\n if (isDirective(propValue)) {\r\n def = propValue;\r\n value = undefined;\r\n } else if (\r\n Array.isArray(propValue) &&\r\n propValue.length >= 1 &&\r\n isDirective(propValue[0])\r\n ) {\r\n def = propValue[0];\r\n value = propValue[1];\r\n } else {\r\n // Try to resolve by name:\r\n // 1. Built-in directives (always available, e.g., 'show')\r\n // 2. App-registered custom directives (via app.directive())\r\n const builtIn = resolveBuiltInDirective(key.slice(4));\r\n if (builtIn) {\r\n def = builtIn;\r\n value = propValue;\r\n } else {\r\n const custom = appContext?.directives.get(key.slice(4));\r\n if (custom) {\r\n def = custom;\r\n value = propValue;\r\n }\r\n }\r\n }\r\n\r\n if (def?.getSSRProps) {\r\n const ssrProps = def.getSSRProps({ value });\r\n if (ssrProps) {\r\n if (!directiveSSRProps) directiveSSRProps = {};\r\n for (const k in ssrProps) {\r\n if (k === 'style' && directiveSSRProps.style) {\r\n directiveSSRProps.style = { ...directiveSSRProps.style, ...ssrProps.style };\r\n } else if (k === 'class' && directiveSSRProps.class) {\r\n directiveSSRProps.class = directiveSSRProps.class + ' ' + ssrProps.class;\r\n } else {\r\n directiveSSRProps[k] = ssrProps[k];\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Merge directive SSR props with element props\r\n const allProps = directiveSSRProps\r\n ? { ...vnode.props, ...directiveSSRProps, style: mergeSSRStyles(vnode.props?.style, directiveSSRProps?.style) }\r\n : vnode.props;\r\n\r\n // Serialize props\r\n for (const key in allProps) {\r\n const value = allProps[key];\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key.startsWith('client:')) continue; // Skip client directives\r\n if (key.startsWith('use:')) continue; // Skip element directives\r\n\r\n if (key === 'style') {\r\n const styleString = typeof value === 'object'\r\n ? stringifyStyle(value)\r\n : String(value);\r\n props += ` style=\"${escapeHtml(styleString)}\"`;\r\n } else if (key === 'className') {\r\n props += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key.startsWith('on')) {\r\n // Skip event listeners on server\r\n } else if (value === true) {\r\n props += ` ${key}`;\r\n } else if (value !== false && value != null) {\r\n props += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n // Void elements\r\n if (VOID_ELEMENTS.has(tagName)) {\r\n yield `<${tagName}${props}>`;\r\n return;\r\n }\r\n\r\n // Fast path: if all children are leaf types (text/number/null/bool),\r\n // render entire element as a single string to avoid per-child yields.\r\n if (vnode.children.length > 0 && allChildrenAreLeaves(vnode.children)) {\r\n let html = `<${tagName}${props}>`;\r\n let prevWasText = false;\r\n for (const child of vnode.children) {\r\n const isText = isTextContent(child);\r\n if (isText && prevWasText) html += '<!--t-->';\r\n if (child != null && (child as any) !== false && (child as any) !== true) {\r\n const cv = child as VNode;\r\n html += escapeHtml(String(cv.type === Text ? cv.text : child));\r\n }\r\n prevWasText = isText;\r\n }\r\n html += `</${tagName}>`;\r\n yield html;\r\n return;\r\n }\r\n\r\n yield `<${tagName}${props}>`;\r\n\r\n // Render children with text boundary markers\r\n // Adjacent text nodes get merged by the browser, so we insert <!--t--> markers\r\n let prevWasText = false;\r\n for (const child of vnode.children) {\r\n const isText = isTextContent(child);\r\n if (isText && prevWasText) {\r\n // Insert marker between adjacent text nodes\r\n yield '<!--t-->';\r\n }\r\n yield* renderToChunks(child, ctx, parentCtx, appContext);\r\n prevWasText = isText;\r\n }\r\n\r\n yield `</${tagName}>`;\r\n }\r\n}\r\n\r\n/**\r\n * Helper to render a VNode to string (for deferred async content)\r\n */\r\nexport async function renderVNodeToString(element: JSXElement, ctx: SSRContext, appContext: AppContext | null = null): Promise<string> {\r\n let result = '';\r\n for await (const chunk of renderToChunks(element, ctx, null, appContext)) {\r\n result += chunk;\r\n }\r\n return result;\r\n}\r\n\r\n// ============= Synchronous String Renderer =============\r\n\r\n/**\r\n * Synchronous render-to-string that avoids async generator overhead.\r\n * Returns null if any async operation is encountered (caller should fall back\r\n * to the async generator path).\r\n *\r\n * For purely synchronous component trees this eliminates thousands of\r\n * microtask/Promise allocations from the AsyncGenerator protocol.\r\n */\r\nexport function renderToStringSync(\r\n element: JSXElement,\r\n ctx: SSRContext,\r\n parentCtx: ComponentSetupContext | null,\r\n appContext: AppContext | null,\r\n buf: string[]\r\n): boolean {\r\n if (element == null || element === false || element === true) {\r\n return true;\r\n }\r\n\r\n // Explicit Comment VNode (normalizeChildren creates these for falsy array items)\r\n if ((element as VNode).type === Comment) {\r\n buf.push('<!---->');\r\n return true;\r\n }\r\n\r\n if (typeof element === 'string' || typeof element === 'number') {\r\n buf.push(escapeHtml(String(element)));\r\n return true;\r\n }\r\n\r\n const vnode = element as VNode;\r\n\r\n if (vnode.type === Text) {\r\n buf.push(escapeHtml(String(vnode.text)));\r\n return true;\r\n }\r\n\r\n if (vnode.type === Fragment) {\r\n for (const child of vnode.children) {\r\n if (!renderToStringSync(child, ctx, parentCtx, appContext, buf)) return false;\r\n }\r\n return true;\r\n }\r\n\r\n // Handle Components\r\n if (isComponent(vnode.type)) {\r\n const setup = vnode.type.__setup;\r\n const componentName = vnode.type.__name || 'Anonymous';\r\n const allProps = vnode.props || {};\r\n\r\n const { children, slots: slotsFromProps, $models: modelsData, ...propsData } = allProps;\r\n\r\n const id = ctx.nextId();\r\n ctx.pushComponent(id);\r\n\r\n const slots: SlotsObject<any> = {\r\n default: () => children ? (Array.isArray(children) ? children : [children]) : [],\r\n ...slotsFromProps\r\n };\r\n\r\n const ssrLoads: Promise<void>[] = [];\r\n\r\n const ssrHelper = {\r\n load(fn: () => Promise<void>): void {\r\n ssrLoads.push(fn());\r\n },\r\n isServer: true,\r\n isHydrating: false\r\n };\r\n\r\n let componentCtx: ComponentSetupContext = {\r\n el: null as any,\r\n signal: signal,\r\n props: createPropsAccessor(propsData),\r\n slots: slots,\r\n emit: () => { },\r\n parent: parentCtx,\r\n onMounted: () => { },\r\n onUnmounted: () => { },\r\n onCreated: () => { },\r\n onUpdated: () => { },\r\n expose: () => { },\r\n renderFn: null,\r\n update: () => { },\r\n ssr: ssrHelper,\r\n _ssrLoads: ssrLoads\r\n };\r\n\r\n if (ctx._plugins) {\r\n for (const plugin of ctx._plugins) {\r\n const transformed = plugin.server?.transformComponentContext?.(ctx, vnode, componentCtx);\r\n if (transformed) {\r\n componentCtx = transformed;\r\n }\r\n }\r\n }\r\n\r\n if (!parentCtx && appContext) {\r\n provideAppContext(componentCtx, appContext);\r\n }\r\n\r\n const prev = setCurrentInstance(componentCtx);\r\n try {\r\n let renderFn = setup(componentCtx);\r\n\r\n // Bail out if setup is async\r\n if (renderFn && typeof (renderFn as any).then === 'function') {\r\n for (const p of ssrLoads) p.catch(() => {});\r\n setCurrentInstance(prev || null);\r\n ctx.popComponent();\r\n return false;\r\n }\r\n\r\n // Bail out if there are ssr.load() calls\r\n if (ssrLoads.length > 0) {\r\n // Suppress unhandled rejections — the async path will re-run these\r\n for (const p of ssrLoads) p.catch(() => {});\r\n setCurrentInstance(prev || null);\r\n ctx.popComponent();\r\n return false;\r\n }\r\n\r\n if (renderFn) {\r\n const result = (renderFn as () => any)();\r\n if (result) {\r\n if (Array.isArray(result)) {\r\n for (const item of result) {\r\n if (!renderToStringSync(item, ctx, componentCtx, appContext, buf)) {\r\n setCurrentInstance(prev || null);\r\n ctx.popComponent();\r\n return false;\r\n }\r\n }\r\n } else {\r\n if (!renderToStringSync(result, ctx, componentCtx, appContext, buf)) {\r\n setCurrentInstance(prev || null);\r\n ctx.popComponent();\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n } catch (e) {\r\n const error = e instanceof Error ? e : new Error(String(e));\r\n let fallbackHtml: string | null = null;\r\n\r\n if (ctx._onComponentError) {\r\n fallbackHtml = ctx._onComponentError(error, componentName, id);\r\n }\r\n\r\n if (fallbackHtml === null || fallbackHtml === undefined) {\r\n fallbackHtml = `<!--ssr-error:${id}-->`;\r\n }\r\n\r\n if (fallbackHtml) {\r\n buf.push(fallbackHtml);\r\n }\r\n } finally {\r\n setCurrentInstance(prev || null);\r\n }\r\n\r\n if (ctx._plugins) {\r\n for (const plugin of ctx._plugins) {\r\n const transformed = plugin.server?.afterRenderComponent?.(id, vnode, '', ctx);\r\n if (transformed) {\r\n buf.push(transformed);\r\n }\r\n }\r\n }\r\n\r\n buf.push(`<!--$c:${id}-->`);\r\n ctx.popComponent();\r\n return true;\r\n }\r\n\r\n // Handle host elements\r\n if (typeof vnode.type === 'string') {\r\n const tagName = vnode.type;\r\n let props = '';\r\n\r\n let directiveSSRProps: Record<string, any> | null = null;\r\n if (vnode.props) {\r\n for (const key in vnode.props) {\r\n if (key.startsWith('use:')) {\r\n const propValue = vnode.props[key];\r\n let def: DirectiveDefinition | undefined;\r\n let value: any;\r\n\r\n if (isDirective(propValue)) {\r\n def = propValue;\r\n value = undefined;\r\n } else if (\r\n Array.isArray(propValue) &&\r\n propValue.length >= 1 &&\r\n isDirective(propValue[0])\r\n ) {\r\n def = propValue[0];\r\n value = propValue[1];\r\n } else {\r\n const builtIn = resolveBuiltInDirective(key.slice(4));\r\n if (builtIn) {\r\n def = builtIn;\r\n value = propValue;\r\n } else {\r\n const custom = appContext?.directives.get(key.slice(4));\r\n if (custom) {\r\n def = custom;\r\n value = propValue;\r\n }\r\n }\r\n }\r\n\r\n if (def?.getSSRProps) {\r\n const ssrProps = def.getSSRProps({ value });\r\n if (ssrProps) {\r\n if (!directiveSSRProps) directiveSSRProps = {};\r\n for (const k in ssrProps) {\r\n if (k === 'style' && directiveSSRProps.style) {\r\n directiveSSRProps.style = { ...directiveSSRProps.style, ...ssrProps.style };\r\n } else if (k === 'class' && directiveSSRProps.class) {\r\n directiveSSRProps.class = directiveSSRProps.class + ' ' + ssrProps.class;\r\n } else {\r\n directiveSSRProps[k] = ssrProps[k];\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n const allProps = directiveSSRProps\r\n ? { ...vnode.props, ...directiveSSRProps, style: mergeSSRStyles(vnode.props?.style, directiveSSRProps?.style) }\r\n : vnode.props;\r\n\r\n for (const key in allProps) {\r\n const value = allProps[key];\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key.startsWith('client:')) continue;\r\n if (key.startsWith('use:')) continue;\r\n\r\n if (key === 'style') {\r\n const styleString = typeof value === 'object'\r\n ? stringifyStyle(value)\r\n : String(value);\r\n props += ` style=\"${escapeHtml(styleString)}\"`;\r\n } else if (key === 'className') {\r\n props += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key.startsWith('on')) {\r\n // Skip event listeners on server\r\n } else if (value === true) {\r\n props += ` ${key}`;\r\n } else if (value !== false && value != null) {\r\n props += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n if (VOID_ELEMENTS.has(tagName)) {\r\n buf.push(`<${tagName}${props}>`);\r\n return true;\r\n }\r\n\r\n buf.push(`<${tagName}${props}>`);\r\n\r\n let prevWasText = false;\r\n for (const child of vnode.children) {\r\n const isText = isTextContent(child);\r\n if (isText && prevWasText) {\r\n buf.push('<!--t-->');\r\n }\r\n if (!renderToStringSync(child, ctx, parentCtx, appContext, buf)) return false;\r\n prevWasText = isText;\r\n }\r\n\r\n buf.push(`</${tagName}>`);\r\n return true;\r\n }\r\n\r\n return true;\r\n}\r\n","/**\r\n * Core streaming utilities for async SSR\r\n *\r\n * Provides the client-side `$SIGX_REPLACE` function and replacement script\r\n * generation used by core async streaming. These are strategy-agnostic —\r\n * any async component with `ssr.load()` gets streamed without needing a plugin.\r\n *\r\n * Plugins (e.g., islands) can augment replacements via `onAsyncComponentResolved`.\r\n */\r\n\r\n/**\r\n * Escape a JSON string for safe embedding inside <script> tags.\r\n * Prevents XSS by replacing characters that could break out of the script context.\r\n */\r\nexport function escapeJsonForScript(json: string): string {\r\n return json\r\n .replace(/</g, '\\\\u003c')\r\n .replace(/>/g, '\\\\u003e')\r\n .replace(/\\u2028/g, '\\\\u2028')\r\n .replace(/\\u2029/g, '\\\\u2029');\r\n}\r\n\r\n/**\r\n * Generate the streaming bootstrap script (injected once before any replacements).\r\n * Defines `window.$SIGX_REPLACE` which swaps async placeholders with rendered HTML.\r\n */\r\nexport function generateStreamingScript(): string {\r\n return `\r\n<script>\r\nwindow.$SIGX_REPLACE = function(id, html) {\r\n var placeholder = document.querySelector('[data-async-placeholder=\"' + id + '\"]');\r\n if (placeholder) {\r\n var template = document.createElement('template');\r\n template.innerHTML = html;\r\n placeholder.innerHTML = '';\r\n while (template.content.firstChild) {\r\n placeholder.appendChild(template.content.firstChild);\r\n }\r\n placeholder.dispatchEvent(new CustomEvent('sigx:async-ready', { bubbles: true, detail: { id: id } }));\r\n }\r\n};\r\n</script>`;\r\n}\r\n\r\n/**\r\n * Generate a replacement script for a resolved async component.\r\n */\r\nexport function generateReplacementScript(id: number, html: string, extraScript?: string): string {\r\n const escapedHtml = escapeJsonForScript(JSON.stringify(html));\r\n let script = `<script>$SIGX_REPLACE(${id}, ${escapedHtml});`;\r\n if (extraScript) {\r\n script += extraScript;\r\n }\r\n script += `</script>`;\r\n return script;\r\n}\r\n","/**\r\n * Head management composable for SSR and client-side.\r\n *\r\n * Provides `useHead()` for managing `<head>` elements (title, meta, link, script)\r\n * from within components. Works during SSR (collects into SSRContext._head) and\r\n * on the client (updates DOM directly).\r\n *\r\n * @example\r\n * ```tsx\r\n * import { useHead } from '@sigx/server-renderer/head';\r\n *\r\n * function MyPage(ctx) {\r\n * useHead({\r\n * title: 'My Page',\r\n * meta: [\r\n * { name: 'description', content: 'A great page' },\r\n * { property: 'og:title', content: 'My Page' }\r\n * ],\r\n * link: [\r\n * { rel: 'canonical', href: 'https://example.com/my-page' }\r\n * ]\r\n * });\r\n *\r\n * return () => <div>Page content</div>;\r\n * }\r\n * ```\r\n */\r\n\r\nimport { getCurrentInstance } from 'sigx';\r\n\r\n// ============= Types =============\r\n\r\nexport interface HeadMeta {\r\n name?: string;\r\n property?: string;\r\n 'http-equiv'?: string;\r\n charset?: string;\r\n content?: string;\r\n [key: string]: string | undefined;\r\n}\r\n\r\nexport interface HeadLink {\r\n rel: string;\r\n href?: string;\r\n type?: string;\r\n crossorigin?: string;\r\n [key: string]: string | undefined;\r\n}\r\n\r\nexport interface HeadScript {\r\n src?: string;\r\n type?: string;\r\n async?: boolean;\r\n defer?: boolean;\r\n innerHTML?: string;\r\n [key: string]: string | boolean | undefined;\r\n}\r\n\r\nexport interface HeadConfig {\r\n /** Page title */\r\n title?: string;\r\n /** Title template — use %s as placeholder for the title */\r\n titleTemplate?: string;\r\n /** Meta tags */\r\n meta?: HeadMeta[];\r\n /** Link tags */\r\n link?: HeadLink[];\r\n /** Script tags */\r\n script?: HeadScript[];\r\n /** HTML language attribute */\r\n htmlAttrs?: { lang?: string; dir?: string; [key: string]: string | undefined };\r\n /** Body attributes */\r\n bodyAttrs?: { class?: string; [key: string]: string | undefined };\r\n}\r\n\r\n// ============= SSR Head Collection =============\r\n\r\n// Server-side: head configs are collected during rendering\r\nlet _ssrHeadConfigs: HeadConfig[] = [];\r\nlet _isSSR = false;\r\n\r\n/**\r\n * Enable SSR mode for head management.\r\n * Called by the SSR renderer before rendering starts.\r\n */\r\nexport function enableSSRHead(): void {\r\n _isSSR = true;\r\n _ssrHeadConfigs = [];\r\n}\r\n\r\n/**\r\n * Disable SSR mode and return collected configs.\r\n */\r\nexport function collectSSRHead(): HeadConfig[] {\r\n _isSSR = false;\r\n const configs = _ssrHeadConfigs;\r\n _ssrHeadConfigs = [];\r\n return configs;\r\n}\r\n\r\n/**\r\n * Render collected head configs to an HTML string.\r\n * Deduplicates meta tags by name/property and uses the last title.\r\n */\r\nexport function renderHeadToString(configs: HeadConfig[]): string {\r\n const parts: string[] = [];\r\n const seenMeta = new Map<string, string>();\r\n let finalTitle: string | undefined;\r\n let titleTemplate: string | undefined;\r\n\r\n // Process in order — later configs override earlier ones\r\n for (const config of configs) {\r\n if (config.titleTemplate) {\r\n titleTemplate = config.titleTemplate;\r\n }\r\n if (config.title) {\r\n finalTitle = config.title;\r\n }\r\n\r\n if (config.meta) {\r\n for (const meta of config.meta) {\r\n // Deduplicate by name or property\r\n const key = meta.name ? `name:${meta.name}` :\r\n meta.property ? `property:${meta.property}` :\r\n meta['http-equiv'] ? `http-equiv:${meta['http-equiv']}` :\r\n meta.charset ? 'charset' : null;\r\n\r\n const attrs = Object.entries(meta)\r\n .filter(([, v]) => v !== undefined)\r\n .map(([k, v]) => `${escapeAttr(k)}=\"${escapeAttr(String(v))}\"`)\r\n .join(' ');\r\n\r\n const tag = `<meta ${attrs}>`;\r\n\r\n if (key) {\r\n seenMeta.set(key, tag);\r\n } else {\r\n parts.push(tag);\r\n }\r\n }\r\n }\r\n\r\n if (config.link) {\r\n for (const link of config.link) {\r\n const attrs = Object.entries(link)\r\n .filter(([, v]) => v !== undefined)\r\n .map(([k, v]) => `${escapeAttr(k)}=\"${escapeAttr(String(v))}\"`)\r\n .join(' ');\r\n parts.push(`<link ${attrs}>`);\r\n }\r\n }\r\n\r\n if (config.script) {\r\n for (const script of config.script) {\r\n const { innerHTML, ...rest } = script;\r\n const attrs = Object.entries(rest)\r\n .filter(([, v]) => v !== undefined && v !== false)\r\n .map(([k, v]) => v === true ? escapeAttr(k) : `${escapeAttr(k)}=\"${escapeAttr(String(v))}\"`)\r\n .join(' ');\r\n if (innerHTML) {\r\n parts.push(`<script ${attrs}>${innerHTML}</script>`);\r\n } else {\r\n parts.push(`<script ${attrs}></script>`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n const result: string[] = [];\r\n\r\n // Title first\r\n if (finalTitle) {\r\n const title = titleTemplate\r\n ? titleTemplate.replace('%s', finalTitle)\r\n : finalTitle;\r\n result.push(`<title>${escapeHtml(title)}</title>`);\r\n }\r\n\r\n // Deduplicated meta tags\r\n for (const tag of seenMeta.values()) {\r\n result.push(tag);\r\n }\r\n\r\n // Other parts\r\n result.push(...parts);\r\n\r\n return result.join('\\n');\r\n}\r\n\r\n// ============= Client-side Head Management =============\r\n\r\n/** Track elements managed by useHead for cleanup */\r\nconst _managedElements = new WeakMap<object, HTMLElement[]>();\r\nlet _headToken = 0;\r\n\r\nfunction applyHeadClient(config: HeadConfig): (() => void) {\r\n const managed: HTMLElement[] = [];\r\n const token = ++_headToken;\r\n\r\n if (config.title) {\r\n const title = config.titleTemplate\r\n ? config.titleTemplate.replace('%s', config.title)\r\n : config.title;\r\n document.title = title;\r\n }\r\n\r\n if (config.meta) {\r\n for (const meta of config.meta) {\r\n // Remove existing matching meta\r\n const selector = meta.name ? `meta[name=\"${meta.name}\"]` :\r\n meta.property ? `meta[property=\"${meta.property}\"]` :\r\n meta['http-equiv'] ? `meta[http-equiv=\"${meta['http-equiv']}\"]` : null;\r\n\r\n if (selector) {\r\n const existing = document.querySelector(selector);\r\n if (existing) existing.remove();\r\n }\r\n\r\n const el = document.createElement('meta');\r\n for (const [k, v] of Object.entries(meta)) {\r\n if (v !== undefined) el.setAttribute(k, v);\r\n }\r\n el.setAttribute('data-sigx-head', String(token));\r\n document.head.appendChild(el);\r\n managed.push(el);\r\n }\r\n }\r\n\r\n if (config.link) {\r\n for (const link of config.link) {\r\n const el = document.createElement('link');\r\n for (const [k, v] of Object.entries(link)) {\r\n if (v !== undefined) el.setAttribute(k, v);\r\n }\r\n el.setAttribute('data-sigx-head', String(token));\r\n document.head.appendChild(el);\r\n managed.push(el);\r\n }\r\n }\r\n\r\n if (config.script) {\r\n for (const script of config.script) {\r\n const { innerHTML, ...rest } = script;\r\n const el = document.createElement('script');\r\n for (const [k, v] of Object.entries(rest)) {\r\n if (v === true) el.setAttribute(k, '');\r\n else if (v !== undefined && v !== false) el.setAttribute(k, String(v));\r\n }\r\n if (innerHTML) el.textContent = innerHTML;\r\n el.setAttribute('data-sigx-head', String(token));\r\n document.head.appendChild(el);\r\n managed.push(el);\r\n }\r\n }\r\n\r\n if (config.htmlAttrs) {\r\n for (const [k, v] of Object.entries(config.htmlAttrs)) {\r\n if (v !== undefined) document.documentElement.setAttribute(k, v);\r\n }\r\n }\r\n\r\n if (config.bodyAttrs) {\r\n for (const [k, v] of Object.entries(config.bodyAttrs)) {\r\n if (v !== undefined) document.body.setAttribute(k, v);\r\n }\r\n }\r\n\r\n // Return cleanup function\r\n return () => {\r\n for (const el of managed) {\r\n el.remove();\r\n }\r\n };\r\n}\r\n\r\n// ============= Public API =============\r\n\r\n/**\r\n * Manage `<head>` elements from within a component.\r\n *\r\n * During SSR, collects head configs for later rendering with `renderHeadToString()`.\r\n * On the client, updates the DOM directly. Cleans up on component unmount.\r\n *\r\n * @param config - Head configuration (title, meta, link, script, etc.)\r\n */\r\nexport function useHead(config: HeadConfig): void {\r\n if (_isSSR) {\r\n // Server-side: collect configs\r\n _ssrHeadConfigs.push(config);\r\n return;\r\n }\r\n\r\n // Client-side: apply to DOM and register cleanup\r\n const cleanup = applyHeadClient(config);\r\n\r\n // If we're inside a component setup, register cleanup on unmount\r\n const instance = getCurrentInstance();\r\n if (instance) {\r\n instance.onUnmounted(() => cleanup());\r\n }\r\n}\r\n\r\n// ============= Utilities =============\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;');\r\n}\r\n\r\nfunction escapeAttr(s: string): string {\r\n return s\r\n .replace(/&/g, '&amp;')\r\n .replace(/\"/g, '&quot;');\r\n}\r\n","/**\r\n * SSR Factory\r\n *\r\n * Creates an SSR instance with plugin support.\r\n * Plugins are registered via `.use()` and called at appropriate points\r\n * during server rendering and client hydration.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createSSR } from '@sigx/server-renderer';\r\n * import { islandsPlugin } from '@sigx/ssr-islands';\r\n *\r\n * const ssr = createSSR().use(islandsPlugin());\r\n * const html = await ssr.render(<App />);\r\n * ```\r\n */\r\n\r\nimport type { SSRPlugin } from './plugin';\r\nimport type { JSXElement } from 'sigx';\r\nimport type { App, AppContext } from 'sigx';\r\nimport { Readable } from 'node:stream';\r\nimport { SSRContext, createSSRContext, SSRContextOptions, CorePendingAsync } from './server/context';\r\nimport { renderToChunks, renderToStringSync } from './server/render-core';\r\nimport { generateStreamingScript, generateReplacementScript } from './server/streaming';\r\nimport { enableSSRHead, collectSSRHead, renderHeadToString } from './head';\r\nimport type { StreamCallbacks } from './server/types';\r\n\r\n/**\r\n * Check if the input is an App instance (created via defineApp)\r\n */\r\nfunction isApp(input: any): input is App<any> {\r\n return input && typeof input === 'object' && '_rootComponent' in input && '_context' in input;\r\n}\r\n\r\n/**\r\n * Extract the JSX element and optional AppContext from a render input.\r\n */\r\nfunction extractInput(input: JSXElement | App): { element: JSXElement; appContext: AppContext | null } {\r\n if (isApp(input)) {\r\n return { element: input._rootComponent, appContext: input._context };\r\n }\r\n return { element: input, appContext: null };\r\n}\r\n\r\n/**\r\n * Yield all async streaming chunks — core-managed and plugin-managed — interleaved\r\n * so the fastest component streams first regardless of who manages it.\r\n *\r\n * Core-managed: ctx._pendingAsync (from render-core when no plugin overrides)\r\n * Plugin-managed: plugin.server.getStreamingChunks() async generators\r\n *\r\n * Both are raced together using a unified promise race loop.\r\n */\r\nasync function* streamAllAsyncChunks(\r\n ctx: SSRContext,\r\n plugins: SSRPlugin[]\r\n): AsyncGenerator<string> {\r\n type TaggedResult = { index: number; script: string };\r\n\r\n const hasCoreAsync = ctx._pendingAsync.length > 0;\r\n\r\n // Collect plugin streaming generators\r\n const pluginGenerators: AsyncGenerator<string>[] = [];\r\n for (const plugin of plugins) {\r\n const chunks = plugin.server?.getStreamingChunks?.(ctx);\r\n if (chunks) pluginGenerators.push(chunks);\r\n }\r\n\r\n const hasPluginStreaming = pluginGenerators.length > 0;\r\n\r\n // Nothing to stream\r\n if (!hasCoreAsync && !hasPluginStreaming) return;\r\n\r\n // Emit the $SIGX_REPLACE bootstrap script (needed by core replacements)\r\n if (hasCoreAsync) {\r\n yield generateStreamingScript();\r\n }\r\n\r\n // Build tagged promises for core-managed async components\r\n const corePromises: Promise<TaggedResult>[] = ctx._pendingAsync.map(\r\n (pending, index) =>\r\n pending.promise.then(html => {\r\n // Let plugins augment the resolved HTML\r\n let finalHtml = html;\r\n let extraScript = '';\r\n for (const plugin of plugins) {\r\n const result = plugin.server?.onAsyncComponentResolved?.(pending.id, finalHtml, ctx);\r\n if (result) {\r\n if (result.html !== undefined) finalHtml = result.html;\r\n if (result.script) extraScript += result.script;\r\n }\r\n }\r\n return {\r\n index,\r\n script: generateReplacementScript(pending.id, finalHtml, extraScript || undefined)\r\n };\r\n }).catch(error => {\r\n if (process.env.NODE_ENV !== 'production') {\r\n console.error(`Error streaming async component ${pending.id}:`, error);\r\n }\r\n return {\r\n index,\r\n script: generateReplacementScript(\r\n pending.id,\r\n `<div style=\"color:red;\">Error loading component</div>`\r\n )\r\n };\r\n })\r\n );\r\n\r\n const totalCore = corePromises.length;\r\n\r\n // Set up pump pattern for plugin generators so they can be raced alongside core\r\n interface PumpState {\r\n generator: AsyncGenerator<string>;\r\n done: boolean;\r\n }\r\n const pumps: PumpState[] = pluginGenerators.map(g => ({ generator: g, done: false }));\r\n\r\n // Active pump promises, keyed by their slot index (totalCore + i)\r\n const activePumps = new Map<number, Promise<TaggedResult>>();\r\n\r\n function pumpNext(pumpIdx: number): Promise<TaggedResult> {\r\n const slotIndex = totalCore + pumpIdx;\r\n return pumps[pumpIdx].generator.next().then(({ value, done }) => {\r\n if (done) {\r\n pumps[pumpIdx].done = true;\r\n activePumps.delete(slotIndex);\r\n return { index: slotIndex, script: '' };\r\n }\r\n // Re-queue: set new promise for this slot\r\n const nextP = pumpNext(pumpIdx);\r\n activePumps.set(slotIndex, nextP);\r\n return { index: slotIndex, script: value || '' };\r\n });\r\n }\r\n\r\n // Start initial pumps\r\n for (let i = 0; i < pumps.length; i++) {\r\n const slotIndex = totalCore + i;\r\n const p = pumpNext(i);\r\n activePumps.set(slotIndex, p);\r\n }\r\n\r\n // Race loop: core promises + pump promises\r\n const resolvedCore = new Set<number>();\r\n\r\n function getRaceablePromises(): Promise<TaggedResult>[] {\r\n const promises: Promise<TaggedResult>[] = [];\r\n for (let i = 0; i < totalCore; i++) {\r\n if (!resolvedCore.has(i)) promises.push(corePromises[i]);\r\n }\r\n for (const [, p] of activePumps) {\r\n promises.push(p);\r\n }\r\n return promises;\r\n }\r\n\r\n while (true) {\r\n const raceable = getRaceablePromises();\r\n if (raceable.length === 0) break;\r\n\r\n const winner = await Promise.race(raceable);\r\n\r\n if (winner.script) {\r\n yield winner.script;\r\n }\r\n\r\n if (winner.index < totalCore) {\r\n resolvedCore.add(winner.index);\r\n }\r\n // Pump promises auto-re-queue in pumpNext(), so no action needed here\r\n }\r\n}\r\n\r\nexport interface SSRInstance {\r\n /** Register a plugin */\r\n use(plugin: SSRPlugin): SSRInstance;\r\n\r\n /** Render to a complete HTML string */\r\n render(input: JSXElement | App, options?: SSRContextOptions | SSRContext): Promise<string>;\r\n\r\n /** Render to a ReadableStream with streaming support */\r\n renderStream(input: JSXElement | App, options?: SSRContextOptions | SSRContext): ReadableStream<string>;\r\n\r\n /** Render to a Node.js Readable stream (avoids WebStream overhead on Node.js) */\r\n renderNodeStream(input: JSXElement | App, options?: SSRContextOptions | SSRContext): import('node:stream').Readable;\r\n\r\n /** Render with callbacks for fine-grained streaming control */\r\n renderStreamWithCallbacks(\r\n input: JSXElement | App,\r\n callbacks: StreamCallbacks,\r\n options?: SSRContextOptions | SSRContext\r\n ): Promise<void>;\r\n\r\n /** Create a raw SSRContext with plugins pre-configured */\r\n createContext(options?: SSRContextOptions): SSRContext;\r\n}\r\n\r\n/**\r\n * Create an SSR instance with plugin support.\r\n */\r\nexport function createSSR(): SSRInstance {\r\n const plugins: SSRPlugin[] = [];\r\n\r\n function makeContext(options?: SSRContextOptions | SSRContext): SSRContext {\r\n // Accept an existing SSRContext (has _componentId) or create one from options\r\n const ctx = (options && '_componentId' in options)\r\n ? options as SSRContext\r\n : createSSRContext(options as SSRContextOptions | undefined);\r\n ctx._plugins = plugins;\r\n // Run plugin setup hooks\r\n for (const plugin of plugins) {\r\n plugin.server?.setup?.(ctx);\r\n }\r\n return ctx;\r\n }\r\n\r\n return {\r\n use(plugin: SSRPlugin): SSRInstance {\r\n plugins.push(plugin);\r\n return this;\r\n },\r\n\r\n async render(input, options?) {\r\n const { element, appContext } = extractInput(input);\r\n\r\n // Enable head collection during SSR rendering\r\n enableSSRHead();\r\n\r\n let result = '';\r\n let ctx: SSRContext;\r\n\r\n // Try fast synchronous render path first (works with or without plugins).\r\n // All plugin hooks called during the tree walk are synchronous.\r\n const syncCtx = makeContext(options);\r\n const buf: string[] = [];\r\n const syncOk = renderToStringSync(element, syncCtx, null, appContext, buf);\r\n\r\n if (syncOk) {\r\n result = buf.join('');\r\n ctx = syncCtx;\r\n } else {\r\n // Tree has async operations — fall back to async generator path.\r\n // We need a fresh context since the sync attempt may have partially\r\n // modified plugin state.\r\n ctx = makeContext(options);\r\n for await (const chunk of renderToChunks(element, ctx, null, appContext)) {\r\n result += chunk;\r\n }\r\n }\r\n\r\n // Collect injected HTML from all plugins\r\n for (const plugin of plugins) {\r\n const injected = plugin.server?.getInjectedHTML?.(ctx);\r\n if (injected) {\r\n result += typeof injected === 'string' ? injected : await injected;\r\n }\r\n }\r\n\r\n // Collect streaming chunks (for renderToString, await all)\r\n for (const plugin of plugins) {\r\n const chunks = plugin.server?.getStreamingChunks?.(ctx);\r\n if (chunks) {\r\n for await (const chunk of chunks) {\r\n result += chunk;\r\n }\r\n }\r\n }\r\n\r\n // Collect head elements from useHead() calls during rendering\r\n const headConfigs = collectSSRHead();\r\n if (headConfigs.length > 0) {\r\n ctx.addHead(renderHeadToString(headConfigs));\r\n }\r\n\r\n return result;\r\n },\r\n\r\n renderStream(input, options?) {\r\n const ctx = makeContext(options);\r\n ctx._streaming = true;\r\n const { element, appContext } = extractInput(input);\r\n\r\n // Use pull-based ReadableStream backed by an async generator.\r\n // This avoids the push-based \"React Flight pattern\" (worst-case for\r\n // WebStreams — see Vercel fast-webstreams research) and provides\r\n // natural backpressure.\r\n async function* generateAll() {\r\n enableSSRHead();\r\n\r\n // Phase 1: Render main page with chunk batching (4KB threshold).\r\n // Batched enqueues are ~24x faster than individual ones.\r\n let buffer = '';\r\n const FLUSH_THRESHOLD = 4096;\r\n\r\n for await (const chunk of renderToChunks(element, ctx, null, appContext)) {\r\n buffer += chunk;\r\n if (buffer.length >= FLUSH_THRESHOLD) {\r\n yield buffer;\r\n buffer = '';\r\n }\r\n }\r\n if (buffer) { yield buffer; buffer = ''; }\r\n\r\n // Collect head from useHead() calls\r\n const headConfigs = collectSSRHead();\r\n if (headConfigs.length > 0) {\r\n ctx.addHead(renderHeadToString(headConfigs));\r\n }\r\n\r\n // Phase 2: Injected HTML from plugins\r\n for (const plugin of plugins) {\r\n const injected = plugin.server?.getInjectedHTML?.(ctx);\r\n if (injected) {\r\n const html = typeof injected === 'string' ? injected : await injected;\r\n if (html) yield html;\r\n }\r\n }\r\n\r\n // Phase 3: Stream async chunks — core + plugin interleaved\r\n for await (const chunk of streamAllAsyncChunks(ctx, plugins)) {\r\n yield chunk;\r\n }\r\n\r\n // Phase 4: Signal streaming complete\r\n yield `<script>window.__SIGX_STREAMING_COMPLETE__=true;window.dispatchEvent(new Event('sigx:ready'));</script>`;\r\n }\r\n\r\n const generator = generateAll();\r\n\r\n return new ReadableStream<string>({\r\n async pull(controller) {\r\n try {\r\n const { value, done } = await generator.next();\r\n if (done) {\r\n controller.close();\r\n } else {\r\n controller.enqueue(value);\r\n }\r\n } catch (error) {\r\n controller.error(error);\r\n }\r\n }\r\n });\r\n },\r\n\r\n renderNodeStream(input, options?) {\r\n const ctx = makeContext(options);\r\n ctx._streaming = true;\r\n const { element, appContext } = extractInput(input);\r\n\r\n async function* generate(): AsyncGenerator<string> {\r\n // Enable head collection\r\n enableSSRHead();\r\n\r\n // Phase 1: Render the main page (placeholders for async components)\r\n let buffer = '';\r\n const FLUSH_THRESHOLD = 4096;\r\n for await (const chunk of renderToChunks(element, ctx, null, appContext)) {\r\n buffer += chunk;\r\n if (buffer.length >= FLUSH_THRESHOLD) {\r\n yield buffer;\r\n buffer = '';\r\n }\r\n }\r\n if (buffer) { yield buffer; buffer = ''; }\r\n\r\n // Collect head from useHead() calls\r\n const headConfigs = collectSSRHead();\r\n if (headConfigs.length > 0) {\r\n ctx.addHead(renderHeadToString(headConfigs));\r\n }\r\n\r\n // Phase 2: Injected HTML from plugins\r\n for (const plugin of plugins) {\r\n const injected = plugin.server?.getInjectedHTML?.(ctx);\r\n if (injected) {\r\n const html = typeof injected === 'string' ? injected : await injected;\r\n if (html) yield html;\r\n }\r\n }\r\n\r\n // Phase 3: Stream async chunks — core + plugin interleaved\r\n for await (const chunk of streamAllAsyncChunks(ctx, plugins)) {\r\n yield chunk;\r\n }\r\n\r\n // Phase 4: Signal streaming complete\r\n yield `<script>window.__SIGX_STREAMING_COMPLETE__=true;window.dispatchEvent(new Event('sigx:ready'));</script>`;\r\n }\r\n\r\n return Readable.from(generate(), { objectMode: true });\r\n },\r\n\r\n async renderStreamWithCallbacks(input, callbacks, options?) {\r\n const ctx = makeContext(options);\r\n ctx._streaming = true;\r\n const { element, appContext } = extractInput(input);\r\n\r\n try {\r\n // Enable head collection\r\n enableSSRHead();\r\n\r\n // Phase 1: Render the shell\r\n let shellHtml = '';\r\n for await (const chunk of renderToChunks(element, ctx, null, appContext)) {\r\n shellHtml += chunk;\r\n }\r\n\r\n // Collect head from useHead() calls\r\n const headConfigs = collectSSRHead();\r\n if (headConfigs.length > 0) {\r\n ctx.addHead(renderHeadToString(headConfigs));\r\n }\r\n\r\n // Phase 2: Append plugin injected HTML to shell\r\n for (const plugin of plugins) {\r\n const injected = plugin.server?.getInjectedHTML?.(ctx);\r\n if (injected) {\r\n shellHtml += typeof injected === 'string' ? injected : await injected;\r\n }\r\n }\r\n\r\n shellHtml += `<script>window.__SIGX_STREAMING_COMPLETE__=true;window.dispatchEvent(new Event('sigx:ready'));</script>`;\r\n\r\n callbacks.onShellReady(shellHtml);\r\n\r\n // Phase 3: Stream async chunks — core + plugin interleaved\r\n for await (const chunk of streamAllAsyncChunks(ctx, plugins)) {\r\n callbacks.onAsyncChunk(chunk);\r\n }\r\n\r\n callbacks.onComplete();\r\n } catch (error) {\r\n callbacks.onError(error as Error);\r\n }\r\n },\r\n\r\n createContext(options?) {\r\n return makeContext(options);\r\n }\r\n };\r\n}\r\n","/**\r\n * Public SSR rendering APIs — convenience wrappers\r\n *\r\n * These delegate to `createSSR()` internally so there is exactly one\r\n * rendering pipeline. When no plugins are registered the plugin hooks\r\n * are simply no-ops, making these equivalent to calling `createSSR()`\r\n * directly — but with a simpler call signature for the common case.\r\n *\r\n * For plugin-driven rendering (islands, streaming async, etc.),\r\n * use `createSSR().use(plugin).render()` from `@sigx/server-renderer`.\r\n *\r\n * Entry points:\r\n * - `renderToString()` — full render to a single string\r\n * - `renderToStream()` — ReadableStream\r\n * - `renderToNodeStream()` — Node.js Readable (faster on Node.js)\r\n * - `renderToStreamWithCallbacks()` — callback-based streaming\r\n */\r\n\r\nimport type { JSXElement } from 'sigx';\r\nimport type { App } from 'sigx';\r\nimport type { Readable } from 'node:stream';\r\nimport type { SSRContext, SSRContextOptions } from './context';\r\nimport { createSSR } from '../ssr';\r\nimport type { StreamCallbacks } from './types';\r\n\r\n// Re-export StreamCallbacks from shared types (avoids circular dependency)\r\nexport type { StreamCallbacks } from './types';\r\n\r\n/** Shared no-plugin instance — created once, reused for all standalone calls. */\r\nconst _defaultSSR = createSSR();\r\n\r\n/**\r\n * Render JSX element or App to a ReadableStream.\r\n *\r\n * Internally delegates to `createSSR().renderStream()`.\r\n *\r\n * @example\r\n * ```tsx\r\n * // Simple usage with JSX\r\n * renderToStream(<App />)\r\n *\r\n * // With App instance for DI/plugins\r\n * const app = defineApp(<App />).use(router);\r\n * renderToStream(app)\r\n * ```\r\n */\r\nexport function renderToStream(input: JSXElement | App, context?: SSRContext): ReadableStream<string> {\r\n return _defaultSSR.renderStream(input, context);\r\n}\r\n\r\n/**\r\n * Render JSX element or App to a Node.js Readable stream.\r\n *\r\n * Faster than `renderToStream()` on Node.js because it bypasses WebStream\r\n * overhead entirely. Recommended for Express, Fastify, H3, and other\r\n * Node.js HTTP frameworks.\r\n *\r\n * @example\r\n * ```tsx\r\n * import { renderToNodeStream } from '@sigx/server-renderer/server';\r\n *\r\n * const stream = renderToNodeStream(<App />);\r\n * stream.pipe(res);\r\n * ```\r\n */\r\nexport function renderToNodeStream(input: JSXElement | App, context?: SSRContext): Readable {\r\n return _defaultSSR.renderNodeStream(input, context);\r\n}\r\n\r\n/**\r\n * Render with callbacks for fine-grained streaming control.\r\n *\r\n * Internally delegates to `createSSR().renderStreamWithCallbacks()`.\r\n *\r\n * @example\r\n * ```tsx\r\n * const app = defineApp(<App />).use(router);\r\n * await renderToStreamWithCallbacks(app, callbacks)\r\n * ```\r\n */\r\nexport async function renderToStreamWithCallbacks(\r\n input: JSXElement | App,\r\n callbacks: StreamCallbacks,\r\n context?: SSRContext\r\n): Promise<void> {\r\n return _defaultSSR.renderStreamWithCallbacks(input, callbacks, context);\r\n}\r\n\r\n/**\r\n * Render JSX element or App to string.\r\n *\r\n * Internally delegates to `createSSR().render()`.\r\n *\r\n * @example\r\n * ```tsx\r\n * const html = await renderToString(<App />);\r\n *\r\n * const app = defineApp(<App />).use(router);\r\n * const html = await renderToString(app);\r\n * ```\r\n */\r\nexport async function renderToString(input: JSXElement | App, context?: SSRContext): Promise<string> {\r\n return _defaultSSR.render(input, context);\r\n}\r\n","/**\r\n * @sigx/server-renderer/server\r\n * \r\n * Server-side rendering with streaming support and hydration markers.\r\n * Strategy-agnostic — plugins add islands, Suspense, etc.\r\n */\r\n\r\n// Load SSR type augmentations (SSRHelper, ComponentSetupContext extensions)\r\nimport '../client-directives.js';\r\n\r\n// Load SSR directive type augmentation (adds getSSRProps to DirectiveDefinition)\r\nimport '../directive-ssr-types.js';\r\n\r\n// Patch getSSRProps onto built-in directives (show, etc.)\r\nimport { initDirectivesForSSR } from '../builtin-ssr-directives.js';\r\ninitDirectivesForSSR();\r\n\r\nexport { renderToStream, renderToNodeStream, renderToString, renderToStreamWithCallbacks } from './render-api';\r\nexport { renderVNodeToString } from './render-core';\r\nexport { createSSRContext } from './context';\r\nexport type { SSRContext, SSRContextOptions, RenderOptions, CorePendingAsync } from './context';\r\nexport { generateStreamingScript, generateReplacementScript, escapeJsonForScript } from './streaming';\r\nexport type { SSRSignalFn, StreamCallbacks } from './types';\r\nexport { generateSignalKey } from './types';\r\n"],"mappings":"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"}