@pyreon/runtime-server 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src/index.ts","uid":"ab8768fb-1"}]}],"isRoot":true},"nodeParts":{"ab8768fb-1":{"renderedLength":10801,"gzipLength":3492,"brotliLength":0,"metaUid":"ab8768fb-0"}},"nodeMetas":{"ab8768fb-0":{"id":"/src/index.ts","moduleParts":{"index.js":"ab8768fb-1"},"imported":[{"uid":"ab8768fb-2"},{"uid":"ab8768fb-3"}],"importedBy":[],"isEntry":true},"ab8768fb-2":{"id":"node:async_hooks","moduleParts":{},"imported":[],"importedBy":[{"uid":"ab8768fb-0"}]},"ab8768fb-3":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"ab8768fb-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src/index.ts","uid":"8b5feff8-1"}]}],"isRoot":true},"nodeParts":{"8b5feff8-1":{"renderedLength":10969,"gzipLength":3533,"brotliLength":0,"metaUid":"8b5feff8-0"}},"nodeMetas":{"8b5feff8-0":{"id":"/src/index.ts","moduleParts":{"index.js":"8b5feff8-1"},"imported":[{"uid":"8b5feff8-2"},{"uid":"8b5feff8-3"}],"importedBy":[],"isEntry":true},"8b5feff8-2":{"id":"node:async_hooks","moduleParts":{},"imported":[],"importedBy":[{"uid":"8b5feff8-0"}]},"8b5feff8-3":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"8b5feff8-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
package/lib/index.js CHANGED
@@ -111,8 +111,9 @@ async function streamComponentNode(vnode, enqueue) {
111
111
  async function streamElementNode(vnode, enqueue) {
112
112
  const tag = vnode.type;
113
113
  let open = `<${tag}`;
114
- for (const [key, value] of Object.entries(vnode.props)) {
115
- const attr = renderProp(key, value);
114
+ const props = vnode.props;
115
+ for (const key in props) {
116
+ const attr = renderProp(key, props[key]);
116
117
  if (attr) open += ` ${attr}`;
117
118
  }
118
119
  if (isVoidElement(tag)) {
@@ -177,18 +178,27 @@ async function renderNode(node) {
177
178
  if (node == null || node === false) return "";
178
179
  if (typeof node === "string") return escapeHtml(node);
179
180
  if (typeof node === "number" || typeof node === "boolean") return String(node);
180
- if (Array.isArray(node)) return (await Promise.all(node.map((n) => renderNode(n)))).join("");
181
+ if (Array.isArray(node)) {
182
+ let html = "";
183
+ for (const child of node) html += await renderNode(child);
184
+ return html;
185
+ }
181
186
  const vnode = node;
182
187
  if (vnode.type === Fragment) return renderChildren(vnode.children);
183
188
  if (vnode.type === ForSymbol) {
184
189
  const { each, children } = vnode.props;
185
- return `<!--pyreon-for-->${(await Promise.all(each().map((item) => renderNode(children(item))))).join("")}<!--/pyreon-for-->`;
190
+ let forHtml = "<!--pyreon-for-->";
191
+ for (const item of each()) forHtml += await renderNode(children(item));
192
+ forHtml += "<!--/pyreon-for-->";
193
+ return forHtml;
186
194
  }
187
195
  if (typeof vnode.type === "function") return renderComponent(vnode);
188
196
  return renderElement(vnode);
189
197
  }
190
198
  async function renderChildren(children) {
191
- return (await Promise.all(children.map((c) => renderNode(c)))).join("");
199
+ let html = "";
200
+ for (const child of children) html += await renderNode(child);
201
+ return html;
192
202
  }
193
203
  async function renderComponent(vnode) {
194
204
  const { vnode: output } = runWithHooks(vnode.type, mergeChildrenIntoProps(vnode));
@@ -203,8 +213,9 @@ async function renderComponent(vnode) {
203
213
  async function renderElement(vnode) {
204
214
  const tag = vnode.type;
205
215
  let html = `<${tag}`;
206
- for (const [key, value] of Object.entries(vnode.props)) {
207
- const attr = renderProp(key, value);
216
+ const props = vnode.props;
217
+ for (const key in props) {
218
+ const attr = renderProp(key, props[key]);
208
219
  if (attr) html += ` ${attr}`;
209
220
  }
210
221
  if (isVoidElement(tag)) {
@@ -297,7 +308,9 @@ const ESCAPE_MAP = {
297
308
  "\"": "&quot;",
298
309
  "'": "&#39;"
299
310
  };
311
+ const NEEDS_ESCAPE_RE = /[&<>"']/;
300
312
  function escapeHtml(str) {
313
+ if (!NEEDS_ESCAPE_RE.test(str)) return str;
301
314
  return str.replace(/[&<>"']/g, (c) => ESCAPE_MAP[c] ?? c);
302
315
  }
303
316
  /**
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @pyreon/runtime-server — SSR/SSG renderer for Pyreon.\n *\n * Walks a VNode tree and produces HTML strings.\n * Signal accessors (reactive getters `() => value`) are called synchronously\n * to snapshot their current value — no effects are set up on the server.\n *\n * Async components (`async function Component()`) are fully supported:\n * renderToString will await them before continuing the tree walk.\n *\n * API:\n * renderToString(vnode) → Promise<string>\n * renderToStream(vnode) → ReadableStream<string>\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\"\nimport type { ComponentFn, ForProps, VNode, VNodeChild } from \"@pyreon/core\"\nimport { ForSymbol, Fragment, runWithHooks, Suspense, setContextStackProvider } from \"@pyreon/core\"\n\n// ─── Streaming Suspense context ───────────────────────────────────────────────\n// Tracks in-flight async Suspense boundary resolutions within a single stream.\n\ninterface StreamCtx {\n pending: Promise<void>[]\n nextId: () => number\n mainEnqueue: (s: string) => void\n}\n\nconst _streamCtxAls = new AsyncLocalStorage<StreamCtx>()\n\n// ─── Concurrent SSR context isolation ────────────────────────────────────────\n// Each renderToString call runs in its own ALS store (a fresh empty stack[]).\n// Concurrent requests never share context frames.\n\nconst _contextAls = new AsyncLocalStorage<Map<symbol, unknown>[]>()\nconst _fallbackStack: Map<symbol, unknown>[] = []\n\nsetContextStackProvider(() => _contextAls.getStore() ?? _fallbackStack)\n\n// ─── Store isolation (optional) ───────────────────────────────────────────────\n// A second ALS isolates store registries between concurrent requests.\n// Activated only when the user calls configureStoreIsolation().\n\nconst _storeAls = new AsyncLocalStorage<Map<string, unknown>>()\nlet _storeIsolationActive = false\n\n/**\n * Wire up per-request store isolation.\n * Call once at server startup, passing a `setStoreRegistryProvider` function.\n *\n * @example\n * import { configureStoreIsolation } from \"@pyreon/runtime-server\"\n * configureStoreIsolation(setStoreRegistryProvider)\n */\nexport function configureStoreIsolation(\n setStoreRegistryProvider: (fn: () => Map<string, unknown>) => void,\n): void {\n setStoreRegistryProvider(() => _storeAls.getStore() ?? new Map())\n _storeIsolationActive = true\n}\n\n/** Wrap a function call in a fresh store registry (no-op if isolation not configured). */\nfunction withStoreContext<T>(fn: () => T): T {\n if (!_storeIsolationActive) return fn()\n return _storeAls.run(new Map(), fn)\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/** Render a VNode tree to an HTML string. Supports async component functions. */\nexport async function renderToString(root: VNode | null): Promise<string> {\n if (root === null) return \"\"\n // Each call gets a fresh isolated context stack and (optionally) store registry\n return withStoreContext(() => _contextAls.run([], () => renderNode(root)))\n}\n\n/**\n * Run an async function with a fresh, isolated context stack and store registry.\n * Useful when you need to call Pyreon APIs (e.g. useHead, prefetchLoaderData)\n * outside of renderToString but still want per-request isolation.\n */\nexport function runWithRequestContext<T>(fn: () => Promise<T>): Promise<T> {\n return withStoreContext(() => _contextAls.run([], fn))\n}\n\n/**\n * Render a VNode tree to a Web-standard ReadableStream of HTML chunks.\n *\n * True progressive streaming: HTML is flushed to the client as soon as each\n * node is ready. Synchronous subtrees are enqueued immediately; async component\n * boundaries are awaited in-order and their output is enqueued as it resolves.\n *\n * Suspense boundaries are streamed out-of-order: the fallback is emitted\n * immediately, and the resolved children are sent as a `<template>` + inline\n * swap script once ready — without blocking the rest of the page.\n *\n * Each renderToStream call gets its own isolated ALS context stack.\n */\nexport function renderToStream(root: VNode | null): ReadableStream<string> {\n return new ReadableStream<string>({\n start(controller) {\n const enqueue = (chunk: string) => controller.enqueue(chunk)\n let bid = 0\n const ctx: StreamCtx = {\n pending: [],\n nextId: () => bid++,\n mainEnqueue: enqueue,\n }\n return withStoreContext(() =>\n _contextAls.run([], () =>\n _streamCtxAls\n .run(ctx, async () => {\n await streamNode(root, enqueue)\n // Drain all pending Suspense resolutions (may spawn nested ones)\n while (ctx.pending.length > 0) {\n await Promise.all(ctx.pending.splice(0))\n }\n controller.close()\n })\n .catch((err) => controller.error(err)),\n ),\n )\n },\n })\n}\n\n// ─── Streaming renderer ───────────────────────────────────────────────────────\n\nasync function streamVNode(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n if (vnode.type === Fragment) {\n for (const child of vnode.children) await streamNode(child, enqueue)\n return\n }\n\n if (vnode.type === (ForSymbol as unknown as string)) {\n const { each, children } = vnode.props as unknown as ForProps<unknown>\n enqueue(\"<!--pyreon-for-->\")\n for (const item of each()) await streamNode(children(item) as VNodeChild, enqueue)\n enqueue(\"<!--/pyreon-for-->\")\n return\n }\n\n if (typeof vnode.type === \"function\") {\n await streamComponentNode(vnode, enqueue)\n return\n }\n\n await streamElementNode(vnode, enqueue)\n}\n\nasync function streamComponentNode(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n if (vnode.type === Suspense) {\n await streamSuspenseBoundary(vnode, enqueue)\n return\n }\n const { vnode: output } = runWithHooks(vnode.type as ComponentFn, mergeChildrenIntoProps(vnode))\n const resolved = output instanceof Promise ? await output : output\n if (resolved !== null) await streamNode(resolved, enqueue)\n}\n\nasync function streamElementNode(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n const tag = vnode.type as string\n let open = `<${tag}`\n for (const [key, value] of Object.entries(vnode.props)) {\n const attr = renderProp(key, value)\n if (attr) open += ` ${attr}`\n }\n if (isVoidElement(tag)) {\n enqueue(`${open} />`)\n return\n }\n enqueue(`${open}>`)\n for (const child of vnode.children) await streamNode(child, enqueue)\n enqueue(`</${tag}>`)\n}\n\nasync function streamNode(\n node: VNodeChild | null | (() => VNodeChild),\n enqueue: (s: string) => void,\n): Promise<void> {\n if (typeof node === \"function\") {\n return streamNode((node as () => VNodeChild)(), enqueue)\n }\n if (node == null || node === false) return\n if (typeof node === \"string\") {\n enqueue(escapeHtml(node))\n return\n }\n if (typeof node === \"number\" || typeof node === \"boolean\") {\n enqueue(String(node))\n return\n }\n if (Array.isArray(node)) {\n for (const child of node) await streamNode(child, enqueue)\n return\n }\n\n await streamVNode(node as VNode, enqueue)\n}\n\n// Inline swap helper emitted once per stream, before the first <template>\nconst SUSPENSE_SWAP_FN =\n \"<script>function __NS(s,t){var e=document.getElementById(s),l=document.getElementById(t);\" +\n \"if(e&&l){e.replaceWith(l.content.cloneNode(!0));l.remove()}}</script>\"\n\n/**\n * Stream a Suspense boundary: emit fallback immediately, then resolve children\n * asynchronously and emit them as a `<template>` + client-side swap.\n *\n * The actual children HTML is buffered until fully resolved, then emitted to the\n * main stream enqueue so it always arrives after the fallback placeholder.\n */\nasync function streamSuspenseBoundary(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n const ctx = _streamCtxAls.getStore()\n const { fallback, children } = vnode.props as { fallback: VNodeChild; children?: VNodeChild }\n\n // No streaming context (e.g. called from renderToString) — render children inline\n if (!ctx) {\n const { vnode: output } = runWithHooks(Suspense as ComponentFn, vnode.props)\n if (output !== null) await streamNode(output, enqueue)\n return\n }\n\n const id = ctx.nextId()\n const { mainEnqueue } = ctx\n\n // Emit the swap helper function once (before first use)\n if (id === 0) mainEnqueue(SUSPENSE_SWAP_FN)\n\n // Stream the fallback synchronously (no await on children)\n mainEnqueue(`<div id=\"pyreon-s-${id}\">`)\n await streamNode(fallback ?? null, enqueue)\n mainEnqueue(\"</div>\")\n\n // Capture the context store for the async resolution so it inherits context\n const ctxStore = _contextAls.getStore() ?? []\n\n // Queue async resolution — runs in parallel, emits to main stream when done\n // Errors are caught per-boundary so one failing Suspense doesn't abort the stream.\n ctx.pending.push(\n _contextAls.run(ctxStore, async () => {\n try {\n const buf: string[] = []\n await streamNode(children ?? null, (s) => buf.push(s))\n mainEnqueue(`<template id=\"pyreon-t-${id}\">${buf.join(\"\")}</template>`)\n mainEnqueue(`<script>__NS(\"pyreon-s-${id}\",\"pyreon-t-${id}\")</script>`)\n } catch (_err) {\n // Fallback stays visible — no swap script emitted\n }\n }),\n )\n}\n\n// ─── Core renderer ───────────────────────────────────────────────────────────\n\nasync function renderNode(node: VNodeChild | (() => VNodeChild)): Promise<string> {\n // Reactive accessor — call it synchronously (snapshot)\n if (typeof node === \"function\") {\n return renderNode((node as () => VNodeChild)())\n }\n\n if (node == null || node === false) return \"\"\n\n if (typeof node === \"string\") return escapeHtml(node)\n if (typeof node === \"number\" || typeof node === \"boolean\") return String(node)\n\n if (Array.isArray(node)) {\n const parts = await Promise.all(node.map((n) => renderNode(n)))\n return parts.join(\"\")\n }\n\n const vnode = node as VNode\n\n if (vnode.type === Fragment) {\n return renderChildren(vnode.children)\n }\n\n if (vnode.type === (ForSymbol as unknown as string)) {\n const { each, children } = vnode.props as unknown as ForProps<unknown>\n const parts = await Promise.all(each().map((item) => renderNode(children(item) as VNodeChild)))\n // Hydration markers so the client can claim existing For-rendered children\n return `<!--pyreon-for-->${parts.join(\"\")}<!--/pyreon-for-->`\n }\n\n if (typeof vnode.type === \"function\") {\n return renderComponent(vnode as VNode & { type: ComponentFn })\n }\n\n return renderElement(vnode)\n}\n\nasync function renderChildren(children: VNodeChild[]): Promise<string> {\n const parts = await Promise.all(children.map((c) => renderNode(c)))\n return parts.join(\"\")\n}\n\nasync function renderComponent(vnode: VNode & { type: ComponentFn }): Promise<string> {\n const { vnode: output } = runWithHooks(vnode.type, mergeChildrenIntoProps(vnode))\n\n // Async component function (async function Component()) — await the promise\n if (output instanceof Promise) {\n const resolved = await output\n if (resolved === null) return \"\"\n return renderNode(resolved)\n }\n\n if (output === null) return \"\"\n return renderNode(output)\n}\n\nasync function renderElement(vnode: VNode): Promise<string> {\n const tag = vnode.type as string\n let html = `<${tag}`\n\n for (const [key, value] of Object.entries(vnode.props)) {\n const attr = renderProp(key, value)\n if (attr) html += ` ${attr}`\n }\n\n if (isVoidElement(tag)) {\n html += \" />\"\n return html\n }\n\n html += \">\"\n\n for (const child of vnode.children) {\n html += await renderNode(child)\n }\n\n html += `</${tag}>`\n return html\n}\n\nconst SSR_URL_ATTRS = new Set([\"href\", \"src\", \"action\", \"formaction\", \"poster\", \"cite\", \"data\"])\nconst SSR_UNSAFE_URL_RE = /^\\s*(?:javascript|data):/i\n\nfunction renderPropSkipped(key: string): boolean {\n if (key === \"key\" || key === \"ref\" || key === \"n-show\") return true\n if (key.startsWith(\"n-\")) return true\n if (/^on[A-Z]/.test(key)) return true\n return false\n}\n\nfunction renderPropValue(key: string, value: unknown): string | null {\n if (value === null || value === undefined || value === false) return null\n if (value === true) return escapeHtml(toAttrName(key))\n\n if (key === \"class\") {\n const cls = normalizeClass(value)\n return cls ? `class=\"${escapeHtml(cls)}\"` : null\n }\n\n if (key === \"style\") {\n const style = normalizeStyle(value)\n return style ? `style=\"${escapeHtml(style)}\"` : null\n }\n\n return `${escapeHtml(toAttrName(key))}=\"${escapeHtml(String(value))}\"`\n}\n\nfunction renderProp(key: string, value: unknown): string | null {\n if (renderPropSkipped(key)) return null\n\n if (typeof value === \"function\") {\n return renderProp(key, (value as () => unknown)())\n }\n\n if (SSR_URL_ATTRS.has(key) && typeof value === \"string\" && SSR_UNSAFE_URL_RE.test(value)) {\n return null\n }\n\n return renderPropValue(key, value)\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nconst VOID_ELEMENTS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"param\",\n \"source\",\n \"track\",\n \"wbr\",\n])\n\nfunction isVoidElement(tag: string): boolean {\n return VOID_ELEMENTS.has(tag.toLowerCase())\n}\n\n/** camelCase prop → kebab-case HTML attribute (e.g. className → class, htmlFor → for) */\nfunction toAttrName(key: string): string {\n if (key === \"className\") return \"class\"\n if (key === \"htmlFor\") return \"for\"\n return key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)\n}\n\nfunction normalizeClass(value: unknown): string {\n if (typeof value === \"string\") return value\n if (Array.isArray(value)) return value.filter(Boolean).join(\" \")\n if (typeof value === \"object\" && value !== null) {\n return Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v)\n .map(([k]) => k)\n .join(\" \")\n }\n return \"\"\n}\n\nfunction normalizeStyle(value: unknown): string {\n if (typeof value === \"string\") return value\n if (typeof value === \"object\" && value !== null) {\n return Object.entries(value as Record<string, unknown>)\n .map(([k, v]) => `${toKebab(k)}: ${v}`)\n .join(\"; \")\n }\n return \"\"\n}\n\nfunction toKebab(str: string): string {\n return str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)\n}\n\nconst ESCAPE_MAP: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n}\n\nfunction escapeHtml(str: string): string {\n return str.replace(/[&<>\"']/g, (c) => ESCAPE_MAP[c] ?? c)\n}\n\n/**\n * Merge vnode.children into props.children for component rendering.\n * Matches the behavior of mount.ts and hydrate.ts so components can\n * access children passed via h(Comp, props, child1, child2).\n */\nfunction mergeChildrenIntoProps(vnode: VNode): Record<string, unknown> {\n if (\n vnode.children.length > 0 &&\n (vnode.props as Record<string, unknown>).children === undefined\n ) {\n return {\n ...vnode.props,\n children: vnode.children.length === 1 ? vnode.children[0] : vnode.children,\n }\n }\n return vnode.props as Record<string, unknown>\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @pyreon/runtime-server — SSR/SSG renderer for Pyreon.\n *\n * Walks a VNode tree and produces HTML strings.\n * Signal accessors (reactive getters `() => value`) are called synchronously\n * to snapshot their current value — no effects are set up on the server.\n *\n * Async components (`async function Component()`) are fully supported:\n * renderToString will await them before continuing the tree walk.\n *\n * API:\n * renderToString(vnode) → Promise<string>\n * renderToStream(vnode) → ReadableStream<string>\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\"\nimport type { ComponentFn, ForProps, VNode, VNodeChild } from \"@pyreon/core\"\nimport { ForSymbol, Fragment, runWithHooks, Suspense, setContextStackProvider } from \"@pyreon/core\"\n\n// ─── Streaming Suspense context ───────────────────────────────────────────────\n// Tracks in-flight async Suspense boundary resolutions within a single stream.\n\ninterface StreamCtx {\n pending: Promise<void>[]\n nextId: () => number\n mainEnqueue: (s: string) => void\n}\n\nconst _streamCtxAls = new AsyncLocalStorage<StreamCtx>()\n\n// ─── Concurrent SSR context isolation ────────────────────────────────────────\n// Each renderToString call runs in its own ALS store (a fresh empty stack[]).\n// Concurrent requests never share context frames.\n\nconst _contextAls = new AsyncLocalStorage<Map<symbol, unknown>[]>()\nconst _fallbackStack: Map<symbol, unknown>[] = []\n\nsetContextStackProvider(() => _contextAls.getStore() ?? _fallbackStack)\n\n// ─── Store isolation (optional) ───────────────────────────────────────────────\n// A second ALS isolates store registries between concurrent requests.\n// Activated only when the user calls configureStoreIsolation().\n\nconst _storeAls = new AsyncLocalStorage<Map<string, unknown>>()\nlet _storeIsolationActive = false\n\n/**\n * Wire up per-request store isolation.\n * Call once at server startup, passing a `setStoreRegistryProvider` function.\n *\n * @example\n * import { configureStoreIsolation } from \"@pyreon/runtime-server\"\n * configureStoreIsolation(setStoreRegistryProvider)\n */\nexport function configureStoreIsolation(\n setStoreRegistryProvider: (fn: () => Map<string, unknown>) => void,\n): void {\n setStoreRegistryProvider(() => _storeAls.getStore() ?? new Map())\n _storeIsolationActive = true\n}\n\n/** Wrap a function call in a fresh store registry (no-op if isolation not configured). */\nfunction withStoreContext<T>(fn: () => T): T {\n if (!_storeIsolationActive) return fn()\n return _storeAls.run(new Map(), fn)\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/** Render a VNode tree to an HTML string. Supports async component functions. */\nexport async function renderToString(root: VNode | null): Promise<string> {\n if (root === null) return \"\"\n // Each call gets a fresh isolated context stack and (optionally) store registry\n return withStoreContext(() => _contextAls.run([], () => renderNode(root)))\n}\n\n/**\n * Run an async function with a fresh, isolated context stack and store registry.\n * Useful when you need to call Pyreon APIs (e.g. useHead, prefetchLoaderData)\n * outside of renderToString but still want per-request isolation.\n */\nexport function runWithRequestContext<T>(fn: () => Promise<T>): Promise<T> {\n return withStoreContext(() => _contextAls.run([], fn))\n}\n\n/**\n * Render a VNode tree to a Web-standard ReadableStream of HTML chunks.\n *\n * True progressive streaming: HTML is flushed to the client as soon as each\n * node is ready. Synchronous subtrees are enqueued immediately; async component\n * boundaries are awaited in-order and their output is enqueued as it resolves.\n *\n * Suspense boundaries are streamed out-of-order: the fallback is emitted\n * immediately, and the resolved children are sent as a `<template>` + inline\n * swap script once ready — without blocking the rest of the page.\n *\n * Each renderToStream call gets its own isolated ALS context stack.\n */\nexport function renderToStream(root: VNode | null): ReadableStream<string> {\n return new ReadableStream<string>({\n start(controller) {\n const enqueue = (chunk: string) => controller.enqueue(chunk)\n let bid = 0\n const ctx: StreamCtx = {\n pending: [],\n nextId: () => bid++,\n mainEnqueue: enqueue,\n }\n return withStoreContext(() =>\n _contextAls.run([], () =>\n _streamCtxAls\n .run(ctx, async () => {\n await streamNode(root, enqueue)\n // Drain all pending Suspense resolutions (may spawn nested ones)\n while (ctx.pending.length > 0) {\n await Promise.all(ctx.pending.splice(0))\n }\n controller.close()\n })\n .catch((err) => controller.error(err)),\n ),\n )\n },\n })\n}\n\n// ─── Streaming renderer ───────────────────────────────────────────────────────\n\nasync function streamVNode(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n if (vnode.type === Fragment) {\n for (const child of vnode.children) await streamNode(child, enqueue)\n return\n }\n\n if (vnode.type === (ForSymbol as unknown as string)) {\n const { each, children } = vnode.props as unknown as ForProps<unknown>\n enqueue(\"<!--pyreon-for-->\")\n for (const item of each()) await streamNode(children(item) as VNodeChild, enqueue)\n enqueue(\"<!--/pyreon-for-->\")\n return\n }\n\n if (typeof vnode.type === \"function\") {\n await streamComponentNode(vnode, enqueue)\n return\n }\n\n await streamElementNode(vnode, enqueue)\n}\n\nasync function streamComponentNode(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n if (vnode.type === Suspense) {\n await streamSuspenseBoundary(vnode, enqueue)\n return\n }\n const { vnode: output } = runWithHooks(vnode.type as ComponentFn, mergeChildrenIntoProps(vnode))\n const resolved = output instanceof Promise ? await output : output\n if (resolved !== null) await streamNode(resolved, enqueue)\n}\n\nasync function streamElementNode(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n const tag = vnode.type as string\n let open = `<${tag}`\n const props = vnode.props as Record<string, unknown>\n for (const key in props) {\n const attr = renderProp(key, props[key])\n if (attr) open += ` ${attr}`\n }\n if (isVoidElement(tag)) {\n enqueue(`${open} />`)\n return\n }\n enqueue(`${open}>`)\n for (const child of vnode.children) await streamNode(child, enqueue)\n enqueue(`</${tag}>`)\n}\n\nasync function streamNode(\n node: VNodeChild | null | (() => VNodeChild),\n enqueue: (s: string) => void,\n): Promise<void> {\n if (typeof node === \"function\") {\n return streamNode((node as () => VNodeChild)(), enqueue)\n }\n if (node == null || node === false) return\n if (typeof node === \"string\") {\n enqueue(escapeHtml(node))\n return\n }\n if (typeof node === \"number\" || typeof node === \"boolean\") {\n enqueue(String(node))\n return\n }\n if (Array.isArray(node)) {\n for (const child of node) await streamNode(child, enqueue)\n return\n }\n\n await streamVNode(node as VNode, enqueue)\n}\n\n// Inline swap helper emitted once per stream, before the first <template>\nconst SUSPENSE_SWAP_FN =\n \"<script>function __NS(s,t){var e=document.getElementById(s),l=document.getElementById(t);\" +\n \"if(e&&l){e.replaceWith(l.content.cloneNode(!0));l.remove()}}</script>\"\n\n/**\n * Stream a Suspense boundary: emit fallback immediately, then resolve children\n * asynchronously and emit them as a `<template>` + client-side swap.\n *\n * The actual children HTML is buffered until fully resolved, then emitted to the\n * main stream enqueue so it always arrives after the fallback placeholder.\n */\nasync function streamSuspenseBoundary(vnode: VNode, enqueue: (s: string) => void): Promise<void> {\n const ctx = _streamCtxAls.getStore()\n const { fallback, children } = vnode.props as { fallback: VNodeChild; children?: VNodeChild }\n\n // No streaming context (e.g. called from renderToString) — render children inline\n if (!ctx) {\n const { vnode: output } = runWithHooks(Suspense as ComponentFn, vnode.props)\n if (output !== null) await streamNode(output, enqueue)\n return\n }\n\n const id = ctx.nextId()\n const { mainEnqueue } = ctx\n\n // Emit the swap helper function once (before first use)\n if (id === 0) mainEnqueue(SUSPENSE_SWAP_FN)\n\n // Stream the fallback synchronously (no await on children)\n mainEnqueue(`<div id=\"pyreon-s-${id}\">`)\n await streamNode(fallback ?? null, enqueue)\n mainEnqueue(\"</div>\")\n\n // Capture the context store for the async resolution so it inherits context\n const ctxStore = _contextAls.getStore() ?? []\n\n // Queue async resolution — runs in parallel, emits to main stream when done\n // Errors are caught per-boundary so one failing Suspense doesn't abort the stream.\n ctx.pending.push(\n _contextAls.run(ctxStore, async () => {\n try {\n const buf: string[] = []\n await streamNode(children ?? null, (s) => buf.push(s))\n mainEnqueue(`<template id=\"pyreon-t-${id}\">${buf.join(\"\")}</template>`)\n mainEnqueue(`<script>__NS(\"pyreon-s-${id}\",\"pyreon-t-${id}\")</script>`)\n } catch (_err) {\n // Fallback stays visible — no swap script emitted\n }\n }),\n )\n}\n\n// ─── Core renderer ───────────────────────────────────────────────────────────\n\nasync function renderNode(node: VNodeChild | (() => VNodeChild)): Promise<string> {\n // Reactive accessor — call it synchronously (snapshot)\n if (typeof node === \"function\") {\n return renderNode((node as () => VNodeChild)())\n }\n\n if (node == null || node === false) return \"\"\n\n if (typeof node === \"string\") return escapeHtml(node)\n if (typeof node === \"number\" || typeof node === \"boolean\") return String(node)\n\n if (Array.isArray(node)) {\n let html = \"\"\n for (const child of node) html += await renderNode(child)\n return html\n }\n\n const vnode = node as VNode\n\n if (vnode.type === Fragment) {\n return renderChildren(vnode.children)\n }\n\n if (vnode.type === (ForSymbol as unknown as string)) {\n const { each, children } = vnode.props as unknown as ForProps<unknown>\n let forHtml = \"<!--pyreon-for-->\"\n for (const item of each()) forHtml += await renderNode(children(item) as VNodeChild)\n forHtml += \"<!--/pyreon-for-->\"\n return forHtml\n }\n\n if (typeof vnode.type === \"function\") {\n return renderComponent(vnode as VNode & { type: ComponentFn })\n }\n\n return renderElement(vnode)\n}\n\nasync function renderChildren(children: VNodeChild[]): Promise<string> {\n let html = \"\"\n for (const child of children) html += await renderNode(child)\n return html\n}\n\nasync function renderComponent(vnode: VNode & { type: ComponentFn }): Promise<string> {\n const { vnode: output } = runWithHooks(vnode.type, mergeChildrenIntoProps(vnode))\n\n // Async component function (async function Component()) — await the promise\n if (output instanceof Promise) {\n const resolved = await output\n if (resolved === null) return \"\"\n return renderNode(resolved)\n }\n\n if (output === null) return \"\"\n return renderNode(output)\n}\n\nasync function renderElement(vnode: VNode): Promise<string> {\n const tag = vnode.type as string\n let html = `<${tag}`\n\n const props = vnode.props as Record<string, unknown>\n for (const key in props) {\n const attr = renderProp(key, props[key])\n if (attr) html += ` ${attr}`\n }\n\n if (isVoidElement(tag)) {\n html += \" />\"\n return html\n }\n\n html += \">\"\n\n for (const child of vnode.children) {\n html += await renderNode(child)\n }\n\n html += `</${tag}>`\n return html\n}\n\nconst SSR_URL_ATTRS = new Set([\"href\", \"src\", \"action\", \"formaction\", \"poster\", \"cite\", \"data\"])\nconst SSR_UNSAFE_URL_RE = /^\\s*(?:javascript|data):/i\n\nfunction renderPropSkipped(key: string): boolean {\n if (key === \"key\" || key === \"ref\" || key === \"n-show\") return true\n if (key.startsWith(\"n-\")) return true\n if (/^on[A-Z]/.test(key)) return true\n return false\n}\n\nfunction renderPropValue(key: string, value: unknown): string | null {\n if (value === null || value === undefined || value === false) return null\n if (value === true) return escapeHtml(toAttrName(key))\n\n if (key === \"class\") {\n const cls = normalizeClass(value)\n return cls ? `class=\"${escapeHtml(cls)}\"` : null\n }\n\n if (key === \"style\") {\n const style = normalizeStyle(value)\n return style ? `style=\"${escapeHtml(style)}\"` : null\n }\n\n return `${escapeHtml(toAttrName(key))}=\"${escapeHtml(String(value))}\"`\n}\n\nfunction renderProp(key: string, value: unknown): string | null {\n if (renderPropSkipped(key)) return null\n\n if (typeof value === \"function\") {\n return renderProp(key, (value as () => unknown)())\n }\n\n if (SSR_URL_ATTRS.has(key) && typeof value === \"string\" && SSR_UNSAFE_URL_RE.test(value)) {\n return null\n }\n\n return renderPropValue(key, value)\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\nconst VOID_ELEMENTS = new Set([\n \"area\",\n \"base\",\n \"br\",\n \"col\",\n \"embed\",\n \"hr\",\n \"img\",\n \"input\",\n \"link\",\n \"meta\",\n \"param\",\n \"source\",\n \"track\",\n \"wbr\",\n])\n\nfunction isVoidElement(tag: string): boolean {\n return VOID_ELEMENTS.has(tag.toLowerCase())\n}\n\n/** camelCase prop → kebab-case HTML attribute (e.g. className → class, htmlFor → for) */\nfunction toAttrName(key: string): string {\n if (key === \"className\") return \"class\"\n if (key === \"htmlFor\") return \"for\"\n return key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)\n}\n\nfunction normalizeClass(value: unknown): string {\n if (typeof value === \"string\") return value\n if (Array.isArray(value)) return value.filter(Boolean).join(\" \")\n if (typeof value === \"object\" && value !== null) {\n return Object.entries(value as Record<string, unknown>)\n .filter(([, v]) => v)\n .map(([k]) => k)\n .join(\" \")\n }\n return \"\"\n}\n\nfunction normalizeStyle(value: unknown): string {\n if (typeof value === \"string\") return value\n if (typeof value === \"object\" && value !== null) {\n return Object.entries(value as Record<string, unknown>)\n .map(([k, v]) => `${toKebab(k)}: ${v}`)\n .join(\"; \")\n }\n return \"\"\n}\n\nfunction toKebab(str: string): string {\n return str.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)\n}\n\nconst ESCAPE_MAP: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#39;\",\n}\n\n// Fast test — most strings in SSR have no special chars (tag names, class names, etc.)\nconst NEEDS_ESCAPE_RE = /[&<>\"']/\n\nfunction escapeHtml(str: string): string {\n if (!NEEDS_ESCAPE_RE.test(str)) return str\n return str.replace(/[&<>\"']/g, (c) => ESCAPE_MAP[c] ?? c)\n}\n\n/**\n * Merge vnode.children into props.children for component rendering.\n * Matches the behavior of mount.ts and hydrate.ts so components can\n * access children passed via h(Comp, props, child1, child2).\n */\nfunction mergeChildrenIntoProps(vnode: VNode): Record<string, unknown> {\n if (\n vnode.children.length > 0 &&\n (vnode.props as Record<string, unknown>).children === undefined\n ) {\n return {\n ...vnode.props,\n children: vnode.children.length === 1 ? vnode.children[0] : vnode.children,\n }\n }\n return vnode.props as Record<string, unknown>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4BA,MAAM,gBAAgB,IAAI,mBAA8B;AAMxD,MAAM,cAAc,IAAI,mBAA2C;AACnE,MAAM,iBAAyC,EAAE;AAEjD,8BAA8B,YAAY,UAAU,IAAI,eAAe;AAMvE,MAAM,YAAY,IAAI,mBAAyC;AAC/D,IAAI,wBAAwB;;;;;;;;;AAU5B,SAAgB,wBACd,0BACM;AACN,gCAA+B,UAAU,UAAU,oBAAI,IAAI,KAAK,CAAC;AACjE,yBAAwB;;;AAI1B,SAAS,iBAAoB,IAAgB;AAC3C,KAAI,CAAC,sBAAuB,QAAO,IAAI;AACvC,QAAO,UAAU,oBAAI,IAAI,KAAK,EAAE,GAAG;;;AAMrC,eAAsB,eAAe,MAAqC;AACxE,KAAI,SAAS,KAAM,QAAO;AAE1B,QAAO,uBAAuB,YAAY,IAAI,EAAE,QAAQ,WAAW,KAAK,CAAC,CAAC;;;;;;;AAQ5E,SAAgB,sBAAyB,IAAkC;AACzE,QAAO,uBAAuB,YAAY,IAAI,EAAE,EAAE,GAAG,CAAC;;;;;;;;;;;;;;;AAgBxD,SAAgB,eAAe,MAA4C;AACzE,QAAO,IAAI,eAAuB,EAChC,MAAM,YAAY;EAChB,MAAM,WAAW,UAAkB,WAAW,QAAQ,MAAM;EAC5D,IAAI,MAAM;EACV,MAAM,MAAiB;GACrB,SAAS,EAAE;GACX,cAAc;GACd,aAAa;GACd;AACD,SAAO,uBACL,YAAY,IAAI,EAAE,QAChB,cACG,IAAI,KAAK,YAAY;AACpB,SAAM,WAAW,MAAM,QAAQ;AAE/B,UAAO,IAAI,QAAQ,SAAS,EAC1B,OAAM,QAAQ,IAAI,IAAI,QAAQ,OAAO,EAAE,CAAC;AAE1C,cAAW,OAAO;IAClB,CACD,OAAO,QAAQ,WAAW,MAAM,IAAI,CAAC,CACzC,CACF;IAEJ,CAAC;;AAKJ,eAAe,YAAY,OAAc,SAA6C;AACpF,KAAI,MAAM,SAAS,UAAU;AAC3B,OAAK,MAAM,SAAS,MAAM,SAAU,OAAM,WAAW,OAAO,QAAQ;AACpE;;AAGF,KAAI,MAAM,SAAU,WAAiC;EACnD,MAAM,EAAE,MAAM,aAAa,MAAM;AACjC,UAAQ,oBAAoB;AAC5B,OAAK,MAAM,QAAQ,MAAM,CAAE,OAAM,WAAW,SAAS,KAAK,EAAgB,QAAQ;AAClF,UAAQ,qBAAqB;AAC7B;;AAGF,KAAI,OAAO,MAAM,SAAS,YAAY;AACpC,QAAM,oBAAoB,OAAO,QAAQ;AACzC;;AAGF,OAAM,kBAAkB,OAAO,QAAQ;;AAGzC,eAAe,oBAAoB,OAAc,SAA6C;AAC5F,KAAI,MAAM,SAAS,UAAU;AAC3B,QAAM,uBAAuB,OAAO,QAAQ;AAC5C;;CAEF,MAAM,EAAE,OAAO,WAAW,aAAa,MAAM,MAAqB,uBAAuB,MAAM,CAAC;CAChG,MAAM,WAAW,kBAAkB,UAAU,MAAM,SAAS;AAC5D,KAAI,aAAa,KAAM,OAAM,WAAW,UAAU,QAAQ;;AAG5D,eAAe,kBAAkB,OAAc,SAA6C;CAC1F,MAAM,MAAM,MAAM;CAClB,IAAI,OAAO,IAAI;CACf,MAAM,QAAQ,MAAM;AACpB,MAAK,MAAM,OAAO,OAAO;EACvB,MAAM,OAAO,WAAW,KAAK,MAAM,KAAK;AACxC,MAAI,KAAM,SAAQ,IAAI;;AAExB,KAAI,cAAc,IAAI,EAAE;AACtB,UAAQ,GAAG,KAAK,KAAK;AACrB;;AAEF,SAAQ,GAAG,KAAK,GAAG;AACnB,MAAK,MAAM,SAAS,MAAM,SAAU,OAAM,WAAW,OAAO,QAAQ;AACpE,SAAQ,KAAK,IAAI,GAAG;;AAGtB,eAAe,WACb,MACA,SACe;AACf,KAAI,OAAO,SAAS,WAClB,QAAO,WAAY,MAA2B,EAAE,QAAQ;AAE1D,KAAI,QAAQ,QAAQ,SAAS,MAAO;AACpC,KAAI,OAAO,SAAS,UAAU;AAC5B,UAAQ,WAAW,KAAK,CAAC;AACzB;;AAEF,KAAI,OAAO,SAAS,YAAY,OAAO,SAAS,WAAW;AACzD,UAAQ,OAAO,KAAK,CAAC;AACrB;;AAEF,KAAI,MAAM,QAAQ,KAAK,EAAE;AACvB,OAAK,MAAM,SAAS,KAAM,OAAM,WAAW,OAAO,QAAQ;AAC1D;;AAGF,OAAM,YAAY,MAAe,QAAQ;;AAI3C,MAAM,mBACJ;;;;;;;;AAUF,eAAe,uBAAuB,OAAc,SAA6C;CAC/F,MAAM,MAAM,cAAc,UAAU;CACpC,MAAM,EAAE,UAAU,aAAa,MAAM;AAGrC,KAAI,CAAC,KAAK;EACR,MAAM,EAAE,OAAO,WAAW,aAAa,UAAyB,MAAM,MAAM;AAC5E,MAAI,WAAW,KAAM,OAAM,WAAW,QAAQ,QAAQ;AACtD;;CAGF,MAAM,KAAK,IAAI,QAAQ;CACvB,MAAM,EAAE,gBAAgB;AAGxB,KAAI,OAAO,EAAG,aAAY,iBAAiB;AAG3C,aAAY,qBAAqB,GAAG,IAAI;AACxC,OAAM,WAAW,YAAY,MAAM,QAAQ;AAC3C,aAAY,SAAS;CAGrB,MAAM,WAAW,YAAY,UAAU,IAAI,EAAE;AAI7C,KAAI,QAAQ,KACV,YAAY,IAAI,UAAU,YAAY;AACpC,MAAI;GACF,MAAM,MAAgB,EAAE;AACxB,SAAM,WAAW,YAAY,OAAO,MAAM,IAAI,KAAK,EAAE,CAAC;AACtD,eAAY,0BAA0B,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC,aAAa;AACvE,eAAY,0BAA0B,GAAG,cAAc,GAAG,cAAa;WAChE,MAAM;GAGf,CACH;;AAKH,eAAe,WAAW,MAAwD;AAEhF,KAAI,OAAO,SAAS,WAClB,QAAO,WAAY,MAA2B,CAAC;AAGjD,KAAI,QAAQ,QAAQ,SAAS,MAAO,QAAO;AAE3C,KAAI,OAAO,SAAS,SAAU,QAAO,WAAW,KAAK;AACrD,KAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAW,QAAO,OAAO,KAAK;AAE9E,KAAI,MAAM,QAAQ,KAAK,EAAE;EACvB,IAAI,OAAO;AACX,OAAK,MAAM,SAAS,KAAM,SAAQ,MAAM,WAAW,MAAM;AACzD,SAAO;;CAGT,MAAM,QAAQ;AAEd,KAAI,MAAM,SAAS,SACjB,QAAO,eAAe,MAAM,SAAS;AAGvC,KAAI,MAAM,SAAU,WAAiC;EACnD,MAAM,EAAE,MAAM,aAAa,MAAM;EACjC,IAAI,UAAU;AACd,OAAK,MAAM,QAAQ,MAAM,CAAE,YAAW,MAAM,WAAW,SAAS,KAAK,CAAe;AACpF,aAAW;AACX,SAAO;;AAGT,KAAI,OAAO,MAAM,SAAS,WACxB,QAAO,gBAAgB,MAAuC;AAGhE,QAAO,cAAc,MAAM;;AAG7B,eAAe,eAAe,UAAyC;CACrE,IAAI,OAAO;AACX,MAAK,MAAM,SAAS,SAAU,SAAQ,MAAM,WAAW,MAAM;AAC7D,QAAO;;AAGT,eAAe,gBAAgB,OAAuD;CACpF,MAAM,EAAE,OAAO,WAAW,aAAa,MAAM,MAAM,uBAAuB,MAAM,CAAC;AAGjF,KAAI,kBAAkB,SAAS;EAC7B,MAAM,WAAW,MAAM;AACvB,MAAI,aAAa,KAAM,QAAO;AAC9B,SAAO,WAAW,SAAS;;AAG7B,KAAI,WAAW,KAAM,QAAO;AAC5B,QAAO,WAAW,OAAO;;AAG3B,eAAe,cAAc,OAA+B;CAC1D,MAAM,MAAM,MAAM;CAClB,IAAI,OAAO,IAAI;CAEf,MAAM,QAAQ,MAAM;AACpB,MAAK,MAAM,OAAO,OAAO;EACvB,MAAM,OAAO,WAAW,KAAK,MAAM,KAAK;AACxC,MAAI,KAAM,SAAQ,IAAI;;AAGxB,KAAI,cAAc,IAAI,EAAE;AACtB,UAAQ;AACR,SAAO;;AAGT,SAAQ;AAER,MAAK,MAAM,SAAS,MAAM,SACxB,SAAQ,MAAM,WAAW,MAAM;AAGjC,SAAQ,KAAK,IAAI;AACjB,QAAO;;AAGT,MAAM,gBAAgB,IAAI,IAAI;CAAC;CAAQ;CAAO;CAAU;CAAc;CAAU;CAAQ;CAAO,CAAC;AAChG,MAAM,oBAAoB;AAE1B,SAAS,kBAAkB,KAAsB;AAC/C,KAAI,QAAQ,SAAS,QAAQ,SAAS,QAAQ,SAAU,QAAO;AAC/D,KAAI,IAAI,WAAW,KAAK,CAAE,QAAO;AACjC,KAAI,WAAW,KAAK,IAAI,CAAE,QAAO;AACjC,QAAO;;AAGT,SAAS,gBAAgB,KAAa,OAA+B;AACnE,KAAI,UAAU,QAAQ,UAAU,UAAa,UAAU,MAAO,QAAO;AACrE,KAAI,UAAU,KAAM,QAAO,WAAW,WAAW,IAAI,CAAC;AAEtD,KAAI,QAAQ,SAAS;EACnB,MAAM,MAAM,eAAe,MAAM;AACjC,SAAO,MAAM,UAAU,WAAW,IAAI,CAAC,KAAK;;AAG9C,KAAI,QAAQ,SAAS;EACnB,MAAM,QAAQ,eAAe,MAAM;AACnC,SAAO,QAAQ,UAAU,WAAW,MAAM,CAAC,KAAK;;AAGlD,QAAO,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,IAAI,WAAW,OAAO,MAAM,CAAC,CAAC;;AAGtE,SAAS,WAAW,KAAa,OAA+B;AAC9D,KAAI,kBAAkB,IAAI,CAAE,QAAO;AAEnC,KAAI,OAAO,UAAU,WACnB,QAAO,WAAW,KAAM,OAAyB,CAAC;AAGpD,KAAI,cAAc,IAAI,IAAI,IAAI,OAAO,UAAU,YAAY,kBAAkB,KAAK,MAAM,CACtF,QAAO;AAGT,QAAO,gBAAgB,KAAK,MAAM;;AAKpC,MAAM,gBAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,cAAc,KAAsB;AAC3C,QAAO,cAAc,IAAI,IAAI,aAAa,CAAC;;;AAI7C,SAAS,WAAW,KAAqB;AACvC,KAAI,QAAQ,YAAa,QAAO;AAChC,KAAI,QAAQ,UAAW,QAAO;AAC9B,QAAO,IAAI,QAAQ,WAAW,MAAM,IAAI,EAAE,aAAa,GAAG;;AAG5D,SAAS,eAAe,OAAwB;AAC9C,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,OAAO,QAAQ,CAAC,KAAK,IAAI;AAChE,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO,OAAO,QAAQ,MAAiC,CACpD,QAAQ,GAAG,OAAO,EAAE,CACpB,KAAK,CAAC,OAAO,EAAE,CACf,KAAK,IAAI;AAEd,QAAO;;AAGT,SAAS,eAAe,OAAwB;AAC9C,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,OAAO,UAAU,YAAY,UAAU,KACzC,QAAO,OAAO,QAAQ,MAAiC,CACpD,KAAK,CAAC,GAAG,OAAO,GAAG,QAAQ,EAAE,CAAC,IAAI,IAAI,CACtC,KAAK,KAAK;AAEf,QAAO;;AAGT,SAAS,QAAQ,KAAqB;AACpC,QAAO,IAAI,QAAQ,WAAW,MAAM,IAAI,EAAE,aAAa,GAAG;;AAG5D,MAAM,aAAqC;CACzC,KAAK;CACL,KAAK;CACL,KAAK;CACL,MAAK;CACL,KAAK;CACN;AAGD,MAAM,kBAAkB;AAExB,SAAS,WAAW,KAAqB;AACvC,KAAI,CAAC,gBAAgB,KAAK,IAAI,CAAE,QAAO;AACvC,QAAO,IAAI,QAAQ,aAAa,MAAM,WAAW,MAAM,EAAE;;;;;;;AAQ3D,SAAS,uBAAuB,OAAuC;AACrE,KACE,MAAM,SAAS,SAAS,KACvB,MAAM,MAAkC,aAAa,OAEtD,QAAO;EACL,GAAG,MAAM;EACT,UAAU,MAAM,SAAS,WAAW,IAAI,MAAM,SAAS,KAAK,MAAM;EACnE;AAEH,QAAO,MAAM"}
@@ -113,8 +113,9 @@ async function streamComponentNode(vnode, enqueue) {
113
113
  async function streamElementNode(vnode, enqueue) {
114
114
  const tag = vnode.type;
115
115
  let open = `<${tag}`;
116
- for (const [key, value] of Object.entries(vnode.props)) {
117
- const attr = renderProp(key, value);
116
+ const props = vnode.props;
117
+ for (const key in props) {
118
+ const attr = renderProp(key, props[key]);
118
119
  if (attr) open += ` ${attr}`;
119
120
  }
120
121
  if (isVoidElement(tag)) {
@@ -185,7 +186,11 @@ async function renderNode(node) {
185
186
  if (node == null || node === false) return "";
186
187
  if (typeof node === "string") return escapeHtml(node);
187
188
  if (typeof node === "number" || typeof node === "boolean") return String(node);
188
- if (Array.isArray(node)) return (await Promise.all(node.map(n => renderNode(n)))).join("");
189
+ if (Array.isArray(node)) {
190
+ let html = "";
191
+ for (const child of node) html += await renderNode(child);
192
+ return html;
193
+ }
189
194
  const vnode = node;
190
195
  if (vnode.type === Fragment) return renderChildren(vnode.children);
191
196
  if (vnode.type === ForSymbol) {
@@ -193,13 +198,18 @@ async function renderNode(node) {
193
198
  each,
194
199
  children
195
200
  } = vnode.props;
196
- return `<!--pyreon-for-->${(await Promise.all(each().map(item => renderNode(children(item))))).join("")}<!--/pyreon-for-->`;
201
+ let forHtml = "<!--pyreon-for-->";
202
+ for (const item of each()) forHtml += await renderNode(children(item));
203
+ forHtml += "<!--/pyreon-for-->";
204
+ return forHtml;
197
205
  }
198
206
  if (typeof vnode.type === "function") return renderComponent(vnode);
199
207
  return renderElement(vnode);
200
208
  }
201
209
  async function renderChildren(children) {
202
- return (await Promise.all(children.map(c => renderNode(c)))).join("");
210
+ let html = "";
211
+ for (const child of children) html += await renderNode(child);
212
+ return html;
203
213
  }
204
214
  async function renderComponent(vnode) {
205
215
  const {
@@ -216,8 +226,9 @@ async function renderComponent(vnode) {
216
226
  async function renderElement(vnode) {
217
227
  const tag = vnode.type;
218
228
  let html = `<${tag}`;
219
- for (const [key, value] of Object.entries(vnode.props)) {
220
- const attr = renderProp(key, value);
229
+ const props = vnode.props;
230
+ for (const key in props) {
231
+ const attr = renderProp(key, props[key]);
221
232
  if (attr) html += ` ${attr}`;
222
233
  }
223
234
  if (isVoidElement(tag)) {
@@ -278,6 +289,7 @@ function toKebab(str) {
278
289
  return str.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
279
290
  }
280
291
  function escapeHtml(str) {
292
+ if (!NEEDS_ESCAPE_RE.test(str)) return str;
281
293
  return str.replace(/[&<>"']/g, c => ESCAPE_MAP[c] ?? c);
282
294
  }
283
295
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/runtime-server",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "SSR/SSG renderer for Pyreon — streaming HTML + static generation",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -39,8 +39,8 @@
39
39
  "prepublishOnly": "bun run build"
40
40
  },
41
41
  "dependencies": {
42
- "@pyreon/core": "^0.2.1",
43
- "@pyreon/reactivity": "^0.2.1"
42
+ "@pyreon/core": "^0.3.0",
43
+ "@pyreon/reactivity": "^0.3.0"
44
44
  },
45
45
  "publishConfig": {
46
46
  "access": "public"
package/src/index.ts CHANGED
@@ -161,8 +161,9 @@ async function streamComponentNode(vnode: VNode, enqueue: (s: string) => void):
161
161
  async function streamElementNode(vnode: VNode, enqueue: (s: string) => void): Promise<void> {
162
162
  const tag = vnode.type as string
163
163
  let open = `<${tag}`
164
- for (const [key, value] of Object.entries(vnode.props)) {
165
- const attr = renderProp(key, value)
164
+ const props = vnode.props as Record<string, unknown>
165
+ for (const key in props) {
166
+ const attr = renderProp(key, props[key])
166
167
  if (attr) open += ` ${attr}`
167
168
  }
168
169
  if (isVoidElement(tag)) {
@@ -265,8 +266,9 @@ async function renderNode(node: VNodeChild | (() => VNodeChild)): Promise<string
265
266
  if (typeof node === "number" || typeof node === "boolean") return String(node)
266
267
 
267
268
  if (Array.isArray(node)) {
268
- const parts = await Promise.all(node.map((n) => renderNode(n)))
269
- return parts.join("")
269
+ let html = ""
270
+ for (const child of node) html += await renderNode(child)
271
+ return html
270
272
  }
271
273
 
272
274
  const vnode = node as VNode
@@ -277,9 +279,10 @@ async function renderNode(node: VNodeChild | (() => VNodeChild)): Promise<string
277
279
 
278
280
  if (vnode.type === (ForSymbol as unknown as string)) {
279
281
  const { each, children } = vnode.props as unknown as ForProps<unknown>
280
- const parts = await Promise.all(each().map((item) => renderNode(children(item) as VNodeChild)))
281
- // Hydration markers so the client can claim existing For-rendered children
282
- return `<!--pyreon-for-->${parts.join("")}<!--/pyreon-for-->`
282
+ let forHtml = "<!--pyreon-for-->"
283
+ for (const item of each()) forHtml += await renderNode(children(item) as VNodeChild)
284
+ forHtml += "<!--/pyreon-for-->"
285
+ return forHtml
283
286
  }
284
287
 
285
288
  if (typeof vnode.type === "function") {
@@ -290,8 +293,9 @@ async function renderNode(node: VNodeChild | (() => VNodeChild)): Promise<string
290
293
  }
291
294
 
292
295
  async function renderChildren(children: VNodeChild[]): Promise<string> {
293
- const parts = await Promise.all(children.map((c) => renderNode(c)))
294
- return parts.join("")
296
+ let html = ""
297
+ for (const child of children) html += await renderNode(child)
298
+ return html
295
299
  }
296
300
 
297
301
  async function renderComponent(vnode: VNode & { type: ComponentFn }): Promise<string> {
@@ -312,8 +316,9 @@ async function renderElement(vnode: VNode): Promise<string> {
312
316
  const tag = vnode.type as string
313
317
  let html = `<${tag}`
314
318
 
315
- for (const [key, value] of Object.entries(vnode.props)) {
316
- const attr = renderProp(key, value)
319
+ const props = vnode.props as Record<string, unknown>
320
+ for (const key in props) {
321
+ const attr = renderProp(key, props[key])
317
322
  if (attr) html += ` ${attr}`
318
323
  }
319
324
 
@@ -437,7 +442,11 @@ const ESCAPE_MAP: Record<string, string> = {
437
442
  "'": "&#39;",
438
443
  }
439
444
 
445
+ // Fast test — most strings in SSR have no special chars (tag names, class names, etc.)
446
+ const NEEDS_ESCAPE_RE = /[&<>"']/
447
+
440
448
  function escapeHtml(str: string): string {
449
+ if (!NEEDS_ESCAPE_RE.test(str)) return str
441
450
  return str.replace(/[&<>"']/g, (c) => ESCAPE_MAP[c] ?? c)
442
451
  }
443
452