@sigx/server-renderer 0.1.8 → 0.1.10

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 +1 @@
1
- {"version":3,"file":"hydrate-component.d.ts","sourceRoot":"","sources":["../../src/client/hydrate-component.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACH,KAAK,EAiBR,MAAM,MAAM,CAAC;AAQd;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAwL9J"}
1
+ {"version":3,"file":"hydrate-component.d.ts","sourceRoot":"","sources":["../../src/client/hydrate-component.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACH,KAAK,EAKR,MAAM,MAAM,CAAC;AAqBd;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,QAAQ,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,cAAc,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAwL9J"}
@@ -1 +1 @@
1
- {"version":3,"file":"hydrate-context.d.ts","sourceRoot":"","sources":["../../src/client/hydrate-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,KAAK,EAIR,MAAM,MAAM,CAAC;AACd,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAKnD,MAAM,WAAW,aAAc,SAAQ,KAAK;IACxC,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,CAAC,EAAE,GAAG,CAAC;CAChB;AAGD,YAAY,EAAE,WAAW,EAAE,CAAC;AAgB5B;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAE5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,EAAE,CAE9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAID;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAE7E;AAED,yDAAyD;AACzD,wBAAgB,oBAAoB,IAAI,UAAU,GAAG,IAAI,CAExD;AAED,mDAAmD;AACnD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAEjE;AAID;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,WAAW,CA0BnF;AAID;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK,GAAG,IAAI,CAiB3D"}
1
+ {"version":3,"file":"hydrate-context.d.ts","sourceRoot":"","sources":["../../src/client/hydrate-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,KAAK,EAGR,MAAM,MAAM,CAAC;AAEd,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAKnD,MAAM,WAAW,aAAc,SAAQ,KAAK;IACxC,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,eAAe,CAAC,EAAE,GAAG,CAAC;IACtB,MAAM,CAAC,EAAE,GAAG,CAAC;CAChB;AAGD,YAAY,EAAE,WAAW,EAAE,CAAC;AAgB5B;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAE5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,SAAS,EAAE,CAE9C;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAID;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAE7E;AAED,yDAAyD;AACzD,wBAAgB,oBAAoB,IAAI,UAAU,GAAG,IAAI,CAExD;AAED,mDAAmD;AACnD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAEjE;AAID;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,WAAW,CA0BnF;AAID;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK,GAAG,IAAI,CAiB3D"}
@@ -1 +1 @@
1
- {"version":3,"file":"hydrate-core.d.ts","sourceRoot":"","sources":["../../src/client/hydrate-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,KAAK,EAOR,MAAM,MAAM,CAAC;AACd,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAIvC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CA6BvF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CA+HrF"}
1
+ {"version":3,"file":"hydrate-core.d.ts","sourceRoot":"","sources":["../../src/client/hydrate-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACH,KAAK,EAIR,MAAM,MAAM,CAAC;AAEd,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAIvC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI,CA6BvF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CA+HrF"}
@@ -1,2 +1,3 @@
1
- import { a as clearClientPlugins, c as getCurrentAppContext, d as setPendingServerState, i as hydrateComponent, l as registerClientPlugin, n as hydrate, o as createRestoringSignal, r as hydrateNode, s as getClientPlugins, t as ssrClientPlugin, u as setCurrentAppContext } from "../client-ggDL-Wx2.js";
1
+ import "../types-D9iicsq6.js";
2
+ import { a as clearClientPlugins, c as getCurrentAppContext, d as setPendingServerState, i as hydrateComponent, l as registerClientPlugin, n as hydrate, o as createRestoringSignal, r as hydrateNode, s as getClientPlugins, t as ssrClientPlugin, u as setCurrentAppContext } from "../client-CRfOEHiT.js";
2
3
  export { clearClientPlugins, createRestoringSignal, getClientPlugins, getCurrentAppContext, hydrate, hydrateComponent, hydrateNode, registerClientPlugin, setCurrentAppContext, setPendingServerState, ssrClientPlugin };
@@ -1,5 +1,5 @@
1
- import { t as generateSignalKey } from "./types-B4Rf1Xot.js";
2
- import { Fragment, Text, createEmit, createPropsAccessor, createSlots, effect, filterClientDirectives, getCurrentInstance, isComponent, isModel, mount, normalizeSubTree, onElementMounted, patch, patchDirective, patchProp, provideAppContext, registerContextExtension, render, setCurrentInstance, signal } from "sigx";
1
+ import { n as internals_exports, t as generateSignalKey } from "./types-D9iicsq6.js";
2
+ import { Fragment, Text, effect, getCurrentInstance, isComponent, isModel, render, signal } from "sigx";
3
3
  var _pendingServerState = null;
4
4
  var _currentAppContext = null;
5
5
  var _clientPlugins = [];
@@ -46,7 +46,7 @@ function normalizeElement(element) {
46
46
  };
47
47
  return element;
48
48
  }
49
- registerContextExtension((ctx) => {
49
+ (0, internals_exports.registerContextExtension)((ctx) => {
50
50
  const serverState = _pendingServerState;
51
51
  if (serverState) {
52
52
  ctx._serverState = serverState;
@@ -93,7 +93,7 @@ function hydrateComponent(vnode, dom, parent, serverState, trailingMarker) {
93
93
  if (text.startsWith("$c:")) parseInt(text.slice(3), 10);
94
94
  }
95
95
  const internalVNode = vnode;
96
- const { children, slots: slotsFromProps, $models: modelsData, ...propsData } = filterClientDirectives(vnode.props || {});
96
+ const { children, slots: slotsFromProps, $models: modelsData, ...propsData } = (0, internals_exports.filterClientDirectives)(vnode.props || {});
97
97
  const propsWithModels = { ...propsData };
98
98
  if (modelsData) for (const modelKey in modelsData) {
99
99
  const modelValue = modelsData[modelKey];
@@ -101,7 +101,7 @@ function hydrateComponent(vnode, dom, parent, serverState, trailingMarker) {
101
101
  }
102
102
  const reactiveProps = signal(propsWithModels);
103
103
  internalVNode._componentProps = reactiveProps;
104
- const slots = createSlots(children, slotsFromProps);
104
+ const slots = (0, internals_exports.createSlots)(children, slotsFromProps);
105
105
  internalVNode._slots = slots;
106
106
  const mountHooks = [];
107
107
  const unmountHooks = [];
@@ -117,9 +117,9 @@ function hydrateComponent(vnode, dom, parent, serverState, trailingMarker) {
117
117
  const componentCtx = {
118
118
  el: parent,
119
119
  signal: signalFn,
120
- props: createPropsAccessor(reactiveProps),
120
+ props: (0, internals_exports.createPropsAccessor)(reactiveProps),
121
121
  slots,
122
- emit: createEmit(reactiveProps),
122
+ emit: (0, internals_exports.createEmit)(reactiveProps),
123
123
  parent: parentInstance,
124
124
  onMounted: (fn) => {
125
125
  mountHooks.push(fn);
@@ -139,22 +139,22 @@ function hydrateComponent(vnode, dom, parent, serverState, trailingMarker) {
139
139
  ssr: ssrHelper,
140
140
  _serverState: serverState
141
141
  };
142
- if (!parentInstance && getCurrentAppContext()) provideAppContext(componentCtx, getCurrentAppContext());
143
- const prev = setCurrentInstance(componentCtx);
142
+ if (!parentInstance && getCurrentAppContext()) (0, internals_exports.provideAppContext)(componentCtx, getCurrentAppContext());
143
+ const prev = (0, internals_exports.setCurrentInstance)(componentCtx);
144
144
  let renderFn;
145
145
  try {
146
146
  renderFn = setup(componentCtx);
147
147
  } catch (err) {
148
148
  if (process.env.NODE_ENV !== "production") console.error(`Error hydrating component ${componentName}:`, err);
149
149
  } finally {
150
- setCurrentInstance(prev);
150
+ (0, internals_exports.setCurrentInstance)(prev);
151
151
  }
152
152
  let endDom = dom;
153
153
  if (renderFn) {
154
154
  componentCtx.renderFn = renderFn;
155
155
  let isFirstRender = true;
156
156
  const componentEffect = effect(() => {
157
- const prevInstance = setCurrentInstance(componentCtx);
157
+ const prevInstance = (0, internals_exports.setCurrentInstance)(componentCtx);
158
158
  try {
159
159
  const subTreeResult = componentCtx.renderFn();
160
160
  const prevSubTree = internalVNode._subTree;
@@ -162,24 +162,24 @@ function hydrateComponent(vnode, dom, parent, serverState, trailingMarker) {
162
162
  if (isFirstRender) isFirstRender = false;
163
163
  else if (prevSubTree && prevSubTree.dom) {
164
164
  const patchContainer = prevSubTree.dom.parentNode || parent;
165
- const emptyNode = normalizeSubTree(null);
166
- patch(prevSubTree, emptyNode, patchContainer);
165
+ const emptyNode = (0, internals_exports.normalizeSubTree)(null);
166
+ (0, internals_exports.patch)(prevSubTree, emptyNode, patchContainer);
167
167
  internalVNode._subTree = emptyNode;
168
168
  }
169
169
  return;
170
170
  }
171
- const subTree = normalizeSubTree(subTreeResult);
171
+ const subTree = (0, internals_exports.normalizeSubTree)(subTreeResult);
172
172
  if (isFirstRender) {
173
173
  isFirstRender = false;
174
174
  endDom = hydrateNode(subTree, dom, parent);
175
175
  internalVNode._subTree = subTree;
176
176
  } else {
177
- if (prevSubTree) patch(prevSubTree, subTree, prevSubTree.dom?.parentNode || parent);
178
- else mount(subTree, parent, anchor || null);
177
+ if (prevSubTree) (0, internals_exports.patch)(prevSubTree, subTree, prevSubTree.dom?.parentNode || parent);
178
+ else (0, internals_exports.mount)(subTree, parent, anchor || null);
179
179
  internalVNode._subTree = subTree;
180
180
  }
181
181
  } finally {
182
- setCurrentInstance(prevInstance);
182
+ (0, internals_exports.setCurrentInstance)(prevInstance);
183
183
  }
184
184
  });
185
185
  internalVNode._effect = componentEffect;
@@ -260,11 +260,11 @@ function hydrateNode(vnode, dom, parent) {
260
260
  if (key === "children" || key === "key") continue;
261
261
  if (key.startsWith("client:")) continue;
262
262
  if (key.charCodeAt(0) === 117 && key.startsWith("use:")) {
263
- patchDirective(el, key.slice(4), null, vnode.props[key], getCurrentAppContext());
263
+ (0, internals_exports.patchDirective)(el, key.slice(4), null, vnode.props[key], getCurrentAppContext());
264
264
  hasDirectives = true;
265
- } else patchProp(el, key, null, vnode.props[key]);
265
+ } else (0, internals_exports.patchProp)(el, key, null, vnode.props[key]);
266
266
  }
267
- if (hasDirectives) onElementMounted(el);
267
+ if (hasDirectives) (0, internals_exports.onElementMounted)(el);
268
268
  if (vnode.props.ref) {
269
269
  if (typeof vnode.props.ref === "function") vnode.props.ref(el);
270
270
  else if (typeof vnode.props.ref === "object") vnode.props.ref.current = el;
@@ -306,4 +306,4 @@ const ssrClientPlugin = {
306
306
  };
307
307
  export { clearClientPlugins as a, getCurrentAppContext as c, setPendingServerState as d, hydrateComponent as i, registerClientPlugin as l, hydrate as n, createRestoringSignal as o, hydrateNode as r, getClientPlugins as s, ssrClientPlugin as t, setCurrentAppContext as u };
308
308
 
309
- //# sourceMappingURL=client-ggDL-Wx2.js.map
309
+ //# sourceMappingURL=client-CRfOEHiT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-CRfOEHiT.js","names":[],"sources":["../src/client/hydrate-context.ts","../src/client/hydrate-component.ts","../src/client/hydrate-core.ts","../src/client/plugin.ts"],"sourcesContent":["/**\r\n * Hydration context and state management\r\n *\r\n * Manages server state restoration, app context tracking,\r\n * client plugin registration, and the SSR context extension for components.\r\n *\r\n * Strategy-specific concerns (island data, async hydration) are handled\r\n * by plugins registered via `registerClientPlugin()`.\r\n */\r\n\r\nimport {\r\n VNode,\r\n signal,\r\n Text,\r\n} from 'sigx';\r\nimport { registerContextExtension } from 'sigx/internals';\r\nimport type { AppContext } from 'sigx';\r\nimport type { SSRPlugin } from '../plugin';\r\nimport type { SSRSignalFn } from '../server/types';\r\nimport { generateSignalKey } from '../server/types';\r\n\r\n// ============= Internal Types =============\r\n\r\nexport interface InternalVNode extends VNode {\r\n _subTree?: VNode;\r\n _effect?: any;\r\n _componentProps?: any;\r\n _slots?: any;\r\n}\r\n\r\n// Re-export SSRSignalFn from shared types so existing consumers work\r\nexport type { SSRSignalFn };\r\n\r\n// ============= Module State =============\r\n\r\n// Track server state for async components being mounted after streaming\r\nlet _pendingServerState: Record<string, any> | null = null;\r\n\r\n// Track current app context during hydration for DI\r\n// Used for deferred hydration callbacks\r\nlet _currentAppContext: AppContext | null = null;\r\n\r\n// Registered client-side SSR plugins\r\nlet _clientPlugins: SSRPlugin[] = [];\r\n\r\n// ============= Client Plugin Registry =============\r\n\r\n/**\r\n * Register a client-side SSR plugin.\r\n * Plugins are called during hydration to intercept component processing,\r\n * skip default hydration walk, or run post-hydration logic.\r\n */\r\nexport function registerClientPlugin(plugin: SSRPlugin): void {\r\n _clientPlugins.push(plugin);\r\n}\r\n\r\n/**\r\n * Get all registered client-side plugins.\r\n */\r\nexport function getClientPlugins(): SSRPlugin[] {\r\n return _clientPlugins;\r\n}\r\n\r\n/**\r\n * Clear all registered client plugins (useful for testing).\r\n */\r\nexport function clearClientPlugins(): void {\r\n _clientPlugins = [];\r\n}\r\n\r\n// ============= State Accessors =============\r\n\r\n/**\r\n * Set server state that should be used for the next component mount.\r\n * Used internally when mounting async components after streaming.\r\n */\r\nexport function setPendingServerState(state: Record<string, any> | null): void {\r\n _pendingServerState = state;\r\n}\r\n\r\n/** Get the current app context for deferred hydration */\r\nexport function getCurrentAppContext(): AppContext | null {\r\n return _currentAppContext;\r\n}\r\n\r\n/** Set the current app context during hydration */\r\nexport function setCurrentAppContext(ctx: AppContext | null): void {\r\n _currentAppContext = ctx;\r\n}\r\n\r\n// ============= Signal Restoration =============\r\n\r\n/**\r\n * Creates a signal function that restores state from server-captured values.\r\n * Used during hydration of async components to avoid re-fetching data.\r\n * Supports both primitive and object signals.\r\n */\r\nexport function createRestoringSignal(serverState: Record<string, any>): SSRSignalFn {\r\n let signalIndex = 0;\r\n let hasWarnedPositional = false;\r\n\r\n return function restoringSignal(initial: any, name?: string): any {\r\n // Generate a stable key for this signal (must match server-side)\r\n const key = generateSignalKey(name, signalIndex++);\r\n\r\n // Dev warning: positional keys are fragile\r\n if (process.env.NODE_ENV !== 'production' && !name && !hasWarnedPositional) {\r\n hasWarnedPositional = true;\r\n console.warn(\r\n `[SSR Hydration] Signal restored without a name — using positional key \"${key}\". ` +\r\n `If signal declaration order differs between server and client builds, ` +\r\n `state will be silently mismatched. Use named signals: signal(value, \"name\")`\r\n );\r\n }\r\n\r\n // Check if we have server state for this signal\r\n if (key in serverState) {\r\n return signal(serverState[key]);\r\n }\r\n\r\n // No server state, use initial value\r\n return signal(initial as any);\r\n } as SSRSignalFn;\r\n}\r\n\r\n// ============= Element Normalization =============\r\n\r\n/**\r\n * Normalize any element to VNode\r\n */\r\nexport function normalizeElement(element: any): VNode | null {\r\n if (element == null || element === true || element === false) {\r\n return null;\r\n }\r\n\r\n if (typeof element === 'string' || typeof element === 'number') {\r\n return {\r\n type: Text,\r\n props: {},\r\n key: null,\r\n children: [],\r\n dom: null,\r\n text: element\r\n };\r\n }\r\n\r\n return element as VNode;\r\n}\r\n\r\n// ============= Context Extension Registration =============\r\n\r\n/**\r\n * Register the SSR context extension for all components.\r\n * This provides the `ssr` object with a no-op `load()` for client-side rendering.\r\n * Also handles server state restoration for async streamed components.\r\n */\r\nregisterContextExtension((ctx: any) => {\r\n // Check if we have pending server state (from async streaming)\r\n const serverState = _pendingServerState;\r\n if (serverState) {\r\n ctx._serverState = serverState;\r\n _pendingServerState = null; // Clear after use\r\n\r\n // Override signal function to use restoring signal\r\n ctx.signal = createRestoringSignal(serverState);\r\n\r\n // ssr.load() should be a no-op since we have restored state\r\n ctx.ssr = {\r\n load: (_fn: () => Promise<void>) => {\r\n // Skip - using restored server state\r\n },\r\n isServer: false,\r\n isHydrating: true\r\n };\r\n } else if (ctx._serverState) {\r\n // Already has server state (from hydration)\r\n ctx.ssr = {\r\n load: (_fn: () => Promise<void>) => {\r\n // Skip - using restored server state\r\n },\r\n isServer: false,\r\n isHydrating: true\r\n };\r\n } else {\r\n // Default client-side ssr helper - runs async functions for client-side navigation\r\n ctx.ssr = {\r\n load: (fn: () => Promise<void>) => {\r\n // On client-side navigation (not hydration), execute the async function\r\n fn().catch(err => console.error('[SSR] load error:', err));\r\n },\r\n isServer: false,\r\n isHydrating: false\r\n };\r\n }\r\n});\r\n","/**\r\n * Component hydration logic — strategy-agnostic\r\n *\r\n * Handles running component setup, creating reactive effects,\r\n * and restoring server state for hydrated components.\r\n * Does not depend on islands or any specific SSR strategy.\r\n */\r\n\r\nimport {\r\n VNode,\r\n getCurrentInstance,\r\n signal,\r\n effect,\r\n isModel\r\n} from 'sigx';\r\nimport type { ComponentSetupContext, SlotsObject } from 'sigx';\r\nimport {\r\n setCurrentInstance,\r\n createPropsAccessor,\r\n createSlots,\r\n normalizeSubTree,\r\n patch,\r\n mount,\r\n patchProp,\r\n filterClientDirectives,\r\n createEmit,\r\n provideAppContext,\r\n} from 'sigx/internals';\r\nimport {\r\n InternalVNode,\r\n createRestoringSignal,\r\n getCurrentAppContext\r\n} from './hydrate-context';\r\nimport { hydrateNode } from './hydrate-core';\r\n\r\n/**\r\n * Minimal type for component factories used in hydration.\r\n * Compatible with ComponentFactory from runtime-core.\r\n */\r\nexport interface ComponentFactory {\r\n __setup: Function;\r\n __name?: string;\r\n __async?: boolean;\r\n}\r\n\r\n/**\r\n * Hydrate a component - run setup and create reactive effect\r\n *\r\n * With trailing markers, the structure is: <content><!--$c:id-->\r\n * - dom points to start of content\r\n * - trailingMarker (if provided) is the anchor at the end\r\n *\r\n * @param vnode - The VNode to hydrate\r\n * @param dom - The DOM node to start from (content starts here)\r\n * @param parent - The parent node\r\n * @param serverState - Optional state captured from server for async components\r\n * @param trailingMarker - Optional trailing marker comment (the component anchor)\r\n */\r\nexport function hydrateComponent(vnode: VNode, dom: Node | null, parent: Node, serverState?: Record<string, any>, trailingMarker?: Comment | null): Node | null {\r\n const componentFactory = vnode.type as unknown as ComponentFactory;\r\n const setup = componentFactory.__setup;\r\n const componentName = componentFactory.__name || 'Anonymous';\r\n\r\n // With trailing markers, find the marker if not provided\r\n let anchor: Comment | null = trailingMarker || null;\r\n let componentId: number | null = null;\r\n\r\n if (!anchor) {\r\n // Find trailing marker by traversing forward\r\n let current: Node | null = dom;\r\n while (current) {\r\n if (current.nodeType === Node.COMMENT_NODE) {\r\n const text = (current as Comment).data;\r\n if (text.startsWith('$c:')) {\r\n anchor = current as Comment;\r\n componentId = parseInt(text.slice(3), 10);\r\n break;\r\n }\r\n }\r\n current = current.nextSibling;\r\n }\r\n } else {\r\n // Extract component ID from provided marker\r\n const text = anchor.data;\r\n if (text.startsWith('$c:')) {\r\n componentId = parseInt(text.slice(3), 10);\r\n }\r\n }\r\n\r\n const internalVNode = vnode as InternalVNode;\r\n const initialProps = vnode.props || {};\r\n const { children, slots: slotsFromProps, $models: modelsData, ...propsData } = filterClientDirectives(initialProps);\r\n\r\n // Merge Model<T> objects directly into props for unified access: props.model.value\r\n const propsWithModels = { ...propsData };\r\n if (modelsData) {\r\n for (const modelKey in modelsData) {\r\n const modelValue = modelsData[modelKey];\r\n if (isModel(modelValue)) {\r\n propsWithModels[modelKey] = modelValue;\r\n }\r\n }\r\n }\r\n\r\n // Create reactive props\r\n const reactiveProps = signal(propsWithModels);\r\n internalVNode._componentProps = reactiveProps;\r\n\r\n // Create slots\r\n const slots = createSlots(children, slotsFromProps);\r\n internalVNode._slots = slots;\r\n\r\n const mountHooks: ((ctx: any) => void)[] = [];\r\n const unmountHooks: ((ctx: any) => void)[] = [];\r\n const createdHooks: (() => void)[] = [];\r\n const updatedHooks: (() => void)[] = [];\r\n\r\n const parentInstance = getCurrentInstance();\r\n\r\n // Use restoring signal when we have server state to restore\r\n const signalFn = serverState\r\n ? createRestoringSignal(serverState)\r\n : signal;\r\n\r\n // Create SSR helper for client-side\r\n // When hydrating with server state, ssr.load() is a no-op (data already restored)\r\n const hasServerState = !!serverState;\r\n const ssrHelper = {\r\n load(_fn: () => Promise<void>): void {\r\n // No-op on client when hydrating - signal state was restored from server\r\n },\r\n isServer: false,\r\n isHydrating: hasServerState\r\n };\r\n\r\n const componentCtx: ComponentSetupContext = {\r\n el: parent as HTMLElement,\r\n signal: signalFn as typeof signal,\r\n props: createPropsAccessor(reactiveProps),\r\n slots: slots,\r\n emit: createEmit(reactiveProps),\r\n parent: parentInstance,\r\n onMounted: (fn) => { mountHooks.push(fn); },\r\n onUnmounted: (fn) => { unmountHooks.push(fn); },\r\n onCreated: (fn) => { createdHooks.push(fn); },\r\n onUpdated: (fn) => { updatedHooks.push(fn); },\r\n expose: () => { },\r\n renderFn: null,\r\n update: () => { },\r\n ssr: ssrHelper,\r\n _serverState: serverState\r\n };\r\n\r\n // For ROOT component only (no parent), provide the AppContext\r\n if (!parentInstance && getCurrentAppContext()) {\r\n provideAppContext(componentCtx, getCurrentAppContext()!);\r\n }\r\n\r\n const prev = setCurrentInstance(componentCtx);\r\n let renderFn: (() => any) | undefined;\r\n\r\n try {\r\n renderFn = setup(componentCtx);\r\n } catch (err) {\r\n if (process.env.NODE_ENV !== 'production') {\r\n console.error(`Error hydrating component ${componentName}:`, err);\r\n }\r\n } finally {\r\n setCurrentInstance(prev);\r\n }\r\n\r\n // Track where the component's DOM starts\r\n let endDom: Node | null = dom;\r\n\r\n if (renderFn) {\r\n componentCtx.renderFn = renderFn;\r\n let isFirstRender = true;\r\n\r\n // Create reactive effect - on first run, hydrate; on subsequent, use render()\r\n const componentEffect = effect(() => {\r\n const prevInstance = setCurrentInstance(componentCtx);\r\n try {\r\n const subTreeResult = componentCtx.renderFn!();\r\n const prevSubTree = internalVNode._subTree;\r\n\r\n // Handle null/undefined renders (e.g., conditional components like Modal)\r\n if (subTreeResult == null) {\r\n if (isFirstRender) {\r\n // First render returned null - SSR didn't render content, nothing to hydrate\r\n isFirstRender = false;\r\n } else if (prevSubTree && prevSubTree.dom) {\r\n // Had content before, now returning null - unmount the previous subtree\r\n const patchContainer = prevSubTree.dom.parentNode as Element || parent;\r\n const emptyNode = normalizeSubTree(null);\r\n patch(prevSubTree, emptyNode, patchContainer);\r\n internalVNode._subTree = emptyNode;\r\n }\r\n return;\r\n }\r\n\r\n const subTree = normalizeSubTree(subTreeResult);\r\n\r\n if (isFirstRender) {\r\n // First render - hydrate against existing DOM\r\n isFirstRender = false;\r\n endDom = hydrateNode(subTree, dom, parent);\r\n internalVNode._subTree = subTree;\r\n } else {\r\n // Subsequent renders - use patch directly like runtime-core does\r\n if (prevSubTree) {\r\n const patchContainer = prevSubTree.dom?.parentNode as Element || parent;\r\n patch(prevSubTree, subTree, patchContainer);\r\n } else {\r\n // No previous subtree - mount fresh using the component's anchor\r\n mount(subTree, parent as Element, anchor || null);\r\n }\r\n internalVNode._subTree = subTree;\r\n }\r\n } finally {\r\n setCurrentInstance(prevInstance);\r\n }\r\n });\r\n\r\n internalVNode._effect = componentEffect;\r\n componentCtx.update = () => componentEffect();\r\n }\r\n\r\n // Use trailing anchor comment as the component's dom reference\r\n vnode.dom = anchor || endDom;\r\n\r\n // Run mount hooks\r\n const mountCtx = { el: parent as Element };\r\n createdHooks.forEach(hook => hook());\r\n mountHooks.forEach(hook => hook(mountCtx));\r\n\r\n // Store cleanup\r\n vnode.cleanup = () => {\r\n unmountHooks.forEach(hook => hook(mountCtx));\r\n };\r\n\r\n // With trailing markers, the anchor IS the end - return next sibling\r\n return anchor ? anchor.nextSibling : endDom;\r\n}\r\n","/**\r\n * Core hydration logic — strategy-agnostic\r\n *\r\n * Walks existing server-rendered DOM and attaches event handlers,\r\n * creates reactive effects, and delegates components to the component hydrator.\r\n *\r\n * Plugins registered via `registerClientPlugin()` can intercept component\r\n * hydration (e.g., for deferred/island-based hydration strategies).\r\n */\r\n\r\nimport {\r\n VNode,\r\n Fragment,\r\n Text,\r\n isComponent,\r\n} from 'sigx';\r\nimport { patchProp, patchDirective, onElementMounted } from 'sigx/internals';\r\nimport type { AppContext } from 'sigx';\r\nimport { normalizeElement, setCurrentAppContext, getCurrentAppContext, getClientPlugins } from './hydrate-context';\r\nimport { hydrateComponent } from './hydrate-component';\r\n\r\n/**\r\n * Hydrate a server-rendered app.\r\n *\r\n * This walks the existing DOM to attach event handlers, runs component\r\n * setup functions to establish reactivity, then uses runtime-dom for updates.\r\n *\r\n * Registered client plugins are called at appropriate points:\r\n * - `beforeHydrate`: before the DOM walk (return false to skip it entirely)\r\n * - `hydrateComponent`: for each component (return { next } to handle it)\r\n * - `afterHydrate`: after the DOM walk completes\r\n *\r\n * @param element - The root element/VNode to hydrate\r\n * @param container - The DOM container with SSR content\r\n * @param appContext - The app context for DI (provides, etc.)\r\n */\r\nexport function hydrate(element: any, container: Element, appContext?: AppContext): void {\r\n const vnode = normalizeElement(element);\r\n if (!vnode) return;\r\n\r\n // Store app context for component hydration (DI needs this)\r\n setCurrentAppContext(appContext ?? null);\r\n\r\n const plugins = getClientPlugins();\r\n\r\n // Let plugins intercept before the DOM walk\r\n for (const plugin of plugins) {\r\n const result = plugin.client?.beforeHydrate?.(container);\r\n if (result === false) {\r\n // Plugin opted out of the default DOM walk (e.g., resumable SSR)\r\n (container as any)._vnode = vnode;\r\n return;\r\n }\r\n }\r\n\r\n // Walk existing DOM, attach handlers, and mount components\r\n hydrateNode(vnode, container.firstChild, container);\r\n\r\n // Post-hydration hooks\r\n for (const plugin of plugins) {\r\n plugin.client?.afterHydrate?.(container);\r\n }\r\n\r\n // Store vnode on container for potential future use\r\n (container as any)._vnode = vnode;\r\n}\r\n\r\n/**\r\n * Hydrate a VNode against existing DOM\r\n * This only attaches event handlers and refs - no DOM creation\r\n */\r\nexport function hydrateNode(vnode: VNode, dom: Node | null, parent: Node): Node | null {\r\n if (!vnode) return dom;\r\n\r\n // Skip comment nodes (<!--t--> text separators and <!--$c:N--> component markers).\r\n // Component markers are only meaningful when the VNode itself is a component —\r\n // for element/text/fragment VNodes, all comments are just SSR artifacts to skip past.\r\n const isComponentVNode = isComponent(vnode.type);\r\n const isTextVNode = vnode.type === Text;\r\n while (dom && dom.nodeType === Node.COMMENT_NODE) {\r\n if (isComponentVNode) {\r\n const commentText = (dom as Comment).data;\r\n // Stop at component markers — the component hydrator needs them for boundaries\r\n if (commentText.startsWith('$c:')) {\r\n break;\r\n }\r\n }\r\n // When a text VNode hits a <!--t--> separator, the SSR may have omitted the\r\n // preceding empty text (e.g. \"\" + \" · Logout\" → <!--t--> · Logout).\r\n // Replace the comment with an empty text node so this VNode can attach to it,\r\n // preserving the boundary for the next text VNode.\r\n if (isTextVNode && (dom as Comment).data === 't') {\r\n const emptyText = document.createTextNode('');\r\n parent.replaceChild(emptyText, dom);\r\n dom = emptyText;\r\n break;\r\n }\r\n dom = dom.nextSibling;\r\n }\r\n\r\n if (vnode.type === Text) {\r\n if (dom && dom.nodeType === Node.TEXT_NODE) {\r\n vnode.dom = dom;\r\n return dom.nextSibling;\r\n }\r\n // Hydration mismatch: expected a text node but got something else.\r\n // Create a fresh text node and insert it so the VNode has a valid DOM ref.\r\n const textNode = document.createTextNode(String(vnode.text ?? ''));\r\n if (dom) {\r\n parent.insertBefore(textNode, dom);\r\n } else {\r\n parent.appendChild(textNode);\r\n }\r\n vnode.dom = textNode;\r\n return dom;\r\n }\r\n\r\n if (vnode.type === Fragment) {\r\n let current = dom;\r\n for (const child of vnode.children) {\r\n current = hydrateNode(child, current, parent);\r\n }\r\n return current;\r\n }\r\n\r\n if (isComponent(vnode.type)) {\r\n // Let plugins intercept component hydration (e.g., islands scheduling)\r\n const plugins = getClientPlugins();\r\n for (const plugin of plugins) {\r\n const result = plugin.client?.hydrateComponent?.(vnode, dom, parent);\r\n if (result !== undefined) {\r\n // Plugin handled this component — return the next DOM node\r\n return result;\r\n }\r\n }\r\n\r\n // No plugin handled it — hydrate immediately\r\n return hydrateComponent(vnode, dom, parent);\r\n }\r\n\r\n if (typeof vnode.type === 'string') {\r\n if (!dom || dom.nodeType !== Node.ELEMENT_NODE) {\r\n if (process.env.NODE_ENV !== 'production') {\r\n console.warn('[Hydrate] Expected element but got:', dom);\r\n }\r\n return dom;\r\n }\r\n\r\n const el = dom as Element;\r\n vnode.dom = el;\r\n\r\n // Attach event handlers and props using patchProp from runtime-dom\r\n if (vnode.props) {\r\n let hasDirectives = false;\r\n for (const key in vnode.props) {\r\n if (key === 'children' || key === 'key') continue;\r\n if (key.startsWith('client:')) continue;\r\n\r\n if (key.charCodeAt(0) === 117 /* 'u' */ && key.startsWith('use:')) {\r\n // Route use:* directive props through patchDirective\r\n patchDirective(el, key.slice(4), null, vnode.props[key], getCurrentAppContext());\r\n hasDirectives = true;\r\n } else {\r\n // Use patchProp for consistent prop handling (events, refs, etc.)\r\n patchProp(el, key, null, vnode.props[key]);\r\n }\r\n }\r\n\r\n // Fire mounted hooks for directives (element is already in DOM during hydration)\r\n if (hasDirectives) {\r\n onElementMounted(el);\r\n }\r\n\r\n // Handle ref - patchProp skips refs, so we handle them here\r\n if (vnode.props.ref) {\r\n if (typeof vnode.props.ref === 'function') {\r\n vnode.props.ref(el);\r\n } else if (typeof vnode.props.ref === 'object') {\r\n vnode.props.ref.current = el;\r\n }\r\n }\r\n }\r\n\r\n // Hydrate children\r\n let childDom: Node | null = el.firstChild;\r\n for (const child of vnode.children) {\r\n childDom = hydrateNode(child, childDom, el);\r\n }\r\n\r\n // Fix select value after children are hydrated\r\n if (vnode.type === 'select' && vnode.props) {\r\n fixSelectValue(el as HTMLElement, vnode.props);\r\n }\r\n\r\n return el.nextSibling;\r\n }\r\n\r\n return dom;\r\n}\r\n\r\n/**\r\n * Fix select element value after hydrating children.\r\n * This is needed because <select>.value only works after <option> children exist in DOM.\r\n */\r\nfunction fixSelectValue(dom: HTMLElement, props: any) {\r\n if (dom.tagName === 'SELECT' && 'value' in props) {\r\n const val = props.value;\r\n if ((dom as HTMLSelectElement).multiple) {\r\n const options = (dom as HTMLSelectElement).options;\r\n const valArray = Array.isArray(val) ? val : [val];\r\n for (let i = 0; i < options.length; i++) {\r\n options[i].selected = valArray.includes(options[i].value);\r\n }\r\n } else {\r\n (dom as HTMLSelectElement).value = String(val);\r\n }\r\n }\r\n}\r\n","/**\r\n * SSR Client Plugin\r\n * \r\n * Provides app.hydrate() method for client-side hydration of server-rendered HTML.\r\n * This plugin follows the same pattern as the router plugin.\r\n */\r\n\r\nimport type { Plugin, App, AppContext } from '@sigx/runtime-core';\r\nimport { render } from 'sigx';\r\nimport { hydrate as hydrateImpl } from './hydrate-core';\r\n\r\n// ============================================================================\r\n// Type Augmentation\r\n// ============================================================================\r\n\r\n/**\r\n * Hydrate function signature - matches MountFn pattern\r\n */\r\nexport type HydrateFn<TContainer = any> = (\r\n element: any,\r\n container: TContainer,\r\n appContext: AppContext\r\n) => (() => void) | void;\r\n\r\ndeclare module '@sigx/runtime-core' {\r\n interface App<TContainer = any> {\r\n /**\r\n * Hydrate the app from server-rendered HTML.\r\n * \r\n * Unlike mount() which creates new DOM, hydrate() attaches to existing\r\n * server-rendered DOM, adding event handlers and establishing reactivity.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from 'sigx';\r\n * import { ssrClientPlugin } from '@sigx/server-renderer/client';\r\n * \r\n * const app = defineApp(<App />);\r\n * app.use(router)\r\n * .use(ssrClientPlugin)\r\n * .hydrate(document.getElementById('app')!);\r\n * ```\r\n */\r\n hydrate(container: TContainer): App<TContainer>;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Plugin Implementation\r\n// ============================================================================\r\n\r\n/**\r\n * SSR Client Plugin\r\n * \r\n * Adds the hydrate() method to the app instance for client-side hydration.\r\n * Also registers the SSR context extension for all components.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from 'sigx';\r\n * import { ssrClientPlugin } from '@sigx/server-renderer/client';\r\n * \r\n * const app = defineApp(<App />);\r\n * app.use(ssrClientPlugin)\r\n * .use(router)\r\n * .hydrate('#app');\r\n * ```\r\n */\r\nexport const ssrClientPlugin: Plugin = {\r\n name: '@sigx/server-renderer/client',\r\n\r\n install(app: App) {\r\n // Add hydrate method to the app instance\r\n (app as any).hydrate = function(container: Element | string): App {\r\n // Resolve container if string selector\r\n const resolvedContainer = typeof container === 'string'\r\n ? document.querySelector(container)\r\n : container;\r\n\r\n if (!resolvedContainer) {\r\n throw new Error(\r\n `[ssrClientPlugin] Cannot find container: ${container}. ` +\r\n 'Make sure the element exists in the DOM before calling hydrate().'\r\n );\r\n }\r\n\r\n // Get the root component from the app\r\n const rootComponent = (app as any)._rootComponent;\r\n \r\n if (!rootComponent) {\r\n throw new Error(\r\n '[ssrClientPlugin] No root component found on app. ' +\r\n 'Make sure you created the app with defineApp(<Component />).'\r\n );\r\n }\r\n\r\n // Check if there's actual SSR content to hydrate\r\n // If container is empty or only has comments, fall back to client-side render\r\n const hasSSRContent = resolvedContainer.firstElementChild !== null ||\r\n (resolvedContainer.firstChild !== null && \r\n resolvedContainer.firstChild.nodeType !== Node.COMMENT_NODE);\r\n\r\n // Get app context for passing to render (needed for inject() to work)\r\n const appContext = (app as any)._context;\r\n\r\n if (hasSSRContent) {\r\n // Perform hydration with app context for DI\r\n hydrateImpl(rootComponent, resolvedContainer, appContext);\r\n } else {\r\n // No SSR content - fall back to client-side render (dev mode)\r\n render(rootComponent, resolvedContainer, appContext);\r\n }\r\n\r\n // Store container on the vnode for potential unmount\r\n (resolvedContainer as any)._app = app;\r\n\r\n return app;\r\n };\r\n }\r\n};\r\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { a as collectSSRHead, c as useHead, f as renderVNodeToString, i as createSSR, m as initDirectivesForSSR, o as enableSSRHead, p as createSSRContext, r as renderToString, s as renderHeadToString, t as renderToStream } from "./server-UBcHtkm-.js";
2
- import { t as generateSignalKey } from "./types-B4Rf1Xot.js";
3
- import { t as ssrClientPlugin } from "./client-ggDL-Wx2.js";
1
+ import { t as generateSignalKey } from "./types-D9iicsq6.js";
2
+ import { a as collectSSRHead, c as useHead, f as renderVNodeToString, i as createSSR, m as initDirectivesForSSR, o as enableSSRHead, p as createSSRContext, r as renderToString, s as renderHeadToString, t as renderToStream } from "./server-DQ68_nhq.js";
3
+ import { t as ssrClientPlugin } from "./client-CRfOEHiT.js";
4
4
  initDirectivesForSSR();
5
5
  export { collectSSRHead, createSSR, createSSRContext, enableSSRHead, generateSignalKey, renderHeadToString, renderToStream, renderToString, renderVNodeToString, ssrClientPlugin, useHead };
6
6
 
@@ -1,3 +1,3 @@
1
- import { d as generateStreamingScript, f as renderVNodeToString, l as escapeJsonForScript, n as renderToStreamWithCallbacks, p as createSSRContext, r as renderToString, t as renderToStream, u as generateReplacementScript } from "../server-UBcHtkm-.js";
2
- import { t as generateSignalKey } from "../types-B4Rf1Xot.js";
1
+ import { t as generateSignalKey } from "../types-D9iicsq6.js";
2
+ import { d as generateStreamingScript, f as renderVNodeToString, l as escapeJsonForScript, n as renderToStreamWithCallbacks, p as createSSRContext, r as renderToString, t as renderToStream, u as generateReplacementScript } from "../server-DQ68_nhq.js";
3
3
  export { createSSRContext, escapeJsonForScript, generateReplacementScript, generateSignalKey, generateStreamingScript, renderToStream, renderToStreamWithCallbacks, renderToString, renderVNodeToString };
@@ -9,8 +9,7 @@
9
9
  * hydration directives, async streaming) lives in @sigx/ssr-islands and is
10
10
  * injected through the SSRPlugin hooks.
11
11
  */
12
- import { JSXElement, ComponentSetupContext } from 'sigx';
13
- import type { AppContext } from 'sigx';
12
+ import type { JSXElement, ComponentSetupContext, AppContext } from 'sigx';
14
13
  import type { SSRContext } from './context';
15
14
  export declare function escapeHtml(s: string): string;
16
15
  export declare function camelToKebab(str: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"render-core.d.ts","sourceRoot":"","sources":["../../src/server/render-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAGH,UAAU,EACV,qBAAqB,EASxB,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAY5C,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAQD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIhD;AAiBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CASjE;AA4BD;;;;;;GAMG;AACH,wBAAuB,cAAc,CACjC,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,UAAU,EACf,SAAS,GAAE,qBAAqB,GAAG,IAAW,EAC9C,UAAU,GAAE,UAAU,GAAG,IAAW,GACrC,cAAc,CAAC,MAAM,CAAC,CAiWxB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,GAAE,UAAU,GAAG,IAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAMrI;AAID;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,qBAAqB,GAAG,IAAI,EACvC,UAAU,EAAE,UAAU,GAAG,IAAI,EAC7B,GAAG,EAAE,MAAM,EAAE,GACd,OAAO,CAmQT"}
1
+ {"version":3,"file":"render-core.d.ts","sourceRoot":"","sources":["../../src/server/render-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,KAAK,EAAE,UAAU,EAAE,qBAAqB,EAAoC,UAAU,EAAE,MAAM,MAAM,CAAC;AAO5G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAY5C,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAQD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIhD;AAiBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CASjE;AA4BD;;;;;;GAMG;AACH,wBAAuB,cAAc,CACjC,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,UAAU,EACf,SAAS,GAAE,qBAAqB,GAAG,IAAW,EAC9C,UAAU,GAAE,UAAU,GAAG,IAAW,GACrC,cAAc,CAAC,MAAM,CAAC,CAiWxB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,UAAU,EAAE,UAAU,GAAE,UAAU,GAAG,IAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAMrI;AAID;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAC9B,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,qBAAqB,GAAG,IAAI,EACvC,UAAU,EAAE,UAAU,GAAG,IAAI,EAC7B,GAAG,EAAE,MAAM,EAAE,GACd,OAAO,CAmQT"}
@@ -1,5 +1,6 @@
1
- import { resolveBuiltInDirective, show } from "@sigx/runtime-dom";
2
- import { Fragment, Text, createPropsAccessor, getCurrentInstance, isComponent, isDirective, provideAppContext, setCurrentInstance, signal } from "sigx";
1
+ import { n as internals_exports } from "./types-D9iicsq6.js";
2
+ import { show } from "@sigx/runtime-dom";
3
+ import { Fragment, Text, getCurrentInstance, isComponent, isDirective, signal } from "sigx";
3
4
  var _initialized = false;
4
5
  function initShowForSSR() {
5
6
  show.getSSRProps = ({ value }) => {
@@ -143,7 +144,7 @@ async function* renderToChunks(element, ctx, parentCtx = null, appContext = null
143
144
  let componentCtx = {
144
145
  el: null,
145
146
  signal,
146
- props: createPropsAccessor(propsData),
147
+ props: (0, internals_exports.createPropsAccessor)(propsData),
147
148
  slots,
148
149
  emit: () => {},
149
150
  parent: parentCtx,
@@ -167,8 +168,8 @@ async function* renderToChunks(element, ctx, parentCtx = null, appContext = null
167
168
  const transformed = plugin.server?.transformComponentContext?.(ctx, vnode, componentCtx);
168
169
  if (transformed) componentCtx = transformed;
169
170
  }
170
- if (!parentCtx && appContext) provideAppContext(componentCtx, appContext);
171
- const prev = setCurrentInstance(componentCtx);
171
+ if (!parentCtx && appContext) (0, internals_exports.provideAppContext)(componentCtx, appContext);
172
+ const prev = (0, internals_exports.setCurrentInstance)(componentCtx);
172
173
  try {
173
174
  let renderFn = setup(componentCtx);
174
175
  if (renderFn && typeof renderFn.then === "function") renderFn = await renderFn;
@@ -232,7 +233,7 @@ async function* renderToChunks(element, ctx, parentCtx = null, appContext = null
232
233
  if (fallbackHtml) yield fallbackHtml;
233
234
  if (process.env.NODE_ENV !== "production") console.error(`Error rendering component ${componentName}:`, e);
234
235
  } finally {
235
- setCurrentInstance(prev || null);
236
+ (0, internals_exports.setCurrentInstance)(prev || null);
236
237
  }
237
238
  if (ctx._plugins) for (const plugin of ctx._plugins) {
238
239
  const transformed = plugin.server?.afterRenderComponent?.(id, vnode, "", ctx);
@@ -258,7 +259,7 @@ async function* renderToChunks(element, ctx, parentCtx = null, appContext = null
258
259
  def = propValue[0];
259
260
  value = propValue[1];
260
261
  } else {
261
- const builtIn = resolveBuiltInDirective(key.slice(4));
262
+ const builtIn = (0, internals_exports.resolveBuiltInDirective)(key.slice(4));
262
263
  if (builtIn) {
263
264
  def = builtIn;
264
265
  value = propValue;
@@ -350,7 +351,7 @@ function renderToStringSync(element, ctx, parentCtx, appContext, buf) {
350
351
  let componentCtx = {
351
352
  el: null,
352
353
  signal,
353
- props: createPropsAccessor(propsData),
354
+ props: (0, internals_exports.createPropsAccessor)(propsData),
354
355
  slots,
355
356
  emit: () => {},
356
357
  parent: parentCtx,
@@ -374,19 +375,19 @@ function renderToStringSync(element, ctx, parentCtx, appContext, buf) {
374
375
  const transformed = plugin.server?.transformComponentContext?.(ctx, vnode, componentCtx);
375
376
  if (transformed) componentCtx = transformed;
376
377
  }
377
- if (!parentCtx && appContext) provideAppContext(componentCtx, appContext);
378
- const prev = setCurrentInstance(componentCtx);
378
+ if (!parentCtx && appContext) (0, internals_exports.provideAppContext)(componentCtx, appContext);
379
+ const prev = (0, internals_exports.setCurrentInstance)(componentCtx);
379
380
  try {
380
381
  let renderFn = setup(componentCtx);
381
382
  if (renderFn && typeof renderFn.then === "function") {
382
383
  for (const p of ssrLoads) p.catch(() => {});
383
- setCurrentInstance(prev || null);
384
+ (0, internals_exports.setCurrentInstance)(prev || null);
384
385
  ctx.popComponent();
385
386
  return false;
386
387
  }
387
388
  if (ssrLoads.length > 0) {
388
389
  for (const p of ssrLoads) p.catch(() => {});
389
- setCurrentInstance(prev || null);
390
+ (0, internals_exports.setCurrentInstance)(prev || null);
390
391
  ctx.popComponent();
391
392
  return false;
392
393
  }
@@ -395,12 +396,12 @@ function renderToStringSync(element, ctx, parentCtx, appContext, buf) {
395
396
  if (result) {
396
397
  if (Array.isArray(result)) {
397
398
  for (const item of result) if (!renderToStringSync(item, ctx, componentCtx, appContext, buf)) {
398
- setCurrentInstance(prev || null);
399
+ (0, internals_exports.setCurrentInstance)(prev || null);
399
400
  ctx.popComponent();
400
401
  return false;
401
402
  }
402
403
  } else if (!renderToStringSync(result, ctx, componentCtx, appContext, buf)) {
403
- setCurrentInstance(prev || null);
404
+ (0, internals_exports.setCurrentInstance)(prev || null);
404
405
  ctx.popComponent();
405
406
  return false;
406
407
  }
@@ -413,7 +414,7 @@ function renderToStringSync(element, ctx, parentCtx, appContext, buf) {
413
414
  if (fallbackHtml === null || fallbackHtml === void 0) fallbackHtml = `<!--ssr-error:${id}-->`;
414
415
  if (fallbackHtml) buf.push(fallbackHtml);
415
416
  } finally {
416
- setCurrentInstance(prev || null);
417
+ (0, internals_exports.setCurrentInstance)(prev || null);
417
418
  }
418
419
  if (ctx._plugins) for (const plugin of ctx._plugins) {
419
420
  const transformed = plugin.server?.afterRenderComponent?.(id, vnode, "", ctx);
@@ -439,7 +440,7 @@ function renderToStringSync(element, ctx, parentCtx, appContext, buf) {
439
440
  def = propValue[0];
440
441
  value = propValue[1];
441
442
  } else {
442
- const builtIn = resolveBuiltInDirective(key.slice(4));
443
+ const builtIn = (0, internals_exports.resolveBuiltInDirective)(key.slice(4));
443
444
  if (builtIn) {
444
445
  def = builtIn;
445
446
  value = propValue;
@@ -826,4 +827,4 @@ async function renderToString(input, context) {
826
827
  initDirectivesForSSR();
827
828
  export { collectSSRHead as a, useHead as c, generateStreamingScript as d, renderVNodeToString as f, createSSR as i, escapeJsonForScript as l, initDirectivesForSSR as m, renderToStreamWithCallbacks as n, enableSSRHead as o, createSSRContext as p, renderToString as r, renderHeadToString as s, renderToStream as t, generateReplacementScript as u };
828
829
 
829
- //# sourceMappingURL=server-UBcHtkm-.js.map
830
+ //# sourceMappingURL=server-DQ68_nhq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-DQ68_nhq.js","names":[],"sources":["../src/builtin-ssr-directives.ts","../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","/**\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 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/**\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 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 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 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 { 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 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 return new ReadableStream<string>({\r\n async start(controller) {\r\n try {\r\n // Enable head collection\r\n enableSSRHead();\r\n\r\n // Phase 1: Render the main page (placeholders for async components)\r\n for await (const chunk of renderToChunks(element, ctx, null, appContext)) {\r\n controller.enqueue(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: 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) controller.enqueue(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 controller.enqueue(chunk);\r\n }\r\n\r\n // Phase 4: Signal streaming complete\r\n controller.enqueue(\r\n `<script>window.__SIGX_STREAMING_COMPLETE__=true;window.dispatchEvent(new Event('sigx:ready'));</script>`\r\n );\r\n\r\n controller.close();\r\n } catch (error) {\r\n controller.error(error);\r\n }\r\n }\r\n });\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 * - `renderToStreamWithCallbacks()` — callback-based streaming\r\n */\r\n\r\nimport type { JSXElement } from 'sigx';\r\nimport type { App } from 'sigx';\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 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, 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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"}
@@ -0,0 +1,37 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __exportAll = (all, symbols) => {
6
+ let target = {};
7
+ for (var name in all) __defProp(target, name, {
8
+ get: all[name],
9
+ enumerable: true
10
+ });
11
+ if (symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
12
+ return target;
13
+ };
14
+ var __copyProps = (to, from, except, desc) => {
15
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
16
+ key = keys[i];
17
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
18
+ get: ((k) => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ return to;
23
+ };
24
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
25
+ var internals_exports = /* @__PURE__ */ __exportAll({}, 1);
26
+ import * as import__sigx_runtime_core_internals from "@sigx/runtime-core/internals";
27
+ __reExport(internals_exports, import__sigx_runtime_core_internals);
28
+ import * as import__sigx_reactivity_internals from "@sigx/reactivity/internals";
29
+ __reExport(internals_exports, import__sigx_reactivity_internals);
30
+ import * as import__sigx_runtime_dom_internals from "@sigx/runtime-dom/internals";
31
+ __reExport(internals_exports, import__sigx_runtime_dom_internals);
32
+ function generateSignalKey(name, index) {
33
+ return name ?? `$${index}`;
34
+ }
35
+ export { internals_exports as n, generateSignalKey as t };
36
+
37
+ //# sourceMappingURL=types-D9iicsq6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-D9iicsq6.js","names":[],"sources":["../../sigx/dist/internals.js","../src/server/types.ts"],"sourcesContent":["export * from \"@sigx/runtime-core/internals\";\nexport * from \"@sigx/reactivity/internals\";\nexport * from \"@sigx/runtime-dom/internals\";\n","/**\r\n * Shared types for server rendering APIs.\r\n * \r\n * Kept separate to avoid circular imports between ssr.ts and render-api.ts.\r\n */\r\n\r\nimport type { Signal, PrimitiveSignal, Primitive } from 'sigx';\r\n\r\n/**\r\n * SSR-enhanced signal function type.\r\n * Extends the base signal() with an optional `name` parameter used as the\r\n * serialization key for hydration state transfer.\r\n *\r\n * Both `createTrackingSignal` (server/islands) and `createRestoringSignal` (client/hydration)\r\n * use this type and share the same key-generation contract via `generateSignalKey`.\r\n */\r\nexport type SSRSignalFn = {\r\n <T extends Primitive>(initial: T, name?: string): PrimitiveSignal<T>;\r\n <T extends object>(initial: T, name?: string): Signal<T>;\r\n};\r\n\r\n/**\r\n * Generate a stable key for a signal during SSR state tracking/restoration.\r\n *\r\n * Named signals use the provided name; unnamed signals use a positional key (`$0`, `$1`, ...).\r\n * Both server-side tracking (`createTrackingSignal`) and client-side restoration\r\n * (`createRestoringSignal`) MUST use this function to guarantee key parity.\r\n */\r\nexport function generateSignalKey(name: string | undefined, index: number): string {\r\n return name ?? `$${index}`;\r\n}\r\n\r\n/**\r\n * Streaming callbacks interface\r\n */\r\nexport interface StreamCallbacks {\r\n /** Called when the initial shell (synchronous content) is ready */\r\n onShellReady: (html: string) => void;\r\n /** Called for each async chunk (replacement scripts, hydration data) */\r\n onAsyncChunk: (chunk: string) => void;\r\n /** Called when all streaming is complete */\r\n onComplete: () => void;\r\n /** Called on error */\r\n onError: (error: Error) => void;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC4BA,SAAgB,kBAAkB,MAA0B,OAAuB;AAC/E,QAAO,QAAQ,IAAI"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/server-renderer",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Server-side rendering and client hydration for SigX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,12 +42,12 @@
42
42
  "url": "https://github.com/signalxjs/core/issues"
43
43
  },
44
44
  "dependencies": {
45
- "sigx": "^0.1.8"
45
+ "sigx": "^0.1.10"
46
46
  },
47
47
  "devDependencies": {
48
48
  "typescript": "^5.9.3",
49
49
  "vite": "^8.0.0-beta.9",
50
- "@sigx/vite": "^0.1.8"
50
+ "@sigx/vite": "^0.1.10"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "vite build && tsc --emitDeclarationOnly",
@@ -1 +0,0 @@
1
- {"version":3,"file":"client-ggDL-Wx2.js","names":[],"sources":["../src/client/hydrate-context.ts","../src/client/hydrate-component.ts","../src/client/hydrate-core.ts","../src/client/plugin.ts"],"sourcesContent":["/**\r\n * Hydration context and state management\r\n *\r\n * Manages server state restoration, app context tracking,\r\n * client plugin registration, and the SSR context extension for components.\r\n *\r\n * Strategy-specific concerns (island data, async hydration) are handled\r\n * by plugins registered via `registerClientPlugin()`.\r\n */\r\n\r\nimport {\r\n VNode,\r\n signal,\r\n Text,\r\n registerContextExtension\r\n} from 'sigx';\r\nimport type { AppContext } from 'sigx';\r\nimport type { SSRPlugin } from '../plugin';\r\nimport type { SSRSignalFn } from '../server/types';\r\nimport { generateSignalKey } from '../server/types';\r\n\r\n// ============= Internal Types =============\r\n\r\nexport interface InternalVNode extends VNode {\r\n _subTree?: VNode;\r\n _effect?: any;\r\n _componentProps?: any;\r\n _slots?: any;\r\n}\r\n\r\n// Re-export SSRSignalFn from shared types so existing consumers work\r\nexport type { SSRSignalFn };\r\n\r\n// ============= Module State =============\r\n\r\n// Track server state for async components being mounted after streaming\r\nlet _pendingServerState: Record<string, any> | null = null;\r\n\r\n// Track current app context during hydration for DI\r\n// Used for deferred hydration callbacks\r\nlet _currentAppContext: AppContext | null = null;\r\n\r\n// Registered client-side SSR plugins\r\nlet _clientPlugins: SSRPlugin[] = [];\r\n\r\n// ============= Client Plugin Registry =============\r\n\r\n/**\r\n * Register a client-side SSR plugin.\r\n * Plugins are called during hydration to intercept component processing,\r\n * skip default hydration walk, or run post-hydration logic.\r\n */\r\nexport function registerClientPlugin(plugin: SSRPlugin): void {\r\n _clientPlugins.push(plugin);\r\n}\r\n\r\n/**\r\n * Get all registered client-side plugins.\r\n */\r\nexport function getClientPlugins(): SSRPlugin[] {\r\n return _clientPlugins;\r\n}\r\n\r\n/**\r\n * Clear all registered client plugins (useful for testing).\r\n */\r\nexport function clearClientPlugins(): void {\r\n _clientPlugins = [];\r\n}\r\n\r\n// ============= State Accessors =============\r\n\r\n/**\r\n * Set server state that should be used for the next component mount.\r\n * Used internally when mounting async components after streaming.\r\n */\r\nexport function setPendingServerState(state: Record<string, any> | null): void {\r\n _pendingServerState = state;\r\n}\r\n\r\n/** Get the current app context for deferred hydration */\r\nexport function getCurrentAppContext(): AppContext | null {\r\n return _currentAppContext;\r\n}\r\n\r\n/** Set the current app context during hydration */\r\nexport function setCurrentAppContext(ctx: AppContext | null): void {\r\n _currentAppContext = ctx;\r\n}\r\n\r\n// ============= Signal Restoration =============\r\n\r\n/**\r\n * Creates a signal function that restores state from server-captured values.\r\n * Used during hydration of async components to avoid re-fetching data.\r\n * Supports both primitive and object signals.\r\n */\r\nexport function createRestoringSignal(serverState: Record<string, any>): SSRSignalFn {\r\n let signalIndex = 0;\r\n let hasWarnedPositional = false;\r\n\r\n return function restoringSignal(initial: any, name?: string): any {\r\n // Generate a stable key for this signal (must match server-side)\r\n const key = generateSignalKey(name, signalIndex++);\r\n\r\n // Dev warning: positional keys are fragile\r\n if (process.env.NODE_ENV !== 'production' && !name && !hasWarnedPositional) {\r\n hasWarnedPositional = true;\r\n console.warn(\r\n `[SSR Hydration] Signal restored without a name — using positional key \"${key}\". ` +\r\n `If signal declaration order differs between server and client builds, ` +\r\n `state will be silently mismatched. Use named signals: signal(value, \"name\")`\r\n );\r\n }\r\n\r\n // Check if we have server state for this signal\r\n if (key in serverState) {\r\n return signal(serverState[key]);\r\n }\r\n\r\n // No server state, use initial value\r\n return signal(initial as any);\r\n } as SSRSignalFn;\r\n}\r\n\r\n// ============= Element Normalization =============\r\n\r\n/**\r\n * Normalize any element to VNode\r\n */\r\nexport function normalizeElement(element: any): VNode | null {\r\n if (element == null || element === true || element === false) {\r\n return null;\r\n }\r\n\r\n if (typeof element === 'string' || typeof element === 'number') {\r\n return {\r\n type: Text,\r\n props: {},\r\n key: null,\r\n children: [],\r\n dom: null,\r\n text: element\r\n };\r\n }\r\n\r\n return element as VNode;\r\n}\r\n\r\n// ============= Context Extension Registration =============\r\n\r\n/**\r\n * Register the SSR context extension for all components.\r\n * This provides the `ssr` object with a no-op `load()` for client-side rendering.\r\n * Also handles server state restoration for async streamed components.\r\n */\r\nregisterContextExtension((ctx: any) => {\r\n // Check if we have pending server state (from async streaming)\r\n const serverState = _pendingServerState;\r\n if (serverState) {\r\n ctx._serverState = serverState;\r\n _pendingServerState = null; // Clear after use\r\n\r\n // Override signal function to use restoring signal\r\n ctx.signal = createRestoringSignal(serverState);\r\n\r\n // ssr.load() should be a no-op since we have restored state\r\n ctx.ssr = {\r\n load: (_fn: () => Promise<void>) => {\r\n // Skip - using restored server state\r\n },\r\n isServer: false,\r\n isHydrating: true\r\n };\r\n } else if (ctx._serverState) {\r\n // Already has server state (from hydration)\r\n ctx.ssr = {\r\n load: (_fn: () => Promise<void>) => {\r\n // Skip - using restored server state\r\n },\r\n isServer: false,\r\n isHydrating: true\r\n };\r\n } else {\r\n // Default client-side ssr helper - runs async functions for client-side navigation\r\n ctx.ssr = {\r\n load: (fn: () => Promise<void>) => {\r\n // On client-side navigation (not hydration), execute the async function\r\n fn().catch(err => console.error('[SSR] load error:', err));\r\n },\r\n isServer: false,\r\n isHydrating: false\r\n };\r\n }\r\n});\r\n","/**\r\n * Component hydration logic — strategy-agnostic\r\n *\r\n * Handles running component setup, creating reactive effects,\r\n * and restoring server state for hydrated components.\r\n * Does not depend on islands or any specific SSR strategy.\r\n */\r\n\r\nimport {\r\n VNode,\r\n ComponentSetupContext,\r\n setCurrentInstance,\r\n getCurrentInstance,\r\n signal,\r\n SlotsObject,\r\n createPropsAccessor,\r\n createSlots,\r\n normalizeSubTree,\r\n effect,\r\n patch,\r\n mount,\r\n patchProp,\r\n filterClientDirectives,\r\n createEmit,\r\n provideAppContext,\r\n isModel\r\n} from 'sigx';\r\nimport {\r\n InternalVNode,\r\n createRestoringSignal,\r\n getCurrentAppContext\r\n} from './hydrate-context';\r\nimport { hydrateNode } from './hydrate-core';\r\n\r\n/**\r\n * Minimal type for component factories used in hydration.\r\n * Compatible with ComponentFactory from runtime-core.\r\n */\r\nexport interface ComponentFactory {\r\n __setup: Function;\r\n __name?: string;\r\n __async?: boolean;\r\n}\r\n\r\n/**\r\n * Hydrate a component - run setup and create reactive effect\r\n *\r\n * With trailing markers, the structure is: <content><!--$c:id-->\r\n * - dom points to start of content\r\n * - trailingMarker (if provided) is the anchor at the end\r\n *\r\n * @param vnode - The VNode to hydrate\r\n * @param dom - The DOM node to start from (content starts here)\r\n * @param parent - The parent node\r\n * @param serverState - Optional state captured from server for async components\r\n * @param trailingMarker - Optional trailing marker comment (the component anchor)\r\n */\r\nexport function hydrateComponent(vnode: VNode, dom: Node | null, parent: Node, serverState?: Record<string, any>, trailingMarker?: Comment | null): Node | null {\r\n const componentFactory = vnode.type as unknown as ComponentFactory;\r\n const setup = componentFactory.__setup;\r\n const componentName = componentFactory.__name || 'Anonymous';\r\n\r\n // With trailing markers, find the marker if not provided\r\n let anchor: Comment | null = trailingMarker || null;\r\n let componentId: number | null = null;\r\n\r\n if (!anchor) {\r\n // Find trailing marker by traversing forward\r\n let current: Node | null = dom;\r\n while (current) {\r\n if (current.nodeType === Node.COMMENT_NODE) {\r\n const text = (current as Comment).data;\r\n if (text.startsWith('$c:')) {\r\n anchor = current as Comment;\r\n componentId = parseInt(text.slice(3), 10);\r\n break;\r\n }\r\n }\r\n current = current.nextSibling;\r\n }\r\n } else {\r\n // Extract component ID from provided marker\r\n const text = anchor.data;\r\n if (text.startsWith('$c:')) {\r\n componentId = parseInt(text.slice(3), 10);\r\n }\r\n }\r\n\r\n const internalVNode = vnode as InternalVNode;\r\n const initialProps = vnode.props || {};\r\n const { children, slots: slotsFromProps, $models: modelsData, ...propsData } = filterClientDirectives(initialProps);\r\n\r\n // Merge Model<T> objects directly into props for unified access: props.model.value\r\n const propsWithModels = { ...propsData };\r\n if (modelsData) {\r\n for (const modelKey in modelsData) {\r\n const modelValue = modelsData[modelKey];\r\n if (isModel(modelValue)) {\r\n propsWithModels[modelKey] = modelValue;\r\n }\r\n }\r\n }\r\n\r\n // Create reactive props\r\n const reactiveProps = signal(propsWithModels);\r\n internalVNode._componentProps = reactiveProps;\r\n\r\n // Create slots\r\n const slots = createSlots(children, slotsFromProps);\r\n internalVNode._slots = slots;\r\n\r\n const mountHooks: ((ctx: any) => void)[] = [];\r\n const unmountHooks: ((ctx: any) => void)[] = [];\r\n const createdHooks: (() => void)[] = [];\r\n const updatedHooks: (() => void)[] = [];\r\n\r\n const parentInstance = getCurrentInstance();\r\n\r\n // Use restoring signal when we have server state to restore\r\n const signalFn = serverState\r\n ? createRestoringSignal(serverState)\r\n : signal;\r\n\r\n // Create SSR helper for client-side\r\n // When hydrating with server state, ssr.load() is a no-op (data already restored)\r\n const hasServerState = !!serverState;\r\n const ssrHelper = {\r\n load(_fn: () => Promise<void>): void {\r\n // No-op on client when hydrating - signal state was restored from server\r\n },\r\n isServer: false,\r\n isHydrating: hasServerState\r\n };\r\n\r\n const componentCtx: ComponentSetupContext = {\r\n el: parent as HTMLElement,\r\n signal: signalFn as typeof signal,\r\n props: createPropsAccessor(reactiveProps),\r\n slots: slots,\r\n emit: createEmit(reactiveProps),\r\n parent: parentInstance,\r\n onMounted: (fn) => { mountHooks.push(fn); },\r\n onUnmounted: (fn) => { unmountHooks.push(fn); },\r\n onCreated: (fn) => { createdHooks.push(fn); },\r\n onUpdated: (fn) => { updatedHooks.push(fn); },\r\n expose: () => { },\r\n renderFn: null,\r\n update: () => { },\r\n ssr: ssrHelper,\r\n _serverState: serverState\r\n };\r\n\r\n // For ROOT component only (no parent), provide the AppContext\r\n if (!parentInstance && getCurrentAppContext()) {\r\n provideAppContext(componentCtx, getCurrentAppContext()!);\r\n }\r\n\r\n const prev = setCurrentInstance(componentCtx);\r\n let renderFn: (() => any) | undefined;\r\n\r\n try {\r\n renderFn = setup(componentCtx);\r\n } catch (err) {\r\n if (process.env.NODE_ENV !== 'production') {\r\n console.error(`Error hydrating component ${componentName}:`, err);\r\n }\r\n } finally {\r\n setCurrentInstance(prev);\r\n }\r\n\r\n // Track where the component's DOM starts\r\n let endDom: Node | null = dom;\r\n\r\n if (renderFn) {\r\n componentCtx.renderFn = renderFn;\r\n let isFirstRender = true;\r\n\r\n // Create reactive effect - on first run, hydrate; on subsequent, use render()\r\n const componentEffect = effect(() => {\r\n const prevInstance = setCurrentInstance(componentCtx);\r\n try {\r\n const subTreeResult = componentCtx.renderFn!();\r\n const prevSubTree = internalVNode._subTree;\r\n\r\n // Handle null/undefined renders (e.g., conditional components like Modal)\r\n if (subTreeResult == null) {\r\n if (isFirstRender) {\r\n // First render returned null - SSR didn't render content, nothing to hydrate\r\n isFirstRender = false;\r\n } else if (prevSubTree && prevSubTree.dom) {\r\n // Had content before, now returning null - unmount the previous subtree\r\n const patchContainer = prevSubTree.dom.parentNode as Element || parent;\r\n const emptyNode = normalizeSubTree(null);\r\n patch(prevSubTree, emptyNode, patchContainer);\r\n internalVNode._subTree = emptyNode;\r\n }\r\n return;\r\n }\r\n\r\n const subTree = normalizeSubTree(subTreeResult);\r\n\r\n if (isFirstRender) {\r\n // First render - hydrate against existing DOM\r\n isFirstRender = false;\r\n endDom = hydrateNode(subTree, dom, parent);\r\n internalVNode._subTree = subTree;\r\n } else {\r\n // Subsequent renders - use patch directly like runtime-core does\r\n if (prevSubTree) {\r\n const patchContainer = prevSubTree.dom?.parentNode as Element || parent;\r\n patch(prevSubTree, subTree, patchContainer);\r\n } else {\r\n // No previous subtree - mount fresh using the component's anchor\r\n mount(subTree, parent as Element, anchor || null);\r\n }\r\n internalVNode._subTree = subTree;\r\n }\r\n } finally {\r\n setCurrentInstance(prevInstance);\r\n }\r\n });\r\n\r\n internalVNode._effect = componentEffect;\r\n componentCtx.update = () => componentEffect();\r\n }\r\n\r\n // Use trailing anchor comment as the component's dom reference\r\n vnode.dom = anchor || endDom;\r\n\r\n // Run mount hooks\r\n const mountCtx = { el: parent as Element };\r\n createdHooks.forEach(hook => hook());\r\n mountHooks.forEach(hook => hook(mountCtx));\r\n\r\n // Store cleanup\r\n vnode.cleanup = () => {\r\n unmountHooks.forEach(hook => hook(mountCtx));\r\n };\r\n\r\n // With trailing markers, the anchor IS the end - return next sibling\r\n return anchor ? anchor.nextSibling : endDom;\r\n}\r\n","/**\r\n * Core hydration logic — strategy-agnostic\r\n *\r\n * Walks existing server-rendered DOM and attaches event handlers,\r\n * creates reactive effects, and delegates components to the component hydrator.\r\n *\r\n * Plugins registered via `registerClientPlugin()` can intercept component\r\n * hydration (e.g., for deferred/island-based hydration strategies).\r\n */\r\n\r\nimport {\r\n VNode,\r\n Fragment,\r\n Text,\r\n isComponent,\r\n patchProp,\r\n patchDirective,\r\n onElementMounted\r\n} from 'sigx';\r\nimport type { AppContext } from 'sigx';\r\nimport { normalizeElement, setCurrentAppContext, getCurrentAppContext, getClientPlugins } from './hydrate-context';\r\nimport { hydrateComponent } from './hydrate-component';\r\n\r\n/**\r\n * Hydrate a server-rendered app.\r\n *\r\n * This walks the existing DOM to attach event handlers, runs component\r\n * setup functions to establish reactivity, then uses runtime-dom for updates.\r\n *\r\n * Registered client plugins are called at appropriate points:\r\n * - `beforeHydrate`: before the DOM walk (return false to skip it entirely)\r\n * - `hydrateComponent`: for each component (return { next } to handle it)\r\n * - `afterHydrate`: after the DOM walk completes\r\n *\r\n * @param element - The root element/VNode to hydrate\r\n * @param container - The DOM container with SSR content\r\n * @param appContext - The app context for DI (provides, etc.)\r\n */\r\nexport function hydrate(element: any, container: Element, appContext?: AppContext): void {\r\n const vnode = normalizeElement(element);\r\n if (!vnode) return;\r\n\r\n // Store app context for component hydration (DI needs this)\r\n setCurrentAppContext(appContext ?? null);\r\n\r\n const plugins = getClientPlugins();\r\n\r\n // Let plugins intercept before the DOM walk\r\n for (const plugin of plugins) {\r\n const result = plugin.client?.beforeHydrate?.(container);\r\n if (result === false) {\r\n // Plugin opted out of the default DOM walk (e.g., resumable SSR)\r\n (container as any)._vnode = vnode;\r\n return;\r\n }\r\n }\r\n\r\n // Walk existing DOM, attach handlers, and mount components\r\n hydrateNode(vnode, container.firstChild, container);\r\n\r\n // Post-hydration hooks\r\n for (const plugin of plugins) {\r\n plugin.client?.afterHydrate?.(container);\r\n }\r\n\r\n // Store vnode on container for potential future use\r\n (container as any)._vnode = vnode;\r\n}\r\n\r\n/**\r\n * Hydrate a VNode against existing DOM\r\n * This only attaches event handlers and refs - no DOM creation\r\n */\r\nexport function hydrateNode(vnode: VNode, dom: Node | null, parent: Node): Node | null {\r\n if (!vnode) return dom;\r\n\r\n // Skip comment nodes (<!--t--> text separators and <!--$c:N--> component markers).\r\n // Component markers are only meaningful when the VNode itself is a component —\r\n // for element/text/fragment VNodes, all comments are just SSR artifacts to skip past.\r\n const isComponentVNode = isComponent(vnode.type);\r\n const isTextVNode = vnode.type === Text;\r\n while (dom && dom.nodeType === Node.COMMENT_NODE) {\r\n if (isComponentVNode) {\r\n const commentText = (dom as Comment).data;\r\n // Stop at component markers — the component hydrator needs them for boundaries\r\n if (commentText.startsWith('$c:')) {\r\n break;\r\n }\r\n }\r\n // When a text VNode hits a <!--t--> separator, the SSR may have omitted the\r\n // preceding empty text (e.g. \"\" + \" · Logout\" → <!--t--> · Logout).\r\n // Replace the comment with an empty text node so this VNode can attach to it,\r\n // preserving the boundary for the next text VNode.\r\n if (isTextVNode && (dom as Comment).data === 't') {\r\n const emptyText = document.createTextNode('');\r\n parent.replaceChild(emptyText, dom);\r\n dom = emptyText;\r\n break;\r\n }\r\n dom = dom.nextSibling;\r\n }\r\n\r\n if (vnode.type === Text) {\r\n if (dom && dom.nodeType === Node.TEXT_NODE) {\r\n vnode.dom = dom;\r\n return dom.nextSibling;\r\n }\r\n // Hydration mismatch: expected a text node but got something else.\r\n // Create a fresh text node and insert it so the VNode has a valid DOM ref.\r\n const textNode = document.createTextNode(String(vnode.text ?? ''));\r\n if (dom) {\r\n parent.insertBefore(textNode, dom);\r\n } else {\r\n parent.appendChild(textNode);\r\n }\r\n vnode.dom = textNode;\r\n return dom;\r\n }\r\n\r\n if (vnode.type === Fragment) {\r\n let current = dom;\r\n for (const child of vnode.children) {\r\n current = hydrateNode(child, current, parent);\r\n }\r\n return current;\r\n }\r\n\r\n if (isComponent(vnode.type)) {\r\n // Let plugins intercept component hydration (e.g., islands scheduling)\r\n const plugins = getClientPlugins();\r\n for (const plugin of plugins) {\r\n const result = plugin.client?.hydrateComponent?.(vnode, dom, parent);\r\n if (result !== undefined) {\r\n // Plugin handled this component — return the next DOM node\r\n return result;\r\n }\r\n }\r\n\r\n // No plugin handled it — hydrate immediately\r\n return hydrateComponent(vnode, dom, parent);\r\n }\r\n\r\n if (typeof vnode.type === 'string') {\r\n if (!dom || dom.nodeType !== Node.ELEMENT_NODE) {\r\n if (process.env.NODE_ENV !== 'production') {\r\n console.warn('[Hydrate] Expected element but got:', dom);\r\n }\r\n return dom;\r\n }\r\n\r\n const el = dom as Element;\r\n vnode.dom = el;\r\n\r\n // Attach event handlers and props using patchProp from runtime-dom\r\n if (vnode.props) {\r\n let hasDirectives = false;\r\n for (const key in vnode.props) {\r\n if (key === 'children' || key === 'key') continue;\r\n if (key.startsWith('client:')) continue;\r\n\r\n if (key.charCodeAt(0) === 117 /* 'u' */ && key.startsWith('use:')) {\r\n // Route use:* directive props through patchDirective\r\n patchDirective(el, key.slice(4), null, vnode.props[key], getCurrentAppContext());\r\n hasDirectives = true;\r\n } else {\r\n // Use patchProp for consistent prop handling (events, refs, etc.)\r\n patchProp(el, key, null, vnode.props[key]);\r\n }\r\n }\r\n\r\n // Fire mounted hooks for directives (element is already in DOM during hydration)\r\n if (hasDirectives) {\r\n onElementMounted(el);\r\n }\r\n\r\n // Handle ref - patchProp skips refs, so we handle them here\r\n if (vnode.props.ref) {\r\n if (typeof vnode.props.ref === 'function') {\r\n vnode.props.ref(el);\r\n } else if (typeof vnode.props.ref === 'object') {\r\n vnode.props.ref.current = el;\r\n }\r\n }\r\n }\r\n\r\n // Hydrate children\r\n let childDom: Node | null = el.firstChild;\r\n for (const child of vnode.children) {\r\n childDom = hydrateNode(child, childDom, el);\r\n }\r\n\r\n // Fix select value after children are hydrated\r\n if (vnode.type === 'select' && vnode.props) {\r\n fixSelectValue(el as HTMLElement, vnode.props);\r\n }\r\n\r\n return el.nextSibling;\r\n }\r\n\r\n return dom;\r\n}\r\n\r\n/**\r\n * Fix select element value after hydrating children.\r\n * This is needed because <select>.value only works after <option> children exist in DOM.\r\n */\r\nfunction fixSelectValue(dom: HTMLElement, props: any) {\r\n if (dom.tagName === 'SELECT' && 'value' in props) {\r\n const val = props.value;\r\n if ((dom as HTMLSelectElement).multiple) {\r\n const options = (dom as HTMLSelectElement).options;\r\n const valArray = Array.isArray(val) ? val : [val];\r\n for (let i = 0; i < options.length; i++) {\r\n options[i].selected = valArray.includes(options[i].value);\r\n }\r\n } else {\r\n (dom as HTMLSelectElement).value = String(val);\r\n }\r\n }\r\n}\r\n","/**\r\n * SSR Client Plugin\r\n * \r\n * Provides app.hydrate() method for client-side hydration of server-rendered HTML.\r\n * This plugin follows the same pattern as the router plugin.\r\n */\r\n\r\nimport type { Plugin, App, AppContext } from '@sigx/runtime-core';\r\nimport { render } from 'sigx';\r\nimport { hydrate as hydrateImpl } from './hydrate-core';\r\n\r\n// ============================================================================\r\n// Type Augmentation\r\n// ============================================================================\r\n\r\n/**\r\n * Hydrate function signature - matches MountFn pattern\r\n */\r\nexport type HydrateFn<TContainer = any> = (\r\n element: any,\r\n container: TContainer,\r\n appContext: AppContext\r\n) => (() => void) | void;\r\n\r\ndeclare module '@sigx/runtime-core' {\r\n interface App<TContainer = any> {\r\n /**\r\n * Hydrate the app from server-rendered HTML.\r\n * \r\n * Unlike mount() which creates new DOM, hydrate() attaches to existing\r\n * server-rendered DOM, adding event handlers and establishing reactivity.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from 'sigx';\r\n * import { ssrClientPlugin } from '@sigx/server-renderer/client';\r\n * \r\n * const app = defineApp(<App />);\r\n * app.use(router)\r\n * .use(ssrClientPlugin)\r\n * .hydrate(document.getElementById('app')!);\r\n * ```\r\n */\r\n hydrate(container: TContainer): App<TContainer>;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Plugin Implementation\r\n// ============================================================================\r\n\r\n/**\r\n * SSR Client Plugin\r\n * \r\n * Adds the hydrate() method to the app instance for client-side hydration.\r\n * Also registers the SSR context extension for all components.\r\n * \r\n * @example\r\n * ```tsx\r\n * import { defineApp } from 'sigx';\r\n * import { ssrClientPlugin } from '@sigx/server-renderer/client';\r\n * \r\n * const app = defineApp(<App />);\r\n * app.use(ssrClientPlugin)\r\n * .use(router)\r\n * .hydrate('#app');\r\n * ```\r\n */\r\nexport const ssrClientPlugin: Plugin = {\r\n name: '@sigx/server-renderer/client',\r\n\r\n install(app: App) {\r\n // Add hydrate method to the app instance\r\n (app as any).hydrate = function(container: Element | string): App {\r\n // Resolve container if string selector\r\n const resolvedContainer = typeof container === 'string'\r\n ? document.querySelector(container)\r\n : container;\r\n\r\n if (!resolvedContainer) {\r\n throw new Error(\r\n `[ssrClientPlugin] Cannot find container: ${container}. ` +\r\n 'Make sure the element exists in the DOM before calling hydrate().'\r\n );\r\n }\r\n\r\n // Get the root component from the app\r\n const rootComponent = (app as any)._rootComponent;\r\n \r\n if (!rootComponent) {\r\n throw new Error(\r\n '[ssrClientPlugin] No root component found on app. ' +\r\n 'Make sure you created the app with defineApp(<Component />).'\r\n );\r\n }\r\n\r\n // Check if there's actual SSR content to hydrate\r\n // If container is empty or only has comments, fall back to client-side render\r\n const hasSSRContent = resolvedContainer.firstElementChild !== null ||\r\n (resolvedContainer.firstChild !== null && \r\n resolvedContainer.firstChild.nodeType !== Node.COMMENT_NODE);\r\n\r\n // Get app context for passing to render (needed for inject() to work)\r\n const appContext = (app as any)._context;\r\n\r\n if (hasSSRContent) {\r\n // Perform hydration with app context for DI\r\n hydrateImpl(rootComponent, resolvedContainer, appContext);\r\n } else {\r\n // No SSR content - fall back to client-side render (dev mode)\r\n render(rootComponent, resolvedContainer, appContext);\r\n }\r\n\r\n // Store container on the vnode for potential unmount\r\n (resolvedContainer as any)._app = app;\r\n\r\n return app;\r\n };\r\n }\r\n};\r\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"server-UBcHtkm-.js","names":[],"sources":["../src/builtin-ssr-directives.ts","../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","/**\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 JSXElement,\r\n ComponentSetupContext,\r\n setCurrentInstance,\r\n signal,\r\n Text,\r\n SlotsObject,\r\n isComponent,\r\n createPropsAccessor,\r\n provideAppContext,\r\n isDirective\r\n} from 'sigx';\r\nimport type { DirectiveDefinition } from 'sigx';\r\nimport { resolveBuiltInDirective } from '@sigx/runtime-dom';\r\nimport type { AppContext } from 'sigx';\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/**\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 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 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 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 { 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 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 return new ReadableStream<string>({\r\n async start(controller) {\r\n try {\r\n // Enable head collection\r\n enableSSRHead();\r\n\r\n // Phase 1: Render the main page (placeholders for async components)\r\n for await (const chunk of renderToChunks(element, ctx, null, appContext)) {\r\n controller.enqueue(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: 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) controller.enqueue(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 controller.enqueue(chunk);\r\n }\r\n\r\n // Phase 4: Signal streaming complete\r\n controller.enqueue(\r\n `<script>window.__SIGX_STREAMING_COMPLETE__=true;window.dispatchEvent(new Event('sigx:ready'));</script>`\r\n );\r\n\r\n controller.close();\r\n } catch (error) {\r\n controller.error(error);\r\n }\r\n }\r\n });\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 * - `renderToStreamWithCallbacks()` — callback-based streaming\r\n */\r\n\r\nimport type { JSXElement } from 'sigx';\r\nimport type { App } from 'sigx';\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 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, 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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"}
@@ -1,6 +0,0 @@
1
- function generateSignalKey(name, index) {
2
- return name ?? `$${index}`;
3
- }
4
- export { generateSignalKey as t };
5
-
6
- //# sourceMappingURL=types-B4Rf1Xot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-B4Rf1Xot.js","names":[],"sources":["../src/server/types.ts"],"sourcesContent":["/**\r\n * Shared types for server rendering APIs.\r\n * \r\n * Kept separate to avoid circular imports between ssr.ts and render-api.ts.\r\n */\r\n\r\nimport type { Signal, PrimitiveSignal, Primitive } from 'sigx';\r\n\r\n/**\r\n * SSR-enhanced signal function type.\r\n * Extends the base signal() with an optional `name` parameter used as the\r\n * serialization key for hydration state transfer.\r\n *\r\n * Both `createTrackingSignal` (server/islands) and `createRestoringSignal` (client/hydration)\r\n * use this type and share the same key-generation contract via `generateSignalKey`.\r\n */\r\nexport type SSRSignalFn = {\r\n <T extends Primitive>(initial: T, name?: string): PrimitiveSignal<T>;\r\n <T extends object>(initial: T, name?: string): Signal<T>;\r\n};\r\n\r\n/**\r\n * Generate a stable key for a signal during SSR state tracking/restoration.\r\n *\r\n * Named signals use the provided name; unnamed signals use a positional key (`$0`, `$1`, ...).\r\n * Both server-side tracking (`createTrackingSignal`) and client-side restoration\r\n * (`createRestoringSignal`) MUST use this function to guarantee key parity.\r\n */\r\nexport function generateSignalKey(name: string | undefined, index: number): string {\r\n return name ?? `$${index}`;\r\n}\r\n\r\n/**\r\n * Streaming callbacks interface\r\n */\r\nexport interface StreamCallbacks {\r\n /** Called when the initial shell (synchronous content) is ready */\r\n onShellReady: (html: string) => void;\r\n /** Called for each async chunk (replacement scripts, hydration data) */\r\n onAsyncChunk: (chunk: string) => void;\r\n /** Called when all streaming is complete */\r\n onComplete: () => void;\r\n /** Called on error */\r\n onError: (error: Error) => void;\r\n}\r\n"],"mappings":"AA4BA,SAAgB,kBAAkB,MAA0B,OAAuB;AAC/E,QAAO,QAAQ,IAAI"}