@sigx/server-renderer 0.1.10 → 0.1.12

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,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
+ {"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,CAmM9J"}
@@ -1,3 +1,3 @@
1
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
+ 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-VBbiRRNl.js";
3
3
  export { clearClientPlugins, createRestoringSignal, getClientPlugins, getCurrentAppContext, hydrate, hydrateComponent, hydrateNode, registerClientPlugin, setCurrentAppContext, setPendingServerState, ssrClientPlugin };
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/client/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAO,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQlE;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,UAAU,GAAG,GAAG,IAAI,CACtC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,UAAU,KACrB,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzB,OAAO,QAAQ,oBAAoB,CAAC;IAChC,UAAU,GAAG,CAAC,UAAU,GAAG,GAAG;QAC1B;;;;;;;;;;;;;;;;WAgBG;QACH,OAAO,CAAC,SAAS,EAAE,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;KACnD;CACJ;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,EAAE,MAmD7B,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/client/plugin.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAO,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQlE;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,UAAU,GAAG,GAAG,IAAI,CACtC,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,UAAU,KACrB,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzB,OAAO,QAAQ,oBAAoB,CAAC,CAAC;IACjC,UAAU,GAAG,CAAC,UAAU,GAAG,GAAG;QAC1B;;;;;;;;;;;;;;;;WAgBG;QACH,OAAO,CAAC,SAAS,EAAE,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;KACnD;CACJ;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,eAAe,EAAE,MAmD7B,CAAC"}
@@ -159,8 +159,9 @@ function hydrateComponent(vnode, dom, parent, serverState, trailingMarker) {
159
159
  const subTreeResult = componentCtx.renderFn();
160
160
  const prevSubTree = internalVNode._subTree;
161
161
  if (subTreeResult == null) {
162
- if (isFirstRender) isFirstRender = false;
163
- else if (prevSubTree && prevSubTree.dom) {
162
+ if (isFirstRender) {
163
+ if (!(dom != null && anchor != null && dom !== anchor)) isFirstRender = false;
164
+ } else if (prevSubTree && prevSubTree.dom) {
164
165
  const patchContainer = prevSubTree.dom.parentNode || parent;
165
166
  const emptyNode = (0, internals_exports.normalizeSubTree)(null);
166
167
  (0, internals_exports.patch)(prevSubTree, emptyNode, patchContainer);
@@ -306,4 +307,4 @@ const ssrClientPlugin = {
306
307
  };
307
308
  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
309
 
309
- //# sourceMappingURL=client-CRfOEHiT.js.map
310
+ //# sourceMappingURL=client-VBbiRRNl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-VBbiRRNl.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 // Check if there's SSR content in the DOM (between dom and anchor).\r\n // This happens when a lazy() component returns null on first render\r\n // (chunk not loaded yet) but the server rendered the full content.\r\n // In that case, keep isFirstRender=true so the next render (after the\r\n // lazy component resolves) will hydrate against the existing SSR DOM\r\n // instead of mounting a duplicate.\r\n const hasSSRContent = dom != null && anchor != null && dom !== anchor;\r\n if (!hasSSRContent) {\r\n // Truly null first render — SSR also rendered nothing\r\n isFirstRender = false;\r\n }\r\n // If hasSSRContent, leave isFirstRender=true and SSR DOM visible.\r\n // The component will hydrate when it re-renders with real content.\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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"client-directives.d.ts","sourceRoot":"","sources":["../src/client-directives.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CACjC;AAGD,OAAO,QAAQ,oBAAoB,CAAC;IAEhC,UAAU,qBAAqB;QAC3B;;;WAGG;QACH,GAAG,EAAE,SAAS,CAAC;QAEf;;WAEG;QACH,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAE5B;;WAEG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAEnC;;WAEG;QACH,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;KAC/B;CACJ"}
1
+ {"version":3,"file":"client-directives.d.ts","sourceRoot":"","sources":["../src/client-directives.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CACjC;AAGD,OAAO,QAAQ,oBAAoB,CAAC,CAAC;IAEjC,UAAU,qBAAqB;QAC3B;;;WAGG;QACH,GAAG,EAAE,SAAS,CAAC;QAEf;;WAEG;QACH,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAE5B;;WAEG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAEnC;;WAEG;QACH,SAAS,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;KAC/B;CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"directive-ssr-types.d.ts","sourceRoot":"","sources":["../src/directive-ssr-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,QAAQ,oBAAoB,CAAC;IAChC,UAAU,6BAA6B,CAAC,CAAC;QACrC;;;;;WAKG;QACH,WAAW,CAAC,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;KAC1E;CACJ"}
1
+ {"version":3,"file":"directive-ssr-types.d.ts","sourceRoot":"","sources":["../src/directive-ssr-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,QAAQ,oBAAoB,CAAC,CAAC;IACjC,UAAU,6BAA6B,CAAC,CAAC;QACrC;;;;;WAKG;QACH,WAAW,CAAC,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC;KAC1E;CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../src/head.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,MAAM,WAAW,QAAQ;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,QAAQ;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,UAAU;IACvB,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB;IAChB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;IAClB,gBAAgB;IAChB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;IAClB,kBAAkB;IAClB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,8BAA8B;IAC9B,SAAS,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC/E,sBAAsB;IACtB,SAAS,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;CACrE;AAQD;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,UAAU,EAAE,CAK7C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAmFhE;AA0FD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAehD"}
1
+ {"version":3,"file":"head.d.ts","sourceRoot":"","sources":["../src/head.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,MAAM,WAAW,QAAQ;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,QAAQ;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,UAAU;IACvB,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB;IAChB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;IAClB,gBAAgB;IAChB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC;IAClB,kBAAkB;IAClB,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC;IACtB,8BAA8B;IAC9B,SAAS,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC/E,sBAAsB;IACtB,SAAS,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;CACrE;AAQD;;;GAGG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,UAAU,EAAE,CAK7C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAmFhE;AA0FD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAehD"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as generateSignalKey } from "./types-D9iicsq6.js";
2
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";
3
+ import { t as ssrClientPlugin } from "./client-VBbiRRNl.js";
4
4
  initDirectivesForSSR();
5
5
  export { collectSSRHead, createSSR, createSSRContext, enableSSRHead, generateSignalKey, renderHeadToString, renderToStream, renderToString, renderVNodeToString, ssrClientPlugin, useHead };
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/server-renderer",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Server-side rendering and client hydration for SigX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,15 +42,15 @@
42
42
  "url": "https://github.com/signalxjs/core/issues"
43
43
  },
44
44
  "dependencies": {
45
- "sigx": "^0.1.10"
45
+ "sigx": "^0.1.12"
46
46
  },
47
47
  "devDependencies": {
48
48
  "typescript": "^5.9.3",
49
49
  "vite": "^8.0.0-beta.9",
50
- "@sigx/vite": "^0.1.10"
50
+ "@sigx/vite": "^0.1.12"
51
51
  },
52
52
  "scripts": {
53
- "build": "vite build && tsc --emitDeclarationOnly",
53
+ "build": "vite build && tsgo --emitDeclarationOnly",
54
54
  "dev": "vite build --watch"
55
55
  }
56
56
  }
@@ -1 +0,0 @@
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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"}