@oomfware/jsx 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as FC, i as Component, o as JSXElement, r as JSX, s as JSXNode, t as Fragment } from "./jsx-runtime-CpxZaJu6.mjs";
1
+ import { a as SVGAttributes, c as JSXElement, i as JSX, l as JSXNode, o as Component, r as HTMLAttributes, s as FC, t as Fragment } from "./jsx-runtime-CcUWZKzW.mjs";
2
2
 
3
3
  //#region src/lib/create-element.d.ts
4
4
 
@@ -89,6 +89,16 @@ interface SuspenseProps {
89
89
  declare function Suspense({
90
90
  children
91
91
  }: SuspenseProps): JSXElement;
92
+ interface ErrorBoundaryProps {
93
+ fallback: (error: unknown) => JSXNode;
94
+ children?: JSXNode;
95
+ }
96
+ /**
97
+ * error boundary - catches render errors and displays fallback
98
+ */
99
+ declare function ErrorBoundary({
100
+ children
101
+ }: ErrorBoundaryProps): JSXElement;
92
102
  /**
93
103
  * reads a context value or suspends until a promise resolves
94
104
  * @param usable context or promise
@@ -124,5 +134,5 @@ declare function renderToString(node: JSXNode, options?: RenderOptions): Promise
124
134
  */
125
135
  declare function render(node: JSXNode, init?: ResponseInit): Response;
126
136
  //#endregion
127
- export { type Component, type Context, type FC, Fragment, type JSXElement, type JSXNode, type RenderOptions, Suspense, type SuspenseProps, cloneElement, createContext, createElement, createElement as h, render, renderToStream, renderToString, use };
137
+ export { type Component, type Context, ErrorBoundary, type ErrorBoundaryProps, type FC, Fragment, type HTMLAttributes, type JSX, type JSXElement, type JSXNode, type RenderOptions, type SVGAttributes, Suspense, type SuspenseProps, cloneElement, createContext, createElement, createElement as h, render, renderToStream, renderToString, use };
128
138
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/lib/create-element.ts","../src/lib/context.ts","../src/lib/suspense.ts","../src/lib/render.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/lib/create-element.ts","../src/lib/context.ts","../src/lib/suspense.ts","../src/lib/render.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Fragment, jsx } from "./jsx-runtime.mjs";
2
+ import { decodeUtf8From, encodeUtf8 } from "@atcute/uint8array";
2
3
 
3
4
  //#region src/lib/create-element.ts
4
5
  function createElement(type, props, ...children) {
@@ -24,58 +25,82 @@ function cloneElement(element, props, ...children) {
24
25
  }
25
26
 
26
27
  //#endregion
27
- //#region src/lib/context.ts
28
- /** internal provider component */
29
- function Provider({ context, value, children }) {
30
- provide(context, value);
31
- return jsx(Fragment, { children });
32
- }
33
- function createContext(defaultValue) {
34
- const context = {
35
- defaultValue,
36
- Provider: ({ value, children }) => Provider({
37
- context,
38
- value,
39
- children
40
- })
41
- };
42
- return context;
28
+ //#region src/lib/render-context.ts
29
+ /** active render context (set by renderer) */
30
+ let activeRenderContext = null;
31
+ /**
32
+ * sets the active render context
33
+ * @param ctx render context to activate, or null to clear
34
+ * @returns the previous render context
35
+ */
36
+ function setActiveRenderContext(ctx) {
37
+ const prev = activeRenderContext;
38
+ activeRenderContext = ctx;
39
+ return prev;
43
40
  }
44
- const contextStack = [];
45
- /** current frame being built (lazily initialized on first provide) */
46
- let currentFrame = null;
47
41
  /**
48
42
  * provides a value for the context during the current component's render
49
43
  * @param context context key from createContext()
50
44
  * @param value value to provide
51
45
  */
52
46
  function provide(context, value) {
53
- if (!currentFrame) {
54
- const prev = contextStack[contextStack.length - 1];
55
- currentFrame = prev ? new Map(prev) : /* @__PURE__ */ new Map();
47
+ const ctx = activeRenderContext;
48
+ if (!ctx.currentFrame) {
49
+ const prev = ctx.contextStack[ctx.contextStack.length - 1];
50
+ ctx.currentFrame = prev ? new Map(prev) : /* @__PURE__ */ new Map();
56
51
  }
57
- currentFrame.set(context, value);
52
+ ctx.currentFrame.set(context, value);
58
53
  }
59
54
  /**
60
55
  * returns current provided value, or the default value
61
56
  * @param context context key from createContext()
62
57
  */
63
58
  function inject(context) {
64
- const frame = currentFrame ?? contextStack[contextStack.length - 1];
59
+ const ctx = activeRenderContext;
60
+ const frame = ctx.currentFrame ?? ctx.contextStack[ctx.contextStack.length - 1];
65
61
  if (frame?.has(context)) return frame.get(context);
66
62
  return context.defaultValue;
67
63
  }
68
- /** push current frame to stack (called before rendering children) */
64
+ /**
65
+ * pushes current frame to stack (called before rendering children)
66
+ * @returns whether a frame was pushed (needed for popContextFrame)
67
+ */
69
68
  function pushContextFrame() {
70
- if (currentFrame) {
71
- contextStack.push(currentFrame);
72
- currentFrame = null;
69
+ const ctx = activeRenderContext;
70
+ if (ctx.currentFrame) {
71
+ ctx.contextStack.push(ctx.currentFrame);
72
+ ctx.currentFrame = null;
73
+ return true;
73
74
  }
75
+ return false;
74
76
  }
75
- /** pop context frame (called after rendering children) */
77
+ /**
78
+ * pops context frame (called after rendering children)
79
+ * @param hadFrame whether pushContextFrame returned true
80
+ */
76
81
  function popContextFrame(hadFrame) {
77
- if (hadFrame) contextStack.pop();
78
- currentFrame = null;
82
+ const ctx = activeRenderContext;
83
+ if (hadFrame) ctx.contextStack.pop();
84
+ ctx.currentFrame = null;
85
+ }
86
+
87
+ //#endregion
88
+ //#region src/lib/context.ts
89
+ /** internal provider component */
90
+ function Provider({ context, value, children }) {
91
+ provide(context, value);
92
+ return jsx(Fragment, { children });
93
+ }
94
+ function createContext(defaultValue) {
95
+ const context = {
96
+ defaultValue,
97
+ Provider: ({ value, children }) => Provider({
98
+ context,
99
+ value,
100
+ children
101
+ })
102
+ };
103
+ return context;
79
104
  }
80
105
 
81
106
  //#endregion
@@ -86,6 +111,12 @@ function popContextFrame(hadFrame) {
86
111
  function Suspense({ children }) {
87
112
  return jsx(Fragment, { children });
88
113
  }
114
+ /**
115
+ * error boundary - catches render errors and displays fallback
116
+ */
117
+ function ErrorBoundary({ children }) {
118
+ return jsx(Fragment, { children });
119
+ }
89
120
  /** cache for resolved/rejected promise values */
90
121
  const promiseCache = /* @__PURE__ */ new WeakMap();
91
122
  function isContext(value) {
@@ -125,6 +156,7 @@ const HEAD_ELEMENTS = new Set([
125
156
  "link",
126
157
  "style"
127
158
  ]);
159
+ const MAX_SUSPENSE_ATTEMPTS = 20;
128
160
  const SELF_CLOSING_TAGS = new Set([
129
161
  "area",
130
162
  "base",
@@ -163,9 +195,10 @@ const EMPTY_SEGMENT = staticSeg("");
163
195
  * @returns readable stream of UTF-8 encoded HTML
164
196
  */
165
197
  function renderToStream(node, options) {
166
- const encoder = new TextEncoder();
167
198
  const onError = options?.onError ?? ((error) => console.error(error));
168
199
  const context = {
200
+ contextStack: [],
201
+ currentFrame: null,
169
202
  headElements: [],
170
203
  idsByPath: /* @__PURE__ */ new Map(),
171
204
  insideHead: false,
@@ -178,8 +211,8 @@ function renderToStream(node, options) {
178
211
  const root = buildSegment(node, context, "");
179
212
  await resolveBlocking(root);
180
213
  const finalHtml = finalizeHtml(serializeSegment(root), context);
181
- controller.enqueue(encoder.encode(finalHtml));
182
- if (context.pendingSuspense.length > 0) await streamPendingSuspense(context, controller, encoder);
214
+ controller.enqueue(encodeUtf8(finalHtml));
215
+ if (context.pendingSuspense.length > 0) await streamPendingSuspense(context, controller);
183
216
  controller.close();
184
217
  } catch (error) {
185
218
  onError(error);
@@ -195,12 +228,11 @@ function renderToStream(node, options) {
195
228
  */
196
229
  async function renderToString(node, options) {
197
230
  const reader = renderToStream(node, options).getReader();
198
- const decoder = new TextDecoder();
199
231
  let html = "";
200
232
  while (true) {
201
233
  const { done, value } = await reader.read();
202
234
  if (done) break;
203
- html += decoder.decode(value);
235
+ html += decodeUtf8From(value);
204
236
  }
205
237
  return html;
206
238
  }
@@ -225,19 +257,27 @@ function isJSXElement(node) {
225
257
  function isHeadElement(tag) {
226
258
  return HEAD_ELEMENTS.has(tag);
227
259
  }
228
- function buildSegment(node, context, path) {
260
+ function buildSegment(node, ctx, path) {
261
+ const prev = setActiveRenderContext(ctx);
262
+ try {
263
+ return buildSegmentInner(node, ctx, path);
264
+ } finally {
265
+ setActiveRenderContext(prev);
266
+ }
267
+ }
268
+ function buildSegmentInner(node, context, path) {
229
269
  if (typeof node === "string" || typeof node === "number" || typeof node === "bigint") return staticSeg(escapeHtml(node, false));
230
270
  if (node === null || node === void 0 || typeof node === "boolean") return EMPTY_SEGMENT;
231
271
  if (typeof node === "object" && Symbol.iterator in node) {
232
272
  const parts = [];
233
- for (const child of node) parts.push(buildSegment(child, context, path));
273
+ for (const child of node) parts.push(buildSegmentInner(child, context, path));
234
274
  return compositeSeg(parts);
235
275
  }
236
276
  if (isJSXElement(node)) {
237
277
  const { type, props } = node;
238
278
  if (type === Fragment) {
239
279
  const children = props.children;
240
- return children != null ? buildSegment(children, context, path) : EMPTY_SEGMENT;
280
+ return children != null ? buildSegmentInner(children, context, path) : EMPTY_SEGMENT;
241
281
  }
242
282
  if (typeof type === "string") {
243
283
  const tag = type;
@@ -251,6 +291,7 @@ function buildSegment(node, context, path) {
251
291
  }
252
292
  if (typeof type === "function") {
253
293
  if (type === Suspense) return buildSuspenseSegment(props, context, path);
294
+ if (type === ErrorBoundary) return buildErrorBoundarySegment(props, context, path);
254
295
  return buildComponentSegment(type, props, context, path);
255
296
  }
256
297
  }
@@ -313,10 +354,9 @@ function serializeStyle(style) {
313
354
  }
314
355
  function buildComponentSegment(type, props, ctx, path) {
315
356
  const result = type(props);
316
- const hadFrame = currentFrame !== null;
317
- pushContextFrame();
357
+ const hadFrame = pushContextFrame();
318
358
  try {
319
- return buildSegment(result, ctx, path);
359
+ return buildSegmentInner(result, ctx, path);
320
360
  } finally {
321
361
  popContextFrame(hadFrame);
322
362
  }
@@ -335,20 +375,54 @@ function buildSuspenseSegment(props, ctx, path) {
335
375
  fallback: buildSegment(props.fallback, ctx, suspenseId),
336
376
  content: null
337
377
  };
338
- const pending = thrown.then(() => {
339
- seg.content = buildSegment(props.children, ctx, suspenseId);
340
- });
378
+ const asyncCtx = {
379
+ ...ctx,
380
+ contextStack: [...ctx.contextStack],
381
+ currentFrame: null
382
+ };
383
+ const rerender = (attempt) => {
384
+ if (attempt >= MAX_SUSPENSE_ATTEMPTS) throw new Error(`suspense boundary exceeded maximum retry attempts (${MAX_SUSPENSE_ATTEMPTS})`);
385
+ try {
386
+ seg.content = buildSegment(props.children, asyncCtx, suspenseId);
387
+ } catch (err) {
388
+ if (err instanceof Promise) return err.then(() => rerender(attempt + 1));
389
+ throw err;
390
+ }
391
+ };
392
+ const pending = thrown.then(() => rerender(1));
341
393
  seg.pending = pending;
394
+ const tracked = pending.then(() => seg.content);
395
+ tracked.catch(() => {});
342
396
  ctx.pendingSuspense.push({
343
397
  id: suspenseId,
344
- promise: pending.then(() => seg.content)
398
+ promise: tracked
345
399
  });
346
400
  return seg;
347
401
  }
348
402
  throw thrown;
349
403
  }
350
404
  }
351
- /** resolve all blocking suspense boundaries */
405
+ function buildErrorBoundarySegment(props, ctx, path) {
406
+ const asyncCtx = {
407
+ ...ctx,
408
+ contextStack: [...ctx.contextStack],
409
+ currentFrame: null
410
+ };
411
+ try {
412
+ return {
413
+ kind: "error-boundary",
414
+ children: buildSegment(props.children, ctx, path),
415
+ fallbackFn: props.fallback,
416
+ renderContext: asyncCtx,
417
+ path,
418
+ fallbackSegment: null
419
+ };
420
+ } catch (error) {
421
+ if (error instanceof Promise) throw error;
422
+ return buildSegment(props.fallback(error), ctx, path);
423
+ }
424
+ }
425
+ /** resolve all blocking suspense boundaries and error boundaries */
352
426
  async function resolveBlocking(segment) {
353
427
  if (segment.kind === "suspense") {
354
428
  if (segment.pending) {
@@ -358,33 +432,44 @@ async function resolveBlocking(segment) {
358
432
  if (segment.content) await resolveBlocking(segment.content);
359
433
  return;
360
434
  }
435
+ if (segment.kind === "error-boundary") {
436
+ try {
437
+ await resolveBlocking(segment.children);
438
+ } catch (error) {
439
+ segment.fallbackSegment = buildSegment(segment.fallbackFn(error), segment.renderContext, segment.path);
440
+ }
441
+ return;
442
+ }
361
443
  if (segment.kind === "composite") for (const part of segment.parts) await resolveBlocking(part);
362
444
  }
363
445
  /** serialize segment tree to HTML string */
364
446
  function serializeSegment(seg) {
365
447
  if (seg.kind === "static") return seg.html;
366
448
  if (seg.kind === "composite") return seg.parts.map(serializeSegment).join("");
449
+ if (seg.kind === "error-boundary") return serializeSegment(seg.fallbackSegment ?? seg.children);
367
450
  return `<!--$s:${seg.id}-->${serializeSegment(seg.fallback)}<!--/$s:${seg.id}-->`;
368
451
  }
369
452
  /** suspense runtime function name */
370
453
  const SR = "$sr";
371
454
  /** suspense runtime - injected once, swaps template content with fallback */
372
455
  const SUSPENSE_RUNTIME = `<script>${SR}=(t,i,s,e)=>{i="$s:"+t.dataset.suspense;s=document.createTreeWalker(document,128);while(e=s.nextNode())if(e.data===i){while(e.nextSibling?.data!=="/"+i)e.nextSibling.remove();e.nextSibling.replaceWith(...t.content.childNodes);e.remove();break}t.remove()}<\/script>`;
373
- async function streamPendingSuspense(context, controller, encoder) {
374
- let runtimeInjected = false;
375
- const processed = /* @__PURE__ */ new Set();
456
+ async function streamPendingSuspense(context, controller) {
457
+ controller.enqueue(encodeUtf8(SUSPENSE_RUNTIME));
376
458
  while (true) {
377
- const batch = context.pendingSuspense.filter(({ id }) => !processed.has(id));
459
+ const batch = context.pendingSuspense;
378
460
  if (batch.length === 0) break;
461
+ context.pendingSuspense = [];
379
462
  await Promise.all(batch.map(async ({ id, promise }) => {
380
- processed.add(id);
463
+ let resolvedSegment;
464
+ try {
465
+ resolvedSegment = await promise;
466
+ } catch {
467
+ return;
468
+ }
381
469
  try {
382
- const resolvedSegment = await promise;
383
470
  await resolveBlocking(resolvedSegment);
384
471
  const html = serializeSegment(resolvedSegment);
385
- const runtime = runtimeInjected ? "" : SUSPENSE_RUNTIME;
386
- runtimeInjected = true;
387
- controller.enqueue(encoder.encode(`${runtime}<template data-suspense="${id}">${html}</template><script>${SR}(document.currentScript.previousElementSibling)<\/script>`));
472
+ controller.enqueue(encodeUtf8(`<template data-suspense="${id}">${html}</template><script>${SR}(document.currentScript.previousElementSibling)<\/script>`));
388
473
  } catch (error) {
389
474
  context.onError(error);
390
475
  }
@@ -428,5 +513,5 @@ function finalizeHtml(html, context) {
428
513
  }
429
514
 
430
515
  //#endregion
431
- export { Fragment, Suspense, cloneElement, createContext, createElement, createElement as h, render, renderToStream, renderToString, use };
516
+ export { ErrorBoundary, Fragment, Suspense, cloneElement, createContext, createElement, createElement as h, render, renderToStream, renderToString, use };
432
517
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["finalProps: Record<string, unknown>","context: Context<T | undefined>","contextStack: ContextFrame[]","currentFrame: ContextFrame | null","context: RenderContext","parts: Segment[]","parts: string[]","seg: Segment"],"sources":["../src/lib/create-element.ts","../src/lib/context.ts","../src/lib/suspense.ts","../src/lib/render.ts"],"sourcesContent":["import type { JSX } from './intrinsic-elements.ts';\nimport type { Component, JSXElement, JSXNode } from './types.ts';\n\n// #region createElement\n\n/**\n * creates a JSX element for an intrinsic element\n * @param type element tag name\n * @param props element properties\n * @param children child elements\n * @returns JSX element\n */\nexport function createElement<T extends keyof JSX.IntrinsicElements>(\n\ttype: T,\n\tprops?: JSX.IntrinsicElements[T] | null,\n\t...children: JSXNode[]\n): JSXElement<JSX.IntrinsicElements[T], T>;\n\n/**\n * creates a JSX element for a function component\n * @param type component function\n * @param props component properties\n * @param children child elements\n * @returns JSX element\n */\nexport function createElement<P extends {}>(\n\ttype: Component<P>,\n\tprops?: P | null,\n\t...children: JSXNode[]\n): JSXElement<P, Component<P>>;\n\n/**\n * creates a JSX element (classic API)\n * @param type element tag name or component function\n * @param props element properties\n * @param children child elements\n * @returns JSX element\n */\nexport function createElement<P extends {}>(\n\ttype: string | Component<P>,\n\tprops?: P | null,\n\t...children: JSXNode[]\n): JSXElement<P>;\n\nexport function createElement(\n\ttype: string | Component<any>,\n\tprops?: Record<string, unknown> | null,\n\t...children: JSXNode[]\n): JSXElement {\n\tconst finalProps: Record<string, unknown> = { ...props };\n\n\tif (children.length === 1) {\n\t\tfinalProps.children = children[0];\n\t} else if (children.length > 1) {\n\t\tfinalProps.children = children;\n\t}\n\n\treturn { type, props: finalProps };\n}\n\n// #endregion\n\n// #region cloneElement\n\n/**\n * clones a JSX element for an intrinsic element with new props\n * @param element element to clone\n * @param props props to merge (overrides original)\n * @param children children to replace (if provided)\n * @returns cloned JSX element\n */\nexport function cloneElement<T extends keyof JSX.IntrinsicElements>(\n\telement: JSXElement<JSX.IntrinsicElements[T], T>,\n\tprops?: Partial<JSX.IntrinsicElements[T]> | null,\n\t...children: JSXNode[]\n): JSXElement<JSX.IntrinsicElements[T], T>;\n\n/**\n * clones a JSX element for a function component with new props\n * @param element element to clone\n * @param props props to merge (overrides original)\n * @param children children to replace (if provided)\n * @returns cloned JSX element\n */\nexport function cloneElement<P>(\n\telement: JSXElement<P, Component<P>>,\n\tprops?: Partial<P> | null,\n\t...children: JSXNode[]\n): JSXElement<P, Component<P>>;\n\n/**\n * clones a JSX element with new props\n * @param element element to clone\n * @param props props to merge (overrides original)\n * @param children children to replace (if provided)\n * @returns cloned JSX element\n */\nexport function cloneElement<P>(\n\telement: JSXElement<P>,\n\tprops?: Partial<P> | null,\n\t...children: JSXNode[]\n): JSXElement<P>;\n\nexport function cloneElement(\n\telement: JSXElement,\n\tprops?: Record<string, unknown> | null,\n\t...children: JSXNode[]\n): JSXElement {\n\tconst finalProps: Record<string, unknown> = { ...(element.props as Record<string, unknown>), ...props };\n\n\tif (children.length === 1) {\n\t\tfinalProps.children = children[0];\n\t} else if (children.length > 1) {\n\t\tfinalProps.children = children;\n\t}\n\n\treturn { type: element.type, props: finalProps };\n}\n\n// #endregion\n","import { Fragment, jsx } from '../jsx-runtime.ts';\n\nimport type { JSXElement, JSXNode } from './types.ts';\n\n/** context object returned by createContext() */\nexport interface Context<T> {\n\tdefaultValue: T;\n\tProvider: (props: { value: T; children?: JSXNode }) => JSXElement;\n}\n\n/** internal provider props */\ninterface ProviderProps<T> {\n\tcontext: Context<T>;\n\tvalue: T;\n\tchildren?: JSXNode;\n}\n\n/** internal provider component */\nfunction Provider<T>({ context, value, children }: ProviderProps<T>): JSXElement {\n\tprovide(context, value);\n\treturn jsx(Fragment, { children });\n}\n\n/**\n * creates a context with a Provider component\n * @param defaultValue value returned by use() when no Provider is above\n * @example\n * const ThemeContext = createContext('light');\n *\n * <ThemeContext.Provider value=\"dark\">\n * <App />\n * </ThemeContext.Provider>\n *\n * function App() {\n * const theme = use(ThemeContext);\n * return <div>{theme}</div>;\n * }\n */\nexport function createContext<T>(defaultValue: T): Context<T>;\nexport function createContext<T>(): Context<T | undefined>;\nexport function createContext<T>(defaultValue?: T): Context<T | undefined> {\n\tconst context: Context<T | undefined> = {\n\t\tdefaultValue,\n\t\tProvider: ({ value, children }) => Provider({ context, value, children }),\n\t};\n\n\treturn context;\n}\n\n/** stack of context frames */\ntype ContextFrame = Map<Context<unknown>, unknown>;\nconst contextStack: ContextFrame[] = [];\n\n/** current frame being built (lazily initialized on first provide) */\nexport let currentFrame: ContextFrame | null = null;\n\n/**\n * provides a value for the context during the current component's render\n * @param context context key from createContext()\n * @param value value to provide\n */\nexport function provide<T>(context: Context<T>, value: T): void {\n\tif (!currentFrame) {\n\t\t// lazily create frame, copying from previous\n\t\tconst prev = contextStack[contextStack.length - 1];\n\t\tcurrentFrame = prev ? new Map(prev) : new Map();\n\t}\n\tcurrentFrame.set(context as Context<unknown>, value);\n}\n\n/**\n * returns current provided value, or the default value\n * @param context context key from createContext()\n */\nexport function inject<T>(context: Context<T>): T {\n\t// check current frame first, then stack\n\tconst frame = currentFrame ?? contextStack[contextStack.length - 1];\n\tif (frame?.has(context as Context<unknown>)) {\n\t\treturn frame.get(context as Context<unknown>) as T;\n\t}\n\treturn context.defaultValue;\n}\n\n/** push current frame to stack (called before rendering children) */\nexport function pushContextFrame(): void {\n\tif (currentFrame) {\n\t\tcontextStack.push(currentFrame);\n\t\tcurrentFrame = null;\n\t}\n}\n\n/** pop context frame (called after rendering children) */\nexport function popContextFrame(hadFrame: boolean): void {\n\tif (hadFrame) {\n\t\tcontextStack.pop();\n\t}\n\tcurrentFrame = null;\n}\n","import { Fragment, jsx } from '../jsx-runtime.js';\n\nimport { inject, type Context } from './context.js';\nimport type { JSXElement, JSXNode } from './types.js';\n\nexport interface SuspenseProps {\n\tfallback: JSXNode;\n\tchildren?: JSXNode;\n}\n\n/**\n * suspense boundary - renders fallback while children are suspended\n */\nexport function Suspense({ children }: SuspenseProps): JSXElement {\n\t// Suspense is handled specially in buildSegment, this is just for typing\n\treturn jsx(Fragment, { children });\n}\n\n/** cache for resolved/rejected promise values */\nconst promiseCache = new WeakMap<\n\tPromise<unknown>,\n\t{ resolved: true; value: unknown } | { resolved: false; error: unknown }\n>();\n\nfunction isContext<T>(value: unknown): value is Context<T> {\n\treturn typeof value === 'object' && value !== null && 'defaultValue' in value && 'Provider' in value;\n}\n\n/**\n * reads a context value or suspends until a promise resolves\n * @param usable context or promise\n * @returns context value or resolved promise value\n * @throws promise if not yet resolved, or error if rejected\n */\nexport function use<T>(usable: Context<T>): T;\nexport function use<T>(usable: Promise<T>): T;\nexport function use<T>(usable: Context<T> | Promise<T>): T {\n\t// context\n\tif (isContext<T>(usable)) {\n\t\treturn inject(usable);\n\t}\n\t// promise\n\tconst cached = promiseCache.get(usable);\n\tif (cached) {\n\t\tif (cached.resolved) {\n\t\t\treturn cached.value as T;\n\t\t} else {\n\t\t\tthrow cached.error;\n\t\t}\n\t}\n\t// not cached yet - set up caching and throw\n\tusable.then(\n\t\t(value) => promiseCache.set(usable, { resolved: true, value }),\n\t\t(error) => promiseCache.set(usable, { resolved: false, error }),\n\t);\n\tthrow usable;\n}\n","/**\n * streaming JSX renderer\n *\n * architecture:\n * - segment tree: we build a tree of segments (static text, composites, suspense\n * boundaries) then serialize to HTML\n * - suspense: components can throw promises via use(), caught at Suspense boundaries\n * which render fallback immediately and stream resolved content later\n * - head hoisting: <title>, <meta>, <link>, <style> found outside <head> are\n * collected and injected into <head> during finalization\n */\n\nimport { Fragment } from '../jsx-runtime.ts';\n\nimport { currentFrame, popContextFrame, pushContextFrame } from './context.ts';\nimport { Suspense, type SuspenseProps } from './suspense.ts';\nimport type { Component, JSXElement, JSXNode } from './types.ts';\n\nconst HEAD_ELEMENTS = new Set(['title', 'meta', 'link', 'style']);\nconst SELF_CLOSING_TAGS = new Set([\n\t'area',\n\t'base',\n\t'br',\n\t'col',\n\t'embed',\n\t'hr',\n\t'img',\n\t'input',\n\t'link',\n\t'meta',\n\t'param',\n\t'source',\n\t'track',\n\t'wbr',\n]);\n/** props that shouldn't be rendered as HTML attributes */\nconst FRAMEWORK_PROPS = new Set(['children', 'dangerouslySetInnerHTML']);\n\n// #region Segment types\n\ntype Segment =\n\t| {\n\t\t\treadonly kind: 'static';\n\t\t\treadonly html: string;\n\t }\n\t| {\n\t\t\treadonly kind: 'composite';\n\t\t\treadonly parts: readonly Segment[];\n\t }\n\t| {\n\t\t\treadonly kind: 'suspense';\n\t\t\treadonly id: string;\n\t\t\treadonly fallback: Segment;\n\t\t\tpending?: Promise<void>;\n\t\t\tcontent: Segment | null;\n\t };\n\nfunction staticSeg(html: string): Segment {\n\treturn { kind: 'static', html };\n}\n\nfunction compositeSeg(parts: Segment[]): Segment {\n\treturn { kind: 'composite', parts };\n}\n\nconst EMPTY_SEGMENT = staticSeg('');\n\n// #endregion\n\nexport interface RenderOptions {\n\tonError?: (error: unknown) => void;\n}\n\ninterface RenderContext {\n\theadElements: string[];\n\tidsByPath: Map<string, number>;\n\tinsideHead: boolean;\n\tinsideSvg: boolean;\n\tonError: (error: unknown) => void;\n\tpendingSuspense: Array<{ id: string; promise: Promise<Segment> }>;\n}\n\n/**\n * renders JSX to a readable stream\n * @param node JSX node to render\n * @param options render options\n * @returns readable stream of UTF-8 encoded HTML\n */\nexport function renderToStream(node: JSXNode, options?: RenderOptions): ReadableStream<Uint8Array> {\n\tconst encoder = new TextEncoder();\n\tconst onError = options?.onError ?? ((error) => console.error(error));\n\tconst context: RenderContext = {\n\t\theadElements: [],\n\t\tidsByPath: new Map(),\n\t\tinsideHead: false,\n\t\tinsideSvg: false,\n\t\tonError,\n\t\tpendingSuspense: [],\n\t};\n\treturn new ReadableStream({\n\t\tasync start(controller) {\n\t\t\ttry {\n\t\t\t\tconst root = buildSegment(node, context, '');\n\t\t\t\tawait resolveBlocking(root);\n\t\t\t\tconst html = serializeSegment(root);\n\t\t\t\tconst finalHtml = finalizeHtml(html, context);\n\t\t\t\tcontroller.enqueue(encoder.encode(finalHtml));\n\t\t\t\t// stream pending suspense boundaries as they resolve\n\t\t\t\tif (context.pendingSuspense.length > 0) {\n\t\t\t\t\tawait streamPendingSuspense(context, controller, encoder);\n\t\t\t\t}\n\t\t\t\tcontroller.close();\n\t\t\t} catch (error) {\n\t\t\t\tonError(error);\n\t\t\t\tcontroller.error(error);\n\t\t\t}\n\t\t},\n\t});\n}\n\n/**\n * renders JSX to a string (non-streaming)\n * @param node JSX node to render\n * @param options render options\n * @returns promise resolving to HTML string\n */\nexport async function renderToString(node: JSXNode, options?: RenderOptions): Promise<string> {\n\tconst stream = renderToStream(node, options);\n\tconst reader = stream.getReader();\n\tconst decoder = new TextDecoder();\n\tlet html = '';\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) break;\n\t\thtml += decoder.decode(value);\n\t}\n\treturn html;\n}\n\n/**\n * renders JSX to a streaming Response\n * @param node JSX node to render\n * @param init optional ResponseInit (status, headers, etc.)\n * @returns Response with streaming HTML body\n */\nexport function render(node: JSXNode, init?: ResponseInit): Response {\n\tconst stream = renderToStream(node);\n\n\t// @ts-expect-error: not sure why.\n\tconst headers = new Headers(init?.headers);\n\tif (!headers.has('Content-Type')) {\n\t\theaders.set('Content-Type', 'text/html; charset=utf-8');\n\t}\n\n\treturn new Response(stream, { ...init, headers });\n}\n\n// #region Segment building\n\nfunction isJSXElement(node: unknown): node is JSXElement {\n\treturn typeof node === 'object' && node !== null && 'type' in node && 'props' in node;\n}\n\nfunction isHeadElement(tag: string): boolean {\n\treturn HEAD_ELEMENTS.has(tag);\n}\n\nfunction buildSegment(node: JSXNode, context: RenderContext, path: string): Segment {\n\t// primitives\n\tif (typeof node === 'string' || typeof node === 'number' || typeof node === 'bigint') {\n\t\treturn staticSeg(escapeHtml(node, false));\n\t}\n\tif (node === null || node === undefined || typeof node === 'boolean') {\n\t\treturn EMPTY_SEGMENT;\n\t}\n\t// iterables (arrays, generators, etc.)\n\tif (typeof node === 'object' && Symbol.iterator in node) {\n\t\tconst parts: Segment[] = [];\n\t\tfor (const child of node) {\n\t\t\tparts.push(buildSegment(child, context, path));\n\t\t}\n\t\treturn compositeSeg(parts);\n\t}\n\t// JSX elements\n\tif (isJSXElement(node)) {\n\t\tconst { type, props } = node;\n\t\t// Fragment\n\t\tif (type === Fragment) {\n\t\t\tconst children = (props as { children?: JSXNode }).children;\n\t\t\treturn children != null ? buildSegment(children, context, path) : EMPTY_SEGMENT;\n\t\t}\n\t\t// intrinsic elements (HTML tags)\n\t\tif (typeof type === 'string') {\n\t\t\tconst tag = type;\n\n\t\t\tif (tag === 'head') {\n\t\t\t\treturn buildHeadElementSegment(tag, props as Record<string, unknown>, context, path);\n\t\t\t}\n\n\t\t\tif (!context.insideHead && isHeadElement(tag)) {\n\t\t\t\t// hoist to <head>\n\t\t\t\tconst elementSeg = buildElementSegment(tag, props as Record<string, unknown>, context, path);\n\t\t\t\tcontext.headElements.push(serializeSegment(elementSeg));\n\t\t\t\treturn EMPTY_SEGMENT;\n\t\t\t}\n\n\t\t\treturn buildElementSegment(tag, props as Record<string, unknown>, context, path);\n\t\t}\n\t\t// function components\n\t\tif (typeof type === 'function') {\n\t\t\t// Suspense boundary\n\t\t\tif (type === Suspense) {\n\t\t\t\treturn buildSuspenseSegment(props as unknown as SuspenseProps, context, path);\n\t\t\t}\n\t\t\treturn buildComponentSegment(type, props as Record<string, unknown>, context, path);\n\t\t}\n\t}\n\treturn EMPTY_SEGMENT;\n}\n\n// #endregion\n\n// #region Element building\n\nfunction buildElementSegment(\n\ttag: string,\n\tprops: Record<string, unknown>,\n\tcontext: RenderContext,\n\tpath: string,\n): Segment {\n\tconst currentIsSvg = context.insideSvg || tag === 'svg';\n\tconst attrs = renderAttributes(props);\n\t// self-closing tags\n\tif (SELF_CLOSING_TAGS.has(tag)) {\n\t\treturn staticSeg(`<${tag}${attrs}>`);\n\t}\n\t// dangerouslySetInnerHTML\n\tconst innerHTML = props.dangerouslySetInnerHTML as { __html: string } | undefined;\n\tif (innerHTML) {\n\t\treturn staticSeg(`<${tag}${attrs}>${innerHTML.__html}</${tag}>`);\n\t}\n\t// normal element with children\n\tconst open = staticSeg(`<${tag}${attrs}>`);\n\tconst previousInsideSvg = context.insideSvg;\n\tcontext.insideSvg = tag === 'foreignObject' ? false : currentIsSvg;\n\tconst children =\n\t\tprops.children != null ? buildSegment(props.children as JSXNode, context, path) : EMPTY_SEGMENT;\n\tcontext.insideSvg = previousInsideSvg;\n\tconst close = staticSeg(`</${tag}>`);\n\treturn compositeSeg([open, children, close]);\n}\n\nfunction buildHeadElementSegment(\n\ttag: string,\n\tprops: Record<string, unknown>,\n\tcontext: RenderContext,\n\tpath: string,\n): Segment {\n\tconst attrs = renderAttributes(props);\n\tconst previousInsideHead = context.insideHead;\n\tcontext.insideHead = true;\n\tconst open = staticSeg(`<${tag}${attrs}>`);\n\tconst children =\n\t\tprops.children != null ? buildSegment(props.children as JSXNode, context, path) : EMPTY_SEGMENT;\n\tcontext.insideHead = previousInsideHead;\n\tconst close = staticSeg(`</${tag}>`);\n\treturn compositeSeg([open, children, close]);\n}\n\nfunction renderAttributes(props: Record<string, unknown>): string {\n\tlet attrs = '';\n\tfor (const key in props) {\n\t\tif (FRAMEWORK_PROPS.has(key)) continue;\n\t\tconst value = props[key];\n\t\tif (value === undefined || value === null || value === false) continue;\n\t\tif (typeof value === 'function') continue;\n\t\t// style object -> string\n\t\tif (key === 'style' && typeof value === 'object') {\n\t\t\tconst styleStr = serializeStyle(value as Record<string, string | number>);\n\t\t\tif (styleStr) {\n\t\t\t\tattrs += ` style=\"${escapeHtml(styleStr, true)}\"`;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (value === true) {\n\t\t\tattrs += ` ${key}`;\n\t\t} else {\n\t\t\tattrs += ` ${key}=\"${escapeHtml(value, true)}\"`;\n\t\t}\n\t}\n\treturn attrs;\n}\n\nfunction serializeStyle(style: Record<string, string | number>): string {\n\tconst parts: string[] = [];\n\tfor (const [key, value] of Object.entries(style)) {\n\t\tif (value == null) continue;\n\t\tparts.push(`${key}:${value}`);\n\t}\n\treturn parts.join(';');\n}\n\n// #endregion\n\n// #region Component building\n\nfunction buildComponentSegment(\n\ttype: Component,\n\tprops: Record<string, unknown>,\n\tctx: RenderContext,\n\tpath: string,\n): Segment {\n\t// call component\n\tconst result = type(props);\n\t// if component called provide(), push frame before rendering children\n\tconst hadFrame = currentFrame !== null;\n\tpushContextFrame();\n\ttry {\n\t\treturn buildSegment(result, ctx, path);\n\t} finally {\n\t\tpopContextFrame(hadFrame);\n\t}\n}\n\nfunction buildSuspenseSegment(props: SuspenseProps, ctx: RenderContext, path: string): Segment {\n\t// generate unique id for this suspense boundary\n\tconst nextIndex = (ctx.idsByPath.get(path) ?? 0) + 1;\n\tctx.idsByPath.set(path, nextIndex);\n\tconst id = path ? `${path}-${nextIndex}` : `${nextIndex}`;\n\tconst suspenseId = `s${id}`;\n\n\ttry {\n\t\t// try to render children synchronously\n\t\tconst content = buildSegment(props.children, ctx, suspenseId);\n\t\t// no suspension - return content directly (no boundary needed)\n\t\treturn content;\n\t} catch (thrown) {\n\t\t// check if it's a promise (suspension)\n\t\tif (thrown instanceof Promise) {\n\t\t\t// render fallback\n\t\t\tconst fallback = buildSegment(props.fallback, ctx, suspenseId);\n\n\t\t\t// create suspense segment\n\t\t\tconst seg: Segment = {\n\t\t\t\tkind: 'suspense',\n\t\t\t\tid: suspenseId,\n\t\t\t\tfallback,\n\t\t\t\tcontent: null,\n\t\t\t};\n\n\t\t\t// set up promise to re-render children when resolved\n\t\t\tconst pending = thrown.then(() => {\n\t\t\t\t// re-render children after promise resolves\n\t\t\t\tseg.content = buildSegment(props.children, ctx, suspenseId);\n\t\t\t});\n\t\t\tseg.pending = pending;\n\n\t\t\t// track for streaming\n\t\t\tctx.pendingSuspense.push({\n\t\t\t\tid: suspenseId,\n\t\t\t\tpromise: pending.then(() => seg.content!),\n\t\t\t});\n\n\t\t\treturn seg;\n\t\t}\n\t\t// not a promise - re-throw\n\t\tthrow thrown;\n\t}\n}\n\n// #endregion\n\n// #region Serialization\n\n/** resolve all blocking suspense boundaries */\nasync function resolveBlocking(segment: Segment): Promise<void> {\n\tif (segment.kind === 'suspense') {\n\t\tif (segment.pending) {\n\t\t\tawait segment.pending;\n\t\t\tsegment.pending = undefined;\n\t\t}\n\t\tif (segment.content) {\n\t\t\tawait resolveBlocking(segment.content);\n\t\t}\n\t\treturn;\n\t}\n\tif (segment.kind === 'composite') {\n\t\tfor (const part of segment.parts) {\n\t\t\tawait resolveBlocking(part);\n\t\t}\n\t}\n}\n\n/** serialize segment tree to HTML string */\nfunction serializeSegment(seg: Segment): string {\n\tif (seg.kind === 'static') {\n\t\treturn seg.html;\n\t}\n\tif (seg.kind === 'composite') {\n\t\treturn seg.parts.map(serializeSegment).join('');\n\t}\n\t// suspense - always render fallback; resolved content streams in template\n\treturn `<!--$s:${seg.id}-->${serializeSegment(seg.fallback)}<!--/$s:${seg.id}-->`;\n}\n\n// #endregion\n\n// #region Streaming\n\n/** suspense runtime function name */\nconst SR = '$sr';\n/** suspense runtime - injected once, swaps template content with fallback */\nconst SUSPENSE_RUNTIME = `<script>${SR}=(t,i,s,e)=>{i=\"$s:\"+t.dataset.suspense;s=document.createTreeWalker(document,128);while(e=s.nextNode())if(e.data===i){while(e.nextSibling?.data!==\"/\"+i)e.nextSibling.remove();e.nextSibling.replaceWith(...t.content.childNodes);e.remove();break}t.remove()}</script>`;\n\nasync function streamPendingSuspense(\n\tcontext: RenderContext,\n\tcontroller: ReadableStreamDefaultController<Uint8Array>,\n\tencoder: TextEncoder,\n): Promise<void> {\n\tlet runtimeInjected = false;\n\tconst processed = new Set<string>();\n\twhile (true) {\n\t\tconst batch = context.pendingSuspense.filter(({ id }) => !processed.has(id));\n\t\tif (batch.length === 0) break;\n\t\tawait Promise.all(\n\t\t\tbatch.map(async ({ id, promise }) => {\n\t\t\t\tprocessed.add(id);\n\t\t\t\ttry {\n\t\t\t\t\tconst resolvedSegment = await promise;\n\t\t\t\t\tawait resolveBlocking(resolvedSegment);\n\t\t\t\t\tconst html = serializeSegment(resolvedSegment);\n\t\t\t\t\t// inject runtime once before first resolution\n\t\t\t\t\tconst runtime = runtimeInjected ? '' : SUSPENSE_RUNTIME;\n\t\t\t\t\truntimeInjected = true;\n\t\t\t\t\t// stream template + call to swap function\n\t\t\t\t\tcontroller.enqueue(\n\t\t\t\t\t\tencoder.encode(\n\t\t\t\t\t\t\t`${runtime}<template data-suspense=\"${id}\">${html}</template>` +\n\t\t\t\t\t\t\t\t`<script>${SR}(document.currentScript.previousElementSibling)</script>`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcontext.onError(error);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t}\n}\n\n// #endregion\n\n// #region Utilities\n\nconst ATTR_REGEX = /[&\"]/g;\nconst CONTENT_REGEX = /[&<]/g;\n\nfunction escapeHtml(value: unknown, isAttr: boolean): string {\n\tconst str = String(value ?? '');\n\tconst pattern = isAttr ? ATTR_REGEX : CONTENT_REGEX;\n\tpattern.lastIndex = 0;\n\n\tlet escaped = '';\n\tlet last = 0;\n\n\twhile (pattern.test(str)) {\n\t\tconst i = pattern.lastIndex - 1;\n\t\tconst ch = str[i];\n\t\tescaped += str.substring(last, i) + (ch === '&' ? '&amp;' : ch === '\"' ? '&quot;' : '&lt;');\n\t\tlast = i + 1;\n\t}\n\n\treturn escaped + str.substring(last);\n}\n\nfunction finalizeHtml(html: string, context: RenderContext): string {\n\tconst hasHtmlRoot = html.trimStart().toLowerCase().startsWith('<html');\n\t// inject hoisted head elements\n\tif (context.headElements.length > 0) {\n\t\tconst headContent = context.headElements.join('');\n\t\tif (hasHtmlRoot) {\n\t\t\tconst headCloseIndex = html.indexOf('</head>');\n\t\t\tif (headCloseIndex !== -1) {\n\t\t\t\t// inject before existing </head>\n\t\t\t\thtml = html.slice(0, headCloseIndex) + headContent + html.slice(headCloseIndex);\n\t\t\t} else {\n\t\t\t\t// no existing head, inject after <html>\n\t\t\t\tconst htmlOpenMatch = html.match(/<html[^>]*>/);\n\t\t\t\tif (htmlOpenMatch && htmlOpenMatch.index !== undefined) {\n\t\t\t\t\tconst insertIndex = htmlOpenMatch.index + htmlOpenMatch[0].length;\n\t\t\t\t\thtml = html.slice(0, insertIndex) + `<head>${headContent}</head>` + html.slice(insertIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// no HTML root, prepend head\n\t\t\thtml = `<head>${headContent}</head>${html}`;\n\t\t}\n\t}\n\tif (hasHtmlRoot) {\n\t\thtml = '<!doctype html>' + html;\n\t}\n\treturn html;\n}\n\n// #endregion\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["finalProps: Record<string, unknown>","activeRenderContext: RenderContext | null","context: Context<T | undefined>","context: RenderContext","parts: Segment[]","parts: string[]","seg: Segment","asyncCtx: RenderContext","resolvedSegment: Segment"],"sources":["../src/lib/create-element.ts","../src/lib/render-context.ts","../src/lib/context.ts","../src/lib/suspense.ts","../src/lib/render.ts"],"sourcesContent":["import type { JSX } from './intrinsic-elements.ts';\nimport type { Component, JSXElement, JSXNode } from './types.ts';\n\n// #region createElement\n\n/**\n * creates a JSX element for an intrinsic element\n * @param type element tag name\n * @param props element properties\n * @param children child elements\n * @returns JSX element\n */\nexport function createElement<T extends keyof JSX.IntrinsicElements>(\n\ttype: T,\n\tprops?: JSX.IntrinsicElements[T] | null,\n\t...children: JSXNode[]\n): JSXElement<JSX.IntrinsicElements[T], T>;\n\n/**\n * creates a JSX element for a function component\n * @param type component function\n * @param props component properties\n * @param children child elements\n * @returns JSX element\n */\nexport function createElement<P extends {}>(\n\ttype: Component<P>,\n\tprops?: P | null,\n\t...children: JSXNode[]\n): JSXElement<P, Component<P>>;\n\n/**\n * creates a JSX element (classic API)\n * @param type element tag name or component function\n * @param props element properties\n * @param children child elements\n * @returns JSX element\n */\nexport function createElement<P extends {}>(\n\ttype: string | Component<P>,\n\tprops?: P | null,\n\t...children: JSXNode[]\n): JSXElement<P>;\n\nexport function createElement(\n\ttype: string | Component<any>,\n\tprops?: Record<string, unknown> | null,\n\t...children: JSXNode[]\n): JSXElement {\n\tconst finalProps: Record<string, unknown> = { ...props };\n\n\tif (children.length === 1) {\n\t\tfinalProps.children = children[0];\n\t} else if (children.length > 1) {\n\t\tfinalProps.children = children;\n\t}\n\n\treturn { type, props: finalProps };\n}\n\n// #endregion\n\n// #region cloneElement\n\n/**\n * clones a JSX element for an intrinsic element with new props\n * @param element element to clone\n * @param props props to merge (overrides original)\n * @param children children to replace (if provided)\n * @returns cloned JSX element\n */\nexport function cloneElement<T extends keyof JSX.IntrinsicElements>(\n\telement: JSXElement<JSX.IntrinsicElements[T], T>,\n\tprops?: Partial<JSX.IntrinsicElements[T]> | null,\n\t...children: JSXNode[]\n): JSXElement<JSX.IntrinsicElements[T], T>;\n\n/**\n * clones a JSX element for a function component with new props\n * @param element element to clone\n * @param props props to merge (overrides original)\n * @param children children to replace (if provided)\n * @returns cloned JSX element\n */\nexport function cloneElement<P>(\n\telement: JSXElement<P, Component<P>>,\n\tprops?: Partial<P> | null,\n\t...children: JSXNode[]\n): JSXElement<P, Component<P>>;\n\n/**\n * clones a JSX element with new props\n * @param element element to clone\n * @param props props to merge (overrides original)\n * @param children children to replace (if provided)\n * @returns cloned JSX element\n */\nexport function cloneElement<P>(\n\telement: JSXElement<P>,\n\tprops?: Partial<P> | null,\n\t...children: JSXNode[]\n): JSXElement<P>;\n\nexport function cloneElement(\n\telement: JSXElement,\n\tprops?: Record<string, unknown> | null,\n\t...children: JSXNode[]\n): JSXElement {\n\tconst finalProps: Record<string, unknown> = { ...(element.props as Record<string, unknown>), ...props };\n\n\tif (children.length === 1) {\n\t\tfinalProps.children = children[0];\n\t} else if (children.length > 1) {\n\t\tfinalProps.children = children;\n\t}\n\n\treturn { type: element.type, props: finalProps };\n}\n\n// #endregion\n","import type { Context } from './context.ts';\nimport type { JSXNode } from './types.ts';\n\n/** stack of context frames */\ntype ContextFrame = Map<Context<unknown>, unknown>;\n\n// #region Segment types\n\nexport type Segment =\n\t| {\n\t\t\treadonly kind: 'static';\n\t\t\treadonly html: string;\n\t }\n\t| {\n\t\t\treadonly kind: 'composite';\n\t\t\treadonly parts: readonly Segment[];\n\t }\n\t| {\n\t\t\treadonly kind: 'suspense';\n\t\t\treadonly id: string;\n\t\t\treadonly fallback: Segment;\n\t\t\tpending?: Promise<void>;\n\t\t\tcontent: Segment | null;\n\t }\n\t| {\n\t\t\treadonly kind: 'error-boundary';\n\t\t\treadonly children: Segment;\n\t\t\treadonly fallbackFn: (error: unknown) => JSXNode;\n\t\t\treadonly renderContext: RenderContext;\n\t\t\treadonly path: string;\n\t\t\tfallbackSegment: Segment | null;\n\t };\n\n// #endregion\n\n/** render context passed through the render tree */\nexport interface RenderContext {\n\tcontextStack: ContextFrame[];\n\tcurrentFrame: ContextFrame | null;\n\theadElements: string[];\n\tidsByPath: Map<string, number>;\n\tinsideHead: boolean;\n\tinsideSvg: boolean;\n\tonError: (error: unknown) => void;\n\tpendingSuspense: Array<{ id: string; promise: Promise<Segment> }>;\n}\n\n/** active render context (set by renderer) */\nlet activeRenderContext: RenderContext | null = null;\n\n/**\n * sets the active render context\n * @param ctx render context to activate, or null to clear\n * @returns the previous render context\n */\nexport function setActiveRenderContext(ctx: RenderContext | null): RenderContext | null {\n\tconst prev = activeRenderContext;\n\tactiveRenderContext = ctx;\n\treturn prev;\n}\n\n/**\n * provides a value for the context during the current component's render\n * @param context context key from createContext()\n * @param value value to provide\n */\nexport function provide<T>(context: Context<T>, value: T): void {\n\tconst ctx = activeRenderContext!;\n\tif (!ctx.currentFrame) {\n\t\t// lazily create frame, copying from previous\n\t\tconst prev = ctx.contextStack[ctx.contextStack.length - 1];\n\t\tctx.currentFrame = prev ? new Map(prev) : new Map();\n\t}\n\tctx.currentFrame.set(context as Context<unknown>, value);\n}\n\n/**\n * returns current provided value, or the default value\n * @param context context key from createContext()\n */\nexport function inject<T>(context: Context<T>): T {\n\tconst ctx = activeRenderContext!;\n\t// check current frame first, then stack\n\tconst frame = ctx.currentFrame ?? ctx.contextStack[ctx.contextStack.length - 1];\n\tif (frame?.has(context as Context<unknown>)) {\n\t\treturn frame.get(context as Context<unknown>) as T;\n\t}\n\treturn context.defaultValue;\n}\n\n/**\n * pushes current frame to stack (called before rendering children)\n * @returns whether a frame was pushed (needed for popContextFrame)\n */\nexport function pushContextFrame(): boolean {\n\tconst ctx = activeRenderContext!;\n\tif (ctx.currentFrame) {\n\t\tctx.contextStack.push(ctx.currentFrame);\n\t\tctx.currentFrame = null;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * pops context frame (called after rendering children)\n * @param hadFrame whether pushContextFrame returned true\n */\nexport function popContextFrame(hadFrame: boolean): void {\n\tconst ctx = activeRenderContext!;\n\tif (hadFrame) {\n\t\tctx.contextStack.pop();\n\t}\n\tctx.currentFrame = null;\n}\n","import { Fragment, jsx } from '../jsx-runtime.ts';\n\nimport { provide } from './render-context.ts';\nimport type { JSXElement, JSXNode } from './types.ts';\n\n/** context object returned by createContext() */\nexport interface Context<T> {\n\tdefaultValue: T;\n\tProvider: (props: { value: T; children?: JSXNode }) => JSXElement;\n}\n\n/** internal provider props */\ninterface ProviderProps<T> {\n\tcontext: Context<T>;\n\tvalue: T;\n\tchildren?: JSXNode;\n}\n\n/** internal provider component */\nfunction Provider<T>({ context, value, children }: ProviderProps<T>): JSXElement {\n\tprovide(context, value);\n\treturn jsx(Fragment, { children });\n}\n\n/**\n * creates a context with a Provider component\n * @param defaultValue value returned by use() when no Provider is above\n * @example\n * const ThemeContext = createContext('light');\n *\n * <ThemeContext.Provider value=\"dark\">\n * <App />\n * </ThemeContext.Provider>\n *\n * function App() {\n * const theme = use(ThemeContext);\n * return <div>{theme}</div>;\n * }\n */\nexport function createContext<T>(defaultValue: T): Context<T>;\nexport function createContext<T>(): Context<T | undefined>;\nexport function createContext<T>(defaultValue?: T): Context<T | undefined> {\n\tconst context: Context<T | undefined> = {\n\t\tdefaultValue,\n\t\tProvider: ({ value, children }) => Provider({ context, value, children }),\n\t};\n\n\treturn context;\n}\n","import { Fragment, jsx } from '../jsx-runtime.js';\n\nimport type { Context } from './context.js';\nimport { inject } from './render-context.js';\nimport type { JSXElement, JSXNode } from './types.js';\n\nexport interface SuspenseProps {\n\tfallback: JSXNode;\n\tchildren?: JSXNode;\n}\n\n/**\n * suspense boundary - renders fallback while children are suspended\n */\nexport function Suspense({ children }: SuspenseProps): JSXElement {\n\t// Suspense is handled specially in buildSegment, this is just for typing\n\treturn jsx(Fragment, { children });\n}\n\nexport interface ErrorBoundaryProps {\n\tfallback: (error: unknown) => JSXNode;\n\tchildren?: JSXNode;\n}\n\n/**\n * error boundary - catches render errors and displays fallback\n */\nexport function ErrorBoundary({ children }: ErrorBoundaryProps): JSXElement {\n\t// ErrorBoundary is handled specially in buildSegment, this is just for typing\n\treturn jsx(Fragment, { children });\n}\n\n/** cache for resolved/rejected promise values */\nconst promiseCache = new WeakMap<\n\tPromise<unknown>,\n\t{ resolved: true; value: unknown } | { resolved: false; error: unknown }\n>();\n\nfunction isContext<T>(value: unknown): value is Context<T> {\n\treturn typeof value === 'object' && value !== null && 'defaultValue' in value && 'Provider' in value;\n}\n\n/**\n * reads a context value or suspends until a promise resolves\n * @param usable context or promise\n * @returns context value or resolved promise value\n * @throws promise if not yet resolved, or error if rejected\n */\nexport function use<T>(usable: Context<T>): T;\nexport function use<T>(usable: Promise<T>): T;\nexport function use<T>(usable: Context<T> | Promise<T>): T {\n\t// context\n\tif (isContext<T>(usable)) {\n\t\treturn inject(usable);\n\t}\n\t// promise\n\tconst cached = promiseCache.get(usable);\n\tif (cached) {\n\t\tif (cached.resolved) {\n\t\t\treturn cached.value as T;\n\t\t} else {\n\t\t\tthrow cached.error;\n\t\t}\n\t}\n\t// not cached yet - set up caching and throw\n\tusable.then(\n\t\t(value) => promiseCache.set(usable, { resolved: true, value }),\n\t\t(error) => promiseCache.set(usable, { resolved: false, error }),\n\t);\n\tthrow usable;\n}\n","/**\n * streaming JSX renderer\n *\n * architecture:\n * - segment tree: we build a tree of segments (static text, composites, suspense\n * boundaries) then serialize to HTML\n * - suspense: components can throw promises via use(), caught at Suspense boundaries\n * which render fallback immediately and stream resolved content later\n * - head hoisting: <title>, <meta>, <link>, <style> found outside <head> are\n * collected and injected into <head> during finalization\n */\n\nimport { decodeUtf8From, encodeUtf8 } from '@atcute/uint8array';\n\nimport { Fragment } from '../jsx-runtime.ts';\n\nimport {\n\tpopContextFrame,\n\tpushContextFrame,\n\ttype RenderContext,\n\ttype Segment,\n\tsetActiveRenderContext,\n} from './render-context.ts';\nimport { ErrorBoundary, type ErrorBoundaryProps, Suspense, type SuspenseProps } from './suspense.ts';\nimport type { Component, JSXElement, JSXNode } from './types.ts';\n\nconst HEAD_ELEMENTS = new Set(['title', 'meta', 'link', 'style']);\nconst MAX_SUSPENSE_ATTEMPTS = 20;\nconst SELF_CLOSING_TAGS = new Set([\n\t'area',\n\t'base',\n\t'br',\n\t'col',\n\t'embed',\n\t'hr',\n\t'img',\n\t'input',\n\t'link',\n\t'meta',\n\t'param',\n\t'source',\n\t'track',\n\t'wbr',\n]);\n/** props that shouldn't be rendered as HTML attributes */\nconst FRAMEWORK_PROPS = new Set(['children', 'dangerouslySetInnerHTML']);\n\n// #region Segment helpers\n\nfunction staticSeg(html: string): Segment {\n\treturn { kind: 'static', html };\n}\n\nfunction compositeSeg(parts: Segment[]): Segment {\n\treturn { kind: 'composite', parts };\n}\n\nconst EMPTY_SEGMENT = staticSeg('');\n\n// #endregion\n\nexport interface RenderOptions {\n\tonError?: (error: unknown) => void;\n}\n\n/**\n * renders JSX to a readable stream\n * @param node JSX node to render\n * @param options render options\n * @returns readable stream of UTF-8 encoded HTML\n */\nexport function renderToStream(node: JSXNode, options?: RenderOptions): ReadableStream<Uint8Array> {\n\tconst onError = options?.onError ?? ((error) => console.error(error));\n\tconst context: RenderContext = {\n\t\tcontextStack: [],\n\t\tcurrentFrame: null,\n\t\theadElements: [],\n\t\tidsByPath: new Map(),\n\t\tinsideHead: false,\n\t\tinsideSvg: false,\n\t\tonError,\n\t\tpendingSuspense: [],\n\t};\n\n\treturn new ReadableStream({\n\t\tasync start(controller) {\n\t\t\ttry {\n\t\t\t\tconst root = buildSegment(node, context, '');\n\t\t\t\tawait resolveBlocking(root);\n\n\t\t\t\tconst html = serializeSegment(root);\n\t\t\t\tconst finalHtml = finalizeHtml(html, context);\n\t\t\t\tcontroller.enqueue(encodeUtf8(finalHtml));\n\n\t\t\t\t// stream pending suspense boundaries as they resolve\n\t\t\t\tif (context.pendingSuspense.length > 0) {\n\t\t\t\t\tawait streamPendingSuspense(context, controller);\n\t\t\t\t}\n\n\t\t\t\tcontroller.close();\n\t\t\t} catch (error) {\n\t\t\t\tonError(error);\n\t\t\t\tcontroller.error(error);\n\t\t\t}\n\t\t},\n\t});\n}\n\n/**\n * renders JSX to a string (non-streaming)\n * @param node JSX node to render\n * @param options render options\n * @returns promise resolving to HTML string\n */\nexport async function renderToString(node: JSXNode, options?: RenderOptions): Promise<string> {\n\tconst stream = renderToStream(node, options);\n\tconst reader = stream.getReader();\n\n\tlet html = '';\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) {\n\t\t\tbreak;\n\t\t}\n\n\t\thtml += decodeUtf8From(value);\n\t}\n\n\treturn html;\n}\n\n/**\n * renders JSX to a streaming Response\n * @param node JSX node to render\n * @param init optional ResponseInit (status, headers, etc.)\n * @returns Response with streaming HTML body\n */\nexport function render(node: JSXNode, init?: ResponseInit): Response {\n\tconst stream = renderToStream(node);\n\n\t// @ts-expect-error: not sure why.\n\tconst headers = new Headers(init?.headers);\n\tif (!headers.has('Content-Type')) {\n\t\theaders.set('Content-Type', 'text/html; charset=utf-8');\n\t}\n\n\treturn new Response(stream, { ...init, headers });\n}\n\n// #region Segment building\n\nfunction isJSXElement(node: unknown): node is JSXElement {\n\treturn typeof node === 'object' && node !== null && 'type' in node && 'props' in node;\n}\n\nfunction isHeadElement(tag: string): boolean {\n\treturn HEAD_ELEMENTS.has(tag);\n}\n\nfunction buildSegment(node: JSXNode, ctx: RenderContext, path: string): Segment {\n\tconst prev = setActiveRenderContext(ctx);\n\ttry {\n\t\treturn buildSegmentInner(node, ctx, path);\n\t} finally {\n\t\tsetActiveRenderContext(prev);\n\t}\n}\n\nfunction buildSegmentInner(node: JSXNode, context: RenderContext, path: string): Segment {\n\t// primitives\n\tif (typeof node === 'string' || typeof node === 'number' || typeof node === 'bigint') {\n\t\treturn staticSeg(escapeHtml(node, false));\n\t}\n\tif (node === null || node === undefined || typeof node === 'boolean') {\n\t\treturn EMPTY_SEGMENT;\n\t}\n\t// iterables (arrays, generators, etc.)\n\tif (typeof node === 'object' && Symbol.iterator in node) {\n\t\tconst parts: Segment[] = [];\n\t\tfor (const child of node) {\n\t\t\tparts.push(buildSegmentInner(child, context, path));\n\t\t}\n\t\treturn compositeSeg(parts);\n\t}\n\t// JSX elements\n\tif (isJSXElement(node)) {\n\t\tconst { type, props } = node;\n\t\t// Fragment\n\t\tif (type === Fragment) {\n\t\t\tconst children = (props as { children?: JSXNode }).children;\n\t\t\treturn children != null ? buildSegmentInner(children, context, path) : EMPTY_SEGMENT;\n\t\t}\n\t\t// intrinsic elements (HTML tags)\n\t\tif (typeof type === 'string') {\n\t\t\tconst tag = type;\n\n\t\t\tif (tag === 'head') {\n\t\t\t\treturn buildHeadElementSegment(tag, props as Record<string, unknown>, context, path);\n\t\t\t}\n\n\t\t\tif (!context.insideHead && isHeadElement(tag)) {\n\t\t\t\t// hoist to <head>\n\t\t\t\tconst elementSeg = buildElementSegment(tag, props as Record<string, unknown>, context, path);\n\t\t\t\tcontext.headElements.push(serializeSegment(elementSeg));\n\t\t\t\treturn EMPTY_SEGMENT;\n\t\t\t}\n\n\t\t\treturn buildElementSegment(tag, props as Record<string, unknown>, context, path);\n\t\t}\n\t\t// function components\n\t\tif (typeof type === 'function') {\n\t\t\t// Suspense boundary\n\t\t\tif (type === Suspense) {\n\t\t\t\treturn buildSuspenseSegment(props as unknown as SuspenseProps, context, path);\n\t\t\t}\n\t\t\t// ErrorBoundary\n\t\t\tif (type === ErrorBoundary) {\n\t\t\t\treturn buildErrorBoundarySegment(props as unknown as ErrorBoundaryProps, context, path);\n\t\t\t}\n\t\t\treturn buildComponentSegment(type, props as Record<string, unknown>, context, path);\n\t\t}\n\t}\n\treturn EMPTY_SEGMENT;\n}\n\n// #endregion\n\n// #region Element building\n\nfunction buildElementSegment(\n\ttag: string,\n\tprops: Record<string, unknown>,\n\tcontext: RenderContext,\n\tpath: string,\n): Segment {\n\tconst currentIsSvg = context.insideSvg || tag === 'svg';\n\tconst attrs = renderAttributes(props);\n\t// self-closing tags\n\tif (SELF_CLOSING_TAGS.has(tag)) {\n\t\treturn staticSeg(`<${tag}${attrs}>`);\n\t}\n\t// dangerouslySetInnerHTML\n\tconst innerHTML = props.dangerouslySetInnerHTML as { __html: string } | undefined;\n\tif (innerHTML) {\n\t\treturn staticSeg(`<${tag}${attrs}>${innerHTML.__html}</${tag}>`);\n\t}\n\t// normal element with children\n\tconst open = staticSeg(`<${tag}${attrs}>`);\n\tconst previousInsideSvg = context.insideSvg;\n\tcontext.insideSvg = tag === 'foreignObject' ? false : currentIsSvg;\n\tconst children =\n\t\tprops.children != null ? buildSegment(props.children as JSXNode, context, path) : EMPTY_SEGMENT;\n\tcontext.insideSvg = previousInsideSvg;\n\tconst close = staticSeg(`</${tag}>`);\n\treturn compositeSeg([open, children, close]);\n}\n\nfunction buildHeadElementSegment(\n\ttag: string,\n\tprops: Record<string, unknown>,\n\tcontext: RenderContext,\n\tpath: string,\n): Segment {\n\tconst attrs = renderAttributes(props);\n\tconst previousInsideHead = context.insideHead;\n\tcontext.insideHead = true;\n\tconst open = staticSeg(`<${tag}${attrs}>`);\n\tconst children =\n\t\tprops.children != null ? buildSegment(props.children as JSXNode, context, path) : EMPTY_SEGMENT;\n\tcontext.insideHead = previousInsideHead;\n\tconst close = staticSeg(`</${tag}>`);\n\treturn compositeSeg([open, children, close]);\n}\n\nfunction renderAttributes(props: Record<string, unknown>): string {\n\tlet attrs = '';\n\tfor (const key in props) {\n\t\tif (FRAMEWORK_PROPS.has(key)) continue;\n\t\tconst value = props[key];\n\t\tif (value === undefined || value === null || value === false) continue;\n\t\tif (typeof value === 'function') continue;\n\t\t// style object -> string\n\t\tif (key === 'style' && typeof value === 'object') {\n\t\t\tconst styleStr = serializeStyle(value as Record<string, string | number>);\n\t\t\tif (styleStr) {\n\t\t\t\tattrs += ` style=\"${escapeHtml(styleStr, true)}\"`;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (value === true) {\n\t\t\tattrs += ` ${key}`;\n\t\t} else {\n\t\t\tattrs += ` ${key}=\"${escapeHtml(value, true)}\"`;\n\t\t}\n\t}\n\treturn attrs;\n}\n\nfunction serializeStyle(style: Record<string, string | number>): string {\n\tconst parts: string[] = [];\n\tfor (const [key, value] of Object.entries(style)) {\n\t\tif (value == null) continue;\n\t\tparts.push(`${key}:${value}`);\n\t}\n\treturn parts.join(';');\n}\n\n// #endregion\n\n// #region Component building\n\nfunction buildComponentSegment(\n\ttype: Component,\n\tprops: Record<string, unknown>,\n\tctx: RenderContext,\n\tpath: string,\n): Segment {\n\t// call component\n\tconst result = type(props);\n\t// if component called provide(), push frame before rendering children\n\tconst hadFrame = pushContextFrame();\n\ttry {\n\t\treturn buildSegmentInner(result, ctx, path);\n\t} finally {\n\t\tpopContextFrame(hadFrame);\n\t}\n}\n\nfunction buildSuspenseSegment(props: SuspenseProps, ctx: RenderContext, path: string): Segment {\n\t// generate unique id for this suspense boundary\n\tconst nextIndex = (ctx.idsByPath.get(path) ?? 0) + 1;\n\tctx.idsByPath.set(path, nextIndex);\n\tconst id = path ? `${path}-${nextIndex}` : `${nextIndex}`;\n\tconst suspenseId = `s${id}`;\n\n\ttry {\n\t\t// try to render children synchronously\n\t\tconst content = buildSegment(props.children, ctx, suspenseId);\n\t\t// no suspension - return content directly (no boundary needed)\n\t\treturn content;\n\t} catch (thrown) {\n\t\t// check if it's a promise (suspension)\n\t\tif (thrown instanceof Promise) {\n\t\t\t// render fallback\n\t\t\tconst fallback = buildSegment(props.fallback, ctx, suspenseId);\n\n\t\t\t// create suspense segment\n\t\t\tconst seg: Segment = {\n\t\t\t\tkind: 'suspense',\n\t\t\t\tid: suspenseId,\n\t\t\t\tfallback,\n\t\t\t\tcontent: null,\n\t\t\t};\n\n\t\t\t// snapshot context stack for async re-render (parent frames will be popped\n\t\t\t// by the time the promise resolves)\n\t\t\tconst asyncCtx: RenderContext = {\n\t\t\t\t...ctx,\n\t\t\t\tcontextStack: [...ctx.contextStack],\n\t\t\t\tcurrentFrame: null,\n\t\t\t};\n\n\t\t\t// re-render function that handles subsequent promise throws\n\t\t\tconst rerender = (attempt: number): Promise<void> | void => {\n\t\t\t\tif (attempt >= MAX_SUSPENSE_ATTEMPTS) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`suspense boundary exceeded maximum retry attempts (${MAX_SUSPENSE_ATTEMPTS})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tseg.content = buildSegment(props.children, asyncCtx, suspenseId);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof Promise) {\n\t\t\t\t\t\t// component threw another promise - wait and retry\n\t\t\t\t\t\treturn err.then(() => rerender(attempt + 1));\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// set up promise to re-render children when resolved\n\t\t\tconst pending = thrown.then(() => rerender(1));\n\t\t\tseg.pending = pending;\n\n\t\t\t// track for streaming\n\t\t\tconst tracked = pending.then(() => seg.content!);\n\t\t\ttracked.catch(() => {}); // prevent unhandled rejection if resolveBlocking catches first\n\t\t\tctx.pendingSuspense.push({ id: suspenseId, promise: tracked });\n\n\t\t\treturn seg;\n\t\t}\n\t\t// not a promise - re-throw\n\t\tthrow thrown;\n\t}\n}\n\nfunction buildErrorBoundarySegment(\n\tprops: ErrorBoundaryProps,\n\tctx: RenderContext,\n\tpath: string,\n): Segment {\n\t// snapshot context for potential async fallback rendering\n\tconst asyncCtx: RenderContext = {\n\t\t...ctx,\n\t\tcontextStack: [...ctx.contextStack],\n\t\tcurrentFrame: null,\n\t};\n\n\ttry {\n\t\tconst children = buildSegment(props.children, ctx, path);\n\t\treturn {\n\t\t\tkind: 'error-boundary',\n\t\t\tchildren,\n\t\t\tfallbackFn: props.fallback,\n\t\t\trenderContext: asyncCtx,\n\t\t\tpath,\n\t\t\tfallbackSegment: null,\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof Promise) {\n\t\t\tthrow error; // let Suspense handle it\n\t\t}\n\t\t// sync error - render fallback immediately\n\t\treturn buildSegment(props.fallback(error), ctx, path);\n\t}\n}\n\n// #endregion\n\n// #region Serialization\n\n/** resolve all blocking suspense boundaries and error boundaries */\nasync function resolveBlocking(segment: Segment): Promise<void> {\n\tif (segment.kind === 'suspense') {\n\t\tif (segment.pending) {\n\t\t\tawait segment.pending;\n\t\t\tsegment.pending = undefined;\n\t\t}\n\t\tif (segment.content) {\n\t\t\tawait resolveBlocking(segment.content);\n\t\t}\n\t\treturn;\n\t}\n\tif (segment.kind === 'error-boundary') {\n\t\ttry {\n\t\t\tawait resolveBlocking(segment.children);\n\t\t} catch (error) {\n\t\t\tsegment.fallbackSegment = buildSegment(\n\t\t\t\tsegment.fallbackFn(error),\n\t\t\t\tsegment.renderContext,\n\t\t\t\tsegment.path,\n\t\t\t);\n\t\t}\n\t\treturn;\n\t}\n\tif (segment.kind === 'composite') {\n\t\tfor (const part of segment.parts) {\n\t\t\tawait resolveBlocking(part);\n\t\t}\n\t}\n}\n\n/** serialize segment tree to HTML string */\nfunction serializeSegment(seg: Segment): string {\n\tif (seg.kind === 'static') {\n\t\treturn seg.html;\n\t}\n\tif (seg.kind === 'composite') {\n\t\treturn seg.parts.map(serializeSegment).join('');\n\t}\n\tif (seg.kind === 'error-boundary') {\n\t\treturn serializeSegment(seg.fallbackSegment ?? seg.children);\n\t}\n\t// suspense - always render fallback; resolved content streams in template\n\treturn `<!--$s:${seg.id}-->${serializeSegment(seg.fallback)}<!--/$s:${seg.id}-->`;\n}\n\n// #endregion\n\n// #region Streaming\n\n/** suspense runtime function name */\nconst SR = '$sr';\n/** suspense runtime - injected once, swaps template content with fallback */\nconst SUSPENSE_RUNTIME = `<script>${SR}=(t,i,s,e)=>{i=\"$s:\"+t.dataset.suspense;s=document.createTreeWalker(document,128);while(e=s.nextNode())if(e.data===i){while(e.nextSibling?.data!==\"/\"+i)e.nextSibling.remove();e.nextSibling.replaceWith(...t.content.childNodes);e.remove();break}t.remove()}</script>`;\n\nasync function streamPendingSuspense(\n\tcontext: RenderContext,\n\tcontroller: ReadableStreamDefaultController<Uint8Array>,\n): Promise<void> {\n\tcontroller.enqueue(encodeUtf8(SUSPENSE_RUNTIME));\n\n\twhile (true) {\n\t\tconst batch = context.pendingSuspense;\n\t\tif (batch.length === 0) {\n\t\t\tbreak;\n\t\t}\n\t\tcontext.pendingSuspense = [];\n\n\t\tawait Promise.all(\n\t\t\tbatch.map(async ({ id, promise }) => {\n\t\t\t\tlet resolvedSegment: Segment;\n\t\t\t\ttry {\n\t\t\t\t\tresolvedSegment = await promise;\n\t\t\t\t} catch {\n\t\t\t\t\t// promise rejected - error was caught by an error boundary\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tawait resolveBlocking(resolvedSegment);\n\n\t\t\t\t\tconst html = serializeSegment(resolvedSegment);\n\n\t\t\t\t\tcontroller.enqueue(\n\t\t\t\t\t\tencodeUtf8(\n\t\t\t\t\t\t\t`<template data-suspense=\"${id}\">${html}</template>` +\n\t\t\t\t\t\t\t\t`<script>${SR}(document.currentScript.previousElementSibling)</script>`,\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tcontext.onError(error);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t}\n}\n\n// #endregion\n\n// #region Utilities\n\nconst ATTR_REGEX = /[&\"]/g;\nconst CONTENT_REGEX = /[&<]/g;\n\nfunction escapeHtml(value: unknown, isAttr: boolean): string {\n\tconst str = String(value ?? '');\n\tconst pattern = isAttr ? ATTR_REGEX : CONTENT_REGEX;\n\tpattern.lastIndex = 0;\n\n\tlet escaped = '';\n\tlet last = 0;\n\n\twhile (pattern.test(str)) {\n\t\tconst i = pattern.lastIndex - 1;\n\t\tconst ch = str[i];\n\t\tescaped += str.substring(last, i) + (ch === '&' ? '&amp;' : ch === '\"' ? '&quot;' : '&lt;');\n\t\tlast = i + 1;\n\t}\n\n\treturn escaped + str.substring(last);\n}\n\nfunction finalizeHtml(html: string, context: RenderContext): string {\n\tconst hasHtmlRoot = html.trimStart().toLowerCase().startsWith('<html');\n\t// inject hoisted head elements\n\tif (context.headElements.length > 0) {\n\t\tconst headContent = context.headElements.join('');\n\t\tif (hasHtmlRoot) {\n\t\t\tconst headCloseIndex = html.indexOf('</head>');\n\t\t\tif (headCloseIndex !== -1) {\n\t\t\t\t// inject before existing </head>\n\t\t\t\thtml = html.slice(0, headCloseIndex) + headContent + html.slice(headCloseIndex);\n\t\t\t} else {\n\t\t\t\t// no existing head, inject after <html>\n\t\t\t\tconst htmlOpenMatch = html.match(/<html[^>]*>/);\n\t\t\t\tif (htmlOpenMatch && htmlOpenMatch.index !== undefined) {\n\t\t\t\t\tconst insertIndex = htmlOpenMatch.index + htmlOpenMatch[0].length;\n\t\t\t\t\thtml = html.slice(0, insertIndex) + `<head>${headContent}</head>` + html.slice(insertIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// no HTML root, prepend head\n\t\t\thtml = `<head>${headContent}</head>${html}`;\n\t\t}\n\t}\n\tif (hasHtmlRoot) {\n\t\thtml = '<!doctype html>' + html;\n\t}\n\treturn html;\n}\n\n// #endregion\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { n as jsx, r as JSX, t as Fragment } from "./jsx-runtime-CpxZaJu6.mjs";
1
+ import { i as JSX, n as jsx, t as Fragment } from "./jsx-runtime-CcUWZKzW.mjs";
2
2
  export { Fragment, type JSX, jsx as jsxDEV };
@@ -1295,5 +1295,5 @@ declare function Fragment(props: {
1295
1295
  children?: JSXNode;
1296
1296
  }): JSXNode;
1297
1297
  //#endregion
1298
- export { FC as a, Component as i, jsx as n, JSXElement as o, JSX as r, JSXNode as s, Fragment as t };
1299
- //# sourceMappingURL=jsx-runtime-CpxZaJu6.d.mts.map
1298
+ export { SVGAttributes as a, JSXElement as c, JSX as i, JSXNode as l, jsx as n, Component as o, HTMLAttributes as r, FC as s, Fragment as t };
1299
+ //# sourceMappingURL=jsx-runtime-CcUWZKzW.d.mts.map