@reckona/mreact-server 0.0.160 → 0.0.161

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.
@@ -6,27 +6,33 @@ import { isDangerousHtmlAttribute, isDangerousHtmlOptIn, isUnsafeMetaRefreshCont
6
6
  import { escapeAttribute, isPromiseLikeUnknown, renderNonceAttribute, serializeScriptJson, } from "./html-internals.js";
7
7
  import { createStringSink, hasDeferredTasks } from "./sink.js";
8
8
  import { renderToReadableStream } from "./stream.js";
9
+ /** Serializes state for safe embedding in an HTML script tag. */
9
10
  export function serializeSsrState(value) {
10
11
  return serializeScriptJson(value);
11
12
  }
13
+ /** Appends serialized SSR state as a JSON script tag. */
12
14
  export function renderSsrState(sink, value, options = {}) {
13
15
  sink.append(`<script type="application/json" data-mreact-ssr-state${renderNonceAttribute(options.nonce)}>${serializeSsrState(value)}</script>`);
14
16
  }
17
+ /** Creates a defensive copy of an event hydration manifest. */
15
18
  export function createEventHydrationManifest(events) {
16
19
  return {
17
20
  version: 1,
18
21
  events: events.map((event) => ({ ...event })),
19
22
  };
20
23
  }
24
+ /** Appends an event hydration manifest as a JSON script tag. */
21
25
  export function renderEventHydrationManifest(sink, manifest, options = {}) {
22
26
  sink.append(`<script type="application/json" data-mreact-event-manifest${renderNonceAttribute(options.nonce)}>${serializeSsrState(manifest)}</script>`);
23
27
  }
28
+ /** Appends an external script tag with optional nonce and integrity attributes. */
24
29
  export function renderScriptAsset(sink, options) {
25
30
  const integrityAttribute = options.integrity === undefined ? "" : ` integrity="${escapeAttribute(options.integrity)}"`;
26
31
  const crossOrigin = options.integrity === undefined ? options.crossOrigin : (options.crossOrigin ?? "anonymous");
27
32
  const crossOriginAttribute = crossOrigin === undefined ? "" : ` crossorigin="${escapeAttribute(crossOrigin)}"`;
28
33
  sink.append(`<script src="${escapeAttribute(options.src)}"${renderNonceAttribute(options.nonce)}${integrityAttribute}${crossOriginAttribute}></script>`);
29
34
  }
35
+ /** Creates an HTML Response from a React-compatible node. */
30
36
  export function html(node, options = {}) {
31
37
  const headers = new Headers(options.headers);
32
38
  const responseOptions = { headers };
@@ -44,12 +50,14 @@ export function html(node, options = {}) {
44
50
  return appendReactNode(sink, node, state);
45
51
  }), responseOptions);
46
52
  }
53
+ /** Renders sink output to a string after awaiting deferred work. */
47
54
  export async function renderToString(render) {
48
55
  const sink = createStringSink();
49
56
  await render(sink);
50
57
  await sink.drain();
51
58
  return sink.toString();
52
59
  }
60
+ /** Renders a React-compatible node to an HTML string. */
53
61
  export async function renderReactNodeToString(node) {
54
62
  const sink = createStringSink();
55
63
  const state = { suspenseId: 0 };
@@ -1 +1 @@
1
- {"version":3,"file":"html-helpers.js","sourceRoot":"","sources":["../src/html-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Fragment,\n Suspense as ReactCompatSuspense,\n isValidElement,\n type ReactCompatElement,\n type ReactCompatNode,\n} from \"@reckona/mreact-compat\";\nimport type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\nimport { escapeHtmlText as escapeHtml } from \"@reckona/mreact-shared/html-escape\";\nimport { isVoidHtmlElement } from \"@reckona/mreact-shared\";\nimport {\n renderReactSuspenseBoundary,\n renderReactSuspenseOutOfOrderBoundary,\n type HydrationScriptOptions,\n} from \"./boundary.js\";\nimport {\n isDangerousHtmlAttribute,\n isDangerousHtmlOptIn,\n isUnsafeMetaRefreshContent,\n isUnsafeUrlAttribute,\n} from \"./url-safety.js\";\nimport {\n escapeAttribute,\n isPromiseLikeUnknown,\n renderNonceAttribute,\n serializeScriptJson,\n} from \"./html-internals.js\";\nimport { createStringSink, hasDeferredTasks, type StreamRender } from \"./sink.js\";\nimport { renderToReadableStream } from \"./stream.js\";\n\nexport interface ScriptAssetOptions {\n src: string;\n nonce?: string;\n integrity?: string;\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n}\n\nexport interface EventHydrationEntry {\n id: string;\n event: string;\n handler: string;\n}\n\nexport interface EventHydrationManifest {\n version: 1;\n events: EventHydrationEntry[];\n}\n\nexport interface HtmlResponseOptions {\n headers?: HeadersInit;\n status?: number;\n statusText?: string;\n}\n\nexport function serializeSsrState(value: unknown): string {\n return serializeScriptJson(value);\n}\n\nexport function renderSsrState(\n sink: HtmlSink,\n value: unknown,\n options: HydrationScriptOptions = {},\n): void {\n sink.append(\n `<script type=\"application/json\" data-mreact-ssr-state${renderNonceAttribute(options.nonce)}>${serializeSsrState(value)}</script>`,\n );\n}\n\nexport function createEventHydrationManifest(\n events: readonly EventHydrationEntry[],\n): EventHydrationManifest {\n return {\n version: 1,\n events: events.map((event) => ({ ...event })),\n };\n}\n\nexport function renderEventHydrationManifest(\n sink: HtmlSink,\n manifest: EventHydrationManifest,\n options: HydrationScriptOptions = {},\n): void {\n sink.append(\n `<script type=\"application/json\" data-mreact-event-manifest${renderNonceAttribute(options.nonce)}>${serializeSsrState(manifest)}</script>`,\n );\n}\n\nexport function renderScriptAsset(sink: HtmlSink, options: ScriptAssetOptions): void {\n const integrityAttribute =\n options.integrity === undefined ? \"\" : ` integrity=\"${escapeAttribute(options.integrity)}\"`;\n const crossOrigin =\n options.integrity === undefined ? options.crossOrigin : (options.crossOrigin ?? \"anonymous\");\n const crossOriginAttribute =\n crossOrigin === undefined ? \"\" : ` crossorigin=\"${escapeAttribute(crossOrigin)}\"`;\n\n sink.append(\n `<script src=\"${escapeAttribute(options.src)}\"${renderNonceAttribute(options.nonce)}${integrityAttribute}${crossOriginAttribute}></script>`,\n );\n}\n\nexport function html(node: unknown, options: HtmlResponseOptions = {}): Response {\n const headers = new Headers(options.headers);\n const responseOptions: ResponseInit = { headers };\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html; charset=utf-8\");\n }\n\n if (options.status !== undefined) {\n responseOptions.status = options.status;\n }\n\n if (options.statusText !== undefined) {\n responseOptions.statusText = options.statusText;\n }\n\n return new Response(\n renderToReadableStream((sink) => {\n const state: HtmlRenderState = { suspenseId: 0 };\n return appendReactNode(sink, node, state);\n }),\n responseOptions,\n );\n}\n\nexport async function renderToString(render: StreamRender): Promise<string> {\n const sink = createStringSink();\n\n await render(sink);\n await sink.drain();\n\n return sink.toString();\n}\n\nexport async function renderReactNodeToString(node: unknown): Promise<string> {\n const sink = createStringSink();\n const state: HtmlRenderState = { suspenseId: 0 };\n\n await appendReactNode(sink, node, state);\n await sink.drain();\n\n return sink.toString();\n}\n\ninterface HtmlRenderState {\n suspenseId: number;\n}\n\nfunction appendReactNode(\n sink: HtmlSink,\n node: unknown,\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n if (isPromiseLikeNode(node)) {\n return node.then((resolved) => appendReactNode(sink, resolved, state));\n }\n\n if (node === null || node === undefined || typeof node === \"boolean\") {\n return;\n }\n\n if (typeof node === \"string\" || typeof node === \"number\") {\n sink.append(escapeHtml(node));\n return;\n }\n\n if (Array.isArray(node)) {\n return appendReactNodeList(sink, node, state);\n }\n\n if (!isValidElement(node)) {\n return;\n }\n\n return appendReactElement(sink, node, state);\n}\n\nfunction appendReactNodeList(\n sink: HtmlSink,\n nodes: readonly unknown[],\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n let chain: PromiseLike<void> | undefined;\n\n for (const node of nodes) {\n if (chain !== undefined) {\n const buffered = renderReactNodeToBufferedString(node, state);\n chain = chain.then(() => appendBufferedSinkAfterResult(sink, buffered));\n continue;\n }\n\n const result = appendReactNode(sink, node, state);\n\n if (isPromiseLike(result)) {\n chain = result;\n }\n }\n\n return chain;\n}\n\nfunction renderReactNodeToBufferedString(\n node: unknown,\n state: HtmlRenderState,\n): { result: void | PromiseLike<void>; sink: ReturnType<typeof createStringSink> } {\n const sink = createStringSink();\n\n return {\n result: appendReactNode(sink, node, state),\n sink,\n };\n}\n\nfunction appendReactElement(\n sink: HtmlSink,\n element: ReactCompatElement,\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n if (typeof element.type === \"string\") {\n return appendHostElement(sink, element, state);\n }\n\n if (element.type === Fragment) {\n return appendReactNode(sink, element.props.children, state);\n }\n\n if (element.type === ReactCompatSuspense) {\n return appendSuspenseElement(sink, element, state);\n }\n\n if (isClassComponentType(element.type)) {\n const instance = new element.type(element.props);\n return appendReactNode(sink, instance.render(), state);\n }\n\n if (typeof element.type === \"function\") {\n return appendReactNode(sink, element.type(element.props), state);\n }\n}\n\nfunction isClassComponentType(\n value: unknown,\n): value is new (props: Record<string, unknown>) => { render(): ReactCompatNode } {\n return typeof value === \"function\" && value.prototype?.render !== undefined;\n}\n\nfunction appendHostElement(\n sink: HtmlSink,\n element: ReactCompatElement,\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n const tagName = element.type as string;\n const innerHtml = (element.props as { dangerouslySetInnerHTML?: { __html?: unknown } })\n .dangerouslySetInnerHTML;\n sink.append(`<${tagName}${renderHtmlAttributes(element.props)}>`);\n\n if (isVoidHtmlElement(tagName)) {\n return;\n }\n\n if (innerHtml !== undefined) {\n sink.append(String(innerHtml.__html ?? \"\"));\n sink.append(`</${tagName}>`);\n return;\n }\n\n const result = isRawTextElement(tagName)\n ? appendRawTextNode(sink, element.props.children)\n : appendReactNode(sink, element.props.children, state);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(`</${tagName}>`);\n });\n }\n\n sink.append(`</${tagName}>`);\n}\n\nfunction isRawTextElement(tagName: string): boolean {\n return tagName === \"script\" || tagName === \"style\";\n}\n\nfunction appendRawTextNode(sink: HtmlSink, node: unknown): void | PromiseLike<void> {\n if (isPromiseLikeNode(node)) {\n return node.then((resolved) => appendRawTextNode(sink, resolved));\n }\n\n if (node === null || node === undefined || typeof node === \"boolean\") {\n return;\n }\n\n if (Array.isArray(node)) {\n return appendRawTextNodeList(sink, node);\n }\n\n if (typeof node === \"string\" || typeof node === \"number\") {\n sink.append(String(node));\n }\n}\n\nfunction appendRawTextNodeList(\n sink: HtmlSink,\n nodes: readonly unknown[],\n): void | PromiseLike<void> {\n let chain: PromiseLike<void> | undefined;\n\n for (const node of nodes) {\n if (chain !== undefined) {\n const buffered = renderRawTextNodeToBufferedString(node);\n chain = chain.then(() => appendBufferedSinkAfterResult(sink, buffered));\n continue;\n }\n\n const result = appendRawTextNode(sink, node);\n\n if (isPromiseLike(result)) {\n chain = result;\n }\n }\n\n return chain;\n}\n\nfunction renderRawTextNodeToBufferedString(\n node: unknown,\n): { result: void | PromiseLike<void>; sink: ReturnType<typeof createStringSink> } {\n const sink = createStringSink();\n\n return {\n result: appendRawTextNode(sink, node),\n sink,\n };\n}\n\nasync function appendBufferedSinkAfterResult(\n sink: HtmlSink,\n buffered: { result: void | PromiseLike<void>; sink: ReturnType<typeof createStringSink> },\n): Promise<void> {\n await buffered.result;\n const shell = buffered.sink.toString();\n sink.append(shell);\n\n if (!hasDeferredTasks(buffered.sink)) {\n return;\n }\n\n const appendDeferredTail = buffered.sink.drain().then(() => {\n const resolved = buffered.sink.toString();\n sink.append(resolved.slice(shell.length));\n });\n\n if (sink.defer !== undefined) {\n sink.defer(appendDeferredTail);\n return;\n }\n\n await appendDeferredTail;\n}\n\nfunction appendSuspenseElement(\n sink: HtmlSink,\n element: ReactCompatElement,\n state: HtmlRenderState,\n): void {\n const rendered = renderReactNodeChildrenToString(element.props.children, state);\n\n if (!isPromiseLikeString(rendered)) {\n renderReactSuspenseBoundary(sink, (boundarySink) => {\n boundarySink.append(rendered);\n });\n return;\n }\n\n const id = state.suspenseId;\n state.suspenseId += 1;\n renderReactSuspenseOutOfOrderBoundary(\n sink,\n `B:${id}`,\n `S:${id}`,\n rendered,\n (boundarySink, renderedHtml) => {\n boundarySink.append(renderedHtml);\n },\n {\n fallback(boundarySink) {\n const fallback = renderReactNodeChildrenToString(\n (element.props as { fallback?: ReactCompatNode }).fallback,\n state,\n );\n\n if (isPromiseLikeString(fallback)) {\n return fallback.then((html) => {\n boundarySink.append(html);\n });\n }\n\n boundarySink.append(fallback);\n },\n },\n );\n}\n\nfunction renderReactNodeChildrenToString(\n node: unknown,\n state: HtmlRenderState,\n): string | PromiseLike<string> {\n const sink = createStringSink();\n const result = appendReactNode(sink, node, state);\n const finish = () =>\n hasDeferredTasks(sink) ? sink.drain().then(() => sink.toString()) : sink.toString();\n\n if (isPromiseLike(result)) {\n return result.then(finish);\n }\n\n return finish();\n}\n\nfunction renderHtmlAttributes(props: Record<string, unknown>): string {\n // Issue 078: <meta http-equiv=\"refresh\" content=\"0;url=javascript:...\">\n // is URL-bearing only when http-equiv is \"refresh\", so we need both\n // attributes in scope to make the call. Strip the unsafe content\n // before per-attribute rendering.\n const sanitizedProps = sanitizeMetaRefreshProps(props);\n return Object.entries(sanitizedProps)\n .map(([name, value]) => renderHtmlAttribute(name, value))\n .filter((attribute) => attribute !== \"\")\n .join(\"\");\n}\n\nfunction sanitizeMetaRefreshProps(\n props: Record<string, unknown>,\n): Record<string, unknown> {\n const httpEquiv = props[\"http-equiv\"] ?? props.httpEquiv;\n const content = props[\"content\"];\n if (typeof httpEquiv !== \"string\" || typeof content !== \"string\") return props;\n if (!isUnsafeMetaRefreshContent(httpEquiv, content)) return props;\n // Drop only `content`; keep http-equiv so the developer's intent is\n // still visible in the rendered HTML (debugging hint).\n const sanitized = { ...props };\n delete sanitized[\"content\"];\n return sanitized;\n}\n\n// Mirrors `isAttributeNameSafe` in react-dom: an attribute name must start with\n// an ASCII letter (or underscore) and contain only word chars, dot, hyphen, or\n// colon. Anything else is dropped to prevent SSR XSS via spread props\n// (`<div {...userControlled} />`). See docs/issues/resolved Issue 060.\nconst VALID_ATTRIBUTE_NAME = /^[A-Za-z_][\\w.\\-:]*$/;\n\n// URL scheme allow/block list is shared with the compiler emit paths\n// (Issues 062 / 073). See packages/server/src/url-safety.ts.\n\nfunction renderHtmlAttribute(name: string, value: unknown): string {\n if (\n name === \"children\" ||\n name === \"dangerouslySetInnerHTML\" ||\n name === \"key\" ||\n name === \"ref\" ||\n value === null ||\n value === undefined ||\n typeof value === \"function\" ||\n /^on/i.test(name)\n ) {\n return \"\";\n }\n\n const attributeName = toHtmlAttributeName(name);\n\n if (!VALID_ATTRIBUTE_NAME.test(attributeName)) {\n return \"\";\n }\n\n if (/^on/i.test(attributeName)) {\n return \"\";\n }\n\n if (value === false && !isBooleanishStringAttribute(attributeName)) {\n return \"\";\n }\n\n // Issue 077: HTML-bearing attributes (`srcdoc`) require the explicit\n // `{ __html: \"...\" }` opt-in. A plain string value -- even if escaped\n // for the attribute syntax -- decodes back to executable HTML inside\n // the iframe document with the parent's origin.\n if (isDangerousHtmlAttribute(attributeName)) {\n if (!isDangerousHtmlOptIn(value)) {\n return \"\";\n }\n return ` ${attributeName}=\"${escapeAttribute(value.__html)}\"`;\n }\n\n if (value === true) {\n if (isBooleanishStringAttribute(attributeName)) {\n return ` ${attributeName}=\"true\"`;\n }\n return ` ${attributeName}`;\n }\n\n if (value === false) {\n return ` ${attributeName}=\"false\"`;\n }\n\n const stringValue = String(value);\n\n if (isUnsafeUrlAttribute(attributeName, stringValue)) {\n return \"\";\n }\n\n return ` ${attributeName}=\"${escapeAttribute(stringValue)}\"`;\n}\n\nfunction toHtmlAttributeName(name: string): string {\n return HTML_ATTRIBUTE_ALIASES[name] ?? name;\n}\n\nconst HTML_ATTRIBUTE_ALIASES: Record<string, string> = {\n acceptCharset: \"accept-charset\",\n autoFocus: \"autofocus\",\n autoPlay: \"autoplay\",\n charSet: \"charset\",\n className: \"class\",\n colSpan: \"colspan\",\n contentEditable: \"contenteditable\",\n crossOrigin: \"crossorigin\",\n encType: \"enctype\",\n formAction: \"formaction\",\n frameBorder: \"frameborder\",\n htmlFor: \"for\",\n httpEquiv: \"http-equiv\",\n maxLength: \"maxlength\",\n minLength: \"minlength\",\n noValidate: \"novalidate\",\n playsInline: \"playsinline\",\n readOnly: \"readonly\",\n rowSpan: \"rowspan\",\n spellCheck: \"spellcheck\",\n srcDoc: \"srcdoc\",\n srcSet: \"srcset\",\n tabIndex: \"tabindex\",\n useMap: \"usemap\",\n};\n\nfunction isBooleanishStringAttribute(name: string): boolean {\n const attributeName = name;\n\n if (\n attributeName.startsWith(\"aria-\") ||\n attributeName.startsWith(\"data-\") ||\n BOOLEANISH_STRING_ATTRIBUTES.has(attributeName)\n ) {\n return true;\n }\n\n if (!hasAsciiUppercase(attributeName)) {\n return false;\n }\n\n const lowerAttributeName = attributeName.toLowerCase();\n return (\n lowerAttributeName.startsWith(\"aria-\") ||\n lowerAttributeName.startsWith(\"data-\") ||\n BOOLEANISH_STRING_ATTRIBUTES.has(lowerAttributeName)\n );\n}\n\nconst BOOLEANISH_STRING_ATTRIBUTES = new Set<string>([\n \"contenteditable\",\n \"draggable\",\n \"spellcheck\",\n]);\n\nfunction hasAsciiUppercase(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code >= 65 && code <= 90) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction isPromiseLikeNode(value: unknown): value is PromiseLike<unknown> {\n return isPromiseLikeUnknown(value);\n}\n\nfunction isPromiseLikeString(value: unknown): value is PromiseLike<string> {\n return isPromiseLikeUnknown(value);\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<void> {\n return isPromiseLikeUnknown(value);\n}\n"]}
1
+ {"version":3,"file":"html-helpers.js","sourceRoot":"","sources":["../src/html-helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Fragment,\n Suspense as ReactCompatSuspense,\n isValidElement,\n type ReactCompatElement,\n type ReactCompatNode,\n} from \"@reckona/mreact-compat\";\nimport type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\nimport { escapeHtmlText as escapeHtml } from \"@reckona/mreact-shared/html-escape\";\nimport { isVoidHtmlElement } from \"@reckona/mreact-shared\";\nimport {\n renderReactSuspenseBoundary,\n renderReactSuspenseOutOfOrderBoundary,\n type HydrationScriptOptions,\n} from \"./boundary.js\";\nimport {\n isDangerousHtmlAttribute,\n isDangerousHtmlOptIn,\n isUnsafeMetaRefreshContent,\n isUnsafeUrlAttribute,\n} from \"./url-safety.js\";\nimport {\n escapeAttribute,\n isPromiseLikeUnknown,\n renderNonceAttribute,\n serializeScriptJson,\n} from \"./html-internals.js\";\nimport { createStringSink, hasDeferredTasks, type StreamRender } from \"./sink.js\";\nimport { renderToReadableStream } from \"./stream.js\";\n\n/** External script asset attributes emitted by renderScriptAsset. */\nexport interface ScriptAssetOptions {\n src: string;\n nonce?: string;\n integrity?: string;\n crossOrigin?: \"anonymous\" | \"use-credentials\";\n}\n\n/** Event handler entry used by the hydration manifest. */\nexport interface EventHydrationEntry {\n id: string;\n event: string;\n handler: string;\n}\n\n/** Manifest of event handlers that can be hydrated on the client. */\nexport interface EventHydrationManifest {\n version: 1;\n events: EventHydrationEntry[];\n}\n\n/** Response options used when wrapping rendered HTML in a Response. */\nexport interface HtmlResponseOptions {\n headers?: HeadersInit;\n status?: number;\n statusText?: string;\n}\n\n/** Serializes state for safe embedding in an HTML script tag. */\nexport function serializeSsrState(value: unknown): string {\n return serializeScriptJson(value);\n}\n\n/** Appends serialized SSR state as a JSON script tag. */\nexport function renderSsrState(\n sink: HtmlSink,\n value: unknown,\n options: HydrationScriptOptions = {},\n): void {\n sink.append(\n `<script type=\"application/json\" data-mreact-ssr-state${renderNonceAttribute(options.nonce)}>${serializeSsrState(value)}</script>`,\n );\n}\n\n/** Creates a defensive copy of an event hydration manifest. */\nexport function createEventHydrationManifest(\n events: readonly EventHydrationEntry[],\n): EventHydrationManifest {\n return {\n version: 1,\n events: events.map((event) => ({ ...event })),\n };\n}\n\n/** Appends an event hydration manifest as a JSON script tag. */\nexport function renderEventHydrationManifest(\n sink: HtmlSink,\n manifest: EventHydrationManifest,\n options: HydrationScriptOptions = {},\n): void {\n sink.append(\n `<script type=\"application/json\" data-mreact-event-manifest${renderNonceAttribute(options.nonce)}>${serializeSsrState(manifest)}</script>`,\n );\n}\n\n/** Appends an external script tag with optional nonce and integrity attributes. */\nexport function renderScriptAsset(sink: HtmlSink, options: ScriptAssetOptions): void {\n const integrityAttribute =\n options.integrity === undefined ? \"\" : ` integrity=\"${escapeAttribute(options.integrity)}\"`;\n const crossOrigin =\n options.integrity === undefined ? options.crossOrigin : (options.crossOrigin ?? \"anonymous\");\n const crossOriginAttribute =\n crossOrigin === undefined ? \"\" : ` crossorigin=\"${escapeAttribute(crossOrigin)}\"`;\n\n sink.append(\n `<script src=\"${escapeAttribute(options.src)}\"${renderNonceAttribute(options.nonce)}${integrityAttribute}${crossOriginAttribute}></script>`,\n );\n}\n\n/** Creates an HTML Response from a React-compatible node. */\nexport function html(node: unknown, options: HtmlResponseOptions = {}): Response {\n const headers = new Headers(options.headers);\n const responseOptions: ResponseInit = { headers };\n\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"text/html; charset=utf-8\");\n }\n\n if (options.status !== undefined) {\n responseOptions.status = options.status;\n }\n\n if (options.statusText !== undefined) {\n responseOptions.statusText = options.statusText;\n }\n\n return new Response(\n renderToReadableStream((sink) => {\n const state: HtmlRenderState = { suspenseId: 0 };\n return appendReactNode(sink, node, state);\n }),\n responseOptions,\n );\n}\n\n/** Renders sink output to a string after awaiting deferred work. */\nexport async function renderToString(render: StreamRender): Promise<string> {\n const sink = createStringSink();\n\n await render(sink);\n await sink.drain();\n\n return sink.toString();\n}\n\n/** Renders a React-compatible node to an HTML string. */\nexport async function renderReactNodeToString(node: unknown): Promise<string> {\n const sink = createStringSink();\n const state: HtmlRenderState = { suspenseId: 0 };\n\n await appendReactNode(sink, node, state);\n await sink.drain();\n\n return sink.toString();\n}\n\ninterface HtmlRenderState {\n suspenseId: number;\n}\n\nfunction appendReactNode(\n sink: HtmlSink,\n node: unknown,\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n if (isPromiseLikeNode(node)) {\n return node.then((resolved) => appendReactNode(sink, resolved, state));\n }\n\n if (node === null || node === undefined || typeof node === \"boolean\") {\n return;\n }\n\n if (typeof node === \"string\" || typeof node === \"number\") {\n sink.append(escapeHtml(node));\n return;\n }\n\n if (Array.isArray(node)) {\n return appendReactNodeList(sink, node, state);\n }\n\n if (!isValidElement(node)) {\n return;\n }\n\n return appendReactElement(sink, node, state);\n}\n\nfunction appendReactNodeList(\n sink: HtmlSink,\n nodes: readonly unknown[],\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n let chain: PromiseLike<void> | undefined;\n\n for (const node of nodes) {\n if (chain !== undefined) {\n const buffered = renderReactNodeToBufferedString(node, state);\n chain = chain.then(() => appendBufferedSinkAfterResult(sink, buffered));\n continue;\n }\n\n const result = appendReactNode(sink, node, state);\n\n if (isPromiseLike(result)) {\n chain = result;\n }\n }\n\n return chain;\n}\n\nfunction renderReactNodeToBufferedString(\n node: unknown,\n state: HtmlRenderState,\n): { result: void | PromiseLike<void>; sink: ReturnType<typeof createStringSink> } {\n const sink = createStringSink();\n\n return {\n result: appendReactNode(sink, node, state),\n sink,\n };\n}\n\nfunction appendReactElement(\n sink: HtmlSink,\n element: ReactCompatElement,\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n if (typeof element.type === \"string\") {\n return appendHostElement(sink, element, state);\n }\n\n if (element.type === Fragment) {\n return appendReactNode(sink, element.props.children, state);\n }\n\n if (element.type === ReactCompatSuspense) {\n return appendSuspenseElement(sink, element, state);\n }\n\n if (isClassComponentType(element.type)) {\n const instance = new element.type(element.props);\n return appendReactNode(sink, instance.render(), state);\n }\n\n if (typeof element.type === \"function\") {\n return appendReactNode(sink, element.type(element.props), state);\n }\n}\n\nfunction isClassComponentType(\n value: unknown,\n): value is new (props: Record<string, unknown>) => { render(): ReactCompatNode } {\n return typeof value === \"function\" && value.prototype?.render !== undefined;\n}\n\nfunction appendHostElement(\n sink: HtmlSink,\n element: ReactCompatElement,\n state: HtmlRenderState,\n): void | PromiseLike<void> {\n const tagName = element.type as string;\n const innerHtml = (element.props as { dangerouslySetInnerHTML?: { __html?: unknown } })\n .dangerouslySetInnerHTML;\n sink.append(`<${tagName}${renderHtmlAttributes(element.props)}>`);\n\n if (isVoidHtmlElement(tagName)) {\n return;\n }\n\n if (innerHtml !== undefined) {\n sink.append(String(innerHtml.__html ?? \"\"));\n sink.append(`</${tagName}>`);\n return;\n }\n\n const result = isRawTextElement(tagName)\n ? appendRawTextNode(sink, element.props.children)\n : appendReactNode(sink, element.props.children, state);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(`</${tagName}>`);\n });\n }\n\n sink.append(`</${tagName}>`);\n}\n\nfunction isRawTextElement(tagName: string): boolean {\n return tagName === \"script\" || tagName === \"style\";\n}\n\nfunction appendRawTextNode(sink: HtmlSink, node: unknown): void | PromiseLike<void> {\n if (isPromiseLikeNode(node)) {\n return node.then((resolved) => appendRawTextNode(sink, resolved));\n }\n\n if (node === null || node === undefined || typeof node === \"boolean\") {\n return;\n }\n\n if (Array.isArray(node)) {\n return appendRawTextNodeList(sink, node);\n }\n\n if (typeof node === \"string\" || typeof node === \"number\") {\n sink.append(String(node));\n }\n}\n\nfunction appendRawTextNodeList(\n sink: HtmlSink,\n nodes: readonly unknown[],\n): void | PromiseLike<void> {\n let chain: PromiseLike<void> | undefined;\n\n for (const node of nodes) {\n if (chain !== undefined) {\n const buffered = renderRawTextNodeToBufferedString(node);\n chain = chain.then(() => appendBufferedSinkAfterResult(sink, buffered));\n continue;\n }\n\n const result = appendRawTextNode(sink, node);\n\n if (isPromiseLike(result)) {\n chain = result;\n }\n }\n\n return chain;\n}\n\nfunction renderRawTextNodeToBufferedString(\n node: unknown,\n): { result: void | PromiseLike<void>; sink: ReturnType<typeof createStringSink> } {\n const sink = createStringSink();\n\n return {\n result: appendRawTextNode(sink, node),\n sink,\n };\n}\n\nasync function appendBufferedSinkAfterResult(\n sink: HtmlSink,\n buffered: { result: void | PromiseLike<void>; sink: ReturnType<typeof createStringSink> },\n): Promise<void> {\n await buffered.result;\n const shell = buffered.sink.toString();\n sink.append(shell);\n\n if (!hasDeferredTasks(buffered.sink)) {\n return;\n }\n\n const appendDeferredTail = buffered.sink.drain().then(() => {\n const resolved = buffered.sink.toString();\n sink.append(resolved.slice(shell.length));\n });\n\n if (sink.defer !== undefined) {\n sink.defer(appendDeferredTail);\n return;\n }\n\n await appendDeferredTail;\n}\n\nfunction appendSuspenseElement(\n sink: HtmlSink,\n element: ReactCompatElement,\n state: HtmlRenderState,\n): void {\n const rendered = renderReactNodeChildrenToString(element.props.children, state);\n\n if (!isPromiseLikeString(rendered)) {\n renderReactSuspenseBoundary(sink, (boundarySink) => {\n boundarySink.append(rendered);\n });\n return;\n }\n\n const id = state.suspenseId;\n state.suspenseId += 1;\n renderReactSuspenseOutOfOrderBoundary(\n sink,\n `B:${id}`,\n `S:${id}`,\n rendered,\n (boundarySink, renderedHtml) => {\n boundarySink.append(renderedHtml);\n },\n {\n fallback(boundarySink) {\n const fallback = renderReactNodeChildrenToString(\n (element.props as { fallback?: ReactCompatNode }).fallback,\n state,\n );\n\n if (isPromiseLikeString(fallback)) {\n return fallback.then((html) => {\n boundarySink.append(html);\n });\n }\n\n boundarySink.append(fallback);\n },\n },\n );\n}\n\nfunction renderReactNodeChildrenToString(\n node: unknown,\n state: HtmlRenderState,\n): string | PromiseLike<string> {\n const sink = createStringSink();\n const result = appendReactNode(sink, node, state);\n const finish = () =>\n hasDeferredTasks(sink) ? sink.drain().then(() => sink.toString()) : sink.toString();\n\n if (isPromiseLike(result)) {\n return result.then(finish);\n }\n\n return finish();\n}\n\nfunction renderHtmlAttributes(props: Record<string, unknown>): string {\n // Issue 078: <meta http-equiv=\"refresh\" content=\"0;url=javascript:...\">\n // is URL-bearing only when http-equiv is \"refresh\", so we need both\n // attributes in scope to make the call. Strip the unsafe content\n // before per-attribute rendering.\n const sanitizedProps = sanitizeMetaRefreshProps(props);\n return Object.entries(sanitizedProps)\n .map(([name, value]) => renderHtmlAttribute(name, value))\n .filter((attribute) => attribute !== \"\")\n .join(\"\");\n}\n\nfunction sanitizeMetaRefreshProps(\n props: Record<string, unknown>,\n): Record<string, unknown> {\n const httpEquiv = props[\"http-equiv\"] ?? props.httpEquiv;\n const content = props[\"content\"];\n if (typeof httpEquiv !== \"string\" || typeof content !== \"string\") return props;\n if (!isUnsafeMetaRefreshContent(httpEquiv, content)) return props;\n // Drop only `content`; keep http-equiv so the developer's intent is\n // still visible in the rendered HTML (debugging hint).\n const sanitized = { ...props };\n delete sanitized[\"content\"];\n return sanitized;\n}\n\n// Mirrors `isAttributeNameSafe` in react-dom: an attribute name must start with\n// an ASCII letter (or underscore) and contain only word chars, dot, hyphen, or\n// colon. Anything else is dropped to prevent SSR XSS via spread props\n// (`<div {...userControlled} />`). See docs/issues/resolved Issue 060.\nconst VALID_ATTRIBUTE_NAME = /^[A-Za-z_][\\w.\\-:]*$/;\n\n// URL scheme allow/block list is shared with the compiler emit paths\n// (Issues 062 / 073). See packages/server/src/url-safety.ts.\n\nfunction renderHtmlAttribute(name: string, value: unknown): string {\n if (\n name === \"children\" ||\n name === \"dangerouslySetInnerHTML\" ||\n name === \"key\" ||\n name === \"ref\" ||\n value === null ||\n value === undefined ||\n typeof value === \"function\" ||\n /^on/i.test(name)\n ) {\n return \"\";\n }\n\n const attributeName = toHtmlAttributeName(name);\n\n if (!VALID_ATTRIBUTE_NAME.test(attributeName)) {\n return \"\";\n }\n\n if (/^on/i.test(attributeName)) {\n return \"\";\n }\n\n if (value === false && !isBooleanishStringAttribute(attributeName)) {\n return \"\";\n }\n\n // Issue 077: HTML-bearing attributes (`srcdoc`) require the explicit\n // `{ __html: \"...\" }` opt-in. A plain string value -- even if escaped\n // for the attribute syntax -- decodes back to executable HTML inside\n // the iframe document with the parent's origin.\n if (isDangerousHtmlAttribute(attributeName)) {\n if (!isDangerousHtmlOptIn(value)) {\n return \"\";\n }\n return ` ${attributeName}=\"${escapeAttribute(value.__html)}\"`;\n }\n\n if (value === true) {\n if (isBooleanishStringAttribute(attributeName)) {\n return ` ${attributeName}=\"true\"`;\n }\n return ` ${attributeName}`;\n }\n\n if (value === false) {\n return ` ${attributeName}=\"false\"`;\n }\n\n const stringValue = String(value);\n\n if (isUnsafeUrlAttribute(attributeName, stringValue)) {\n return \"\";\n }\n\n return ` ${attributeName}=\"${escapeAttribute(stringValue)}\"`;\n}\n\nfunction toHtmlAttributeName(name: string): string {\n return HTML_ATTRIBUTE_ALIASES[name] ?? name;\n}\n\nconst HTML_ATTRIBUTE_ALIASES: Record<string, string> = {\n acceptCharset: \"accept-charset\",\n autoFocus: \"autofocus\",\n autoPlay: \"autoplay\",\n charSet: \"charset\",\n className: \"class\",\n colSpan: \"colspan\",\n contentEditable: \"contenteditable\",\n crossOrigin: \"crossorigin\",\n encType: \"enctype\",\n formAction: \"formaction\",\n frameBorder: \"frameborder\",\n htmlFor: \"for\",\n httpEquiv: \"http-equiv\",\n maxLength: \"maxlength\",\n minLength: \"minlength\",\n noValidate: \"novalidate\",\n playsInline: \"playsinline\",\n readOnly: \"readonly\",\n rowSpan: \"rowspan\",\n spellCheck: \"spellcheck\",\n srcDoc: \"srcdoc\",\n srcSet: \"srcset\",\n tabIndex: \"tabindex\",\n useMap: \"usemap\",\n};\n\nfunction isBooleanishStringAttribute(name: string): boolean {\n const attributeName = name;\n\n if (\n attributeName.startsWith(\"aria-\") ||\n attributeName.startsWith(\"data-\") ||\n BOOLEANISH_STRING_ATTRIBUTES.has(attributeName)\n ) {\n return true;\n }\n\n if (!hasAsciiUppercase(attributeName)) {\n return false;\n }\n\n const lowerAttributeName = attributeName.toLowerCase();\n return (\n lowerAttributeName.startsWith(\"aria-\") ||\n lowerAttributeName.startsWith(\"data-\") ||\n BOOLEANISH_STRING_ATTRIBUTES.has(lowerAttributeName)\n );\n}\n\nconst BOOLEANISH_STRING_ATTRIBUTES = new Set<string>([\n \"contenteditable\",\n \"draggable\",\n \"spellcheck\",\n]);\n\nfunction hasAsciiUppercase(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code >= 65 && code <= 90) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction isPromiseLikeNode(value: unknown): value is PromiseLike<unknown> {\n return isPromiseLikeUnknown(value);\n}\n\nfunction isPromiseLikeString(value: unknown): value is PromiseLike<string> {\n return isPromiseLikeUnknown(value);\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<void> {\n return isPromiseLikeUnknown(value);\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
+ /** Fragment marker used to group children without emitting an extra element. */
1
2
  export { Fragment } from "@reckona/mreact-compat";
3
+ /** Any value accepted by the React-compatible renderer. */
2
4
  export type { ReactCompatNode } from "@reckona/mreact-compat";
5
+ /** Receives HTML chunks and deferred work while server rendering. */
3
6
  export type { HtmlSink } from "@reckona/mreact-shared/compiler-contract";
4
7
  export { CLIENT_REFERENCE_TYPE, SERVER_REFERENCE_TYPE, createClientReference, createFlightClientManifest, createServerReference, createServerActionHandler, fromReactFlightRows, getReactFlightProtocolCoverage, isClientReference, isServerReference, mergeReactFlightRows, renderFlightPreloadLinks, renderFlightResponseScript, renderToFlightResponse, stringifyFlightResponse, toReactFlightRows, } from "./flight.js";
5
8
  export type { ClientReference, FlightClientManifestEntry, FlightClientReference, FlightClientReferenceInput, FlightClientReferenceModel, FlightDataViewModel, FlightElementModel, FlightFormDataModel, FlightIterableModel, FlightModel, FlightResponse, FlightScriptOptions, FlightServerReference, FlightServerReferenceModel, FlightArrayBufferModel, FlightTypedArrayModel, FlightTypedArrayName, ServerAction, ServerActionDescriptor, ServerActionHandlerOptions, ServerActionRegistry, ServerActionReplayStore, ServerActionRequestReference, ServerActionValidationResult, ServerReference, } from "./flight.js";
@@ -11,9 +14,11 @@ export { reactSuspenseRevealExternalScript, renderAsyncBoundary, renderHydration
11
14
  export type { AsyncBoundaryOptions, AsyncBoundaryRender, HydrationScriptOptions, OutOfOrderBoundaryOptions, OutOfOrderReorderScriptOptions, ReactSuspenseBoundaryOptions, ReactSuspenseClientRenderOptions, ReactSuspenseScriptOptions, } from "./boundary.js";
12
15
  export { createEventHydrationManifest, html, renderEventHydrationManifest, renderReactNodeToString, renderScriptAsset, renderSsrState, renderToString, serializeSsrState, } from "./html-helpers.js";
13
16
  export type { EventHydrationEntry, EventHydrationManifest, HtmlResponseOptions, ScriptAssetOptions, } from "./html-helpers.js";
17
+ /** Props accepted by the server Suspense compatibility component. */
14
18
  export interface SuspenseProps extends Record<string, unknown> {
15
19
  fallback?: unknown;
16
20
  children?: unknown;
17
21
  }
22
+ /** Creates a React-compatible Suspense boundary for server rendering. */
18
23
  export declare function Suspense(props: SuspenseProps): never;
19
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAEzE,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,8BAA8B,EAC9B,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,eAAe,EACf,yBAAyB,EACzB,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,EACvB,4BAA4B,EAC5B,4BAA4B,EAC5B,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,YAAY,EACZ,cAAc,EACd,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,iCAAiC,EACjC,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,6BAA6B,EAC7B,2BAA2B,EAC3B,uCAAuC,EACvC,qCAAqC,GACtC,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,8BAA8B,EAC9B,4BAA4B,EAC5B,gCAAgC,EAChC,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,4BAA4B,EAC5B,IAAI,EACJ,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,CAYpD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,gFAAgF;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,2DAA2D;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,qEAAqE;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAEzE,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,8BAA8B,EAC9B,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,eAAe,EACf,yBAAyB,EACzB,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,sBAAsB,EACtB,0BAA0B,EAC1B,oBAAoB,EACpB,uBAAuB,EACvB,4BAA4B,EAC5B,4BAA4B,EAC5B,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,YAAY,EACZ,cAAc,EACd,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,6BAA6B,GAC9B,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,iCAAiC,EACjC,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,6BAA6B,EAC7B,2BAA2B,EAC3B,uCAAuC,EACvC,qCAAqC,GACtC,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,sBAAsB,EACtB,yBAAyB,EACzB,8BAA8B,EAC9B,4BAA4B,EAC5B,gCAAgC,EAChC,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,4BAA4B,EAC5B,IAAI,EACJ,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAE3B,qEAAqE;AACrE,MAAM,WAAW,aAAc,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,yEAAyE;AACzE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,KAAK,CAYpD"}
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import { Suspense as ReactCompatSuspense, createElement, } from "@reckona/mreact-compat";
2
+ /** Fragment marker used to group children without emitting an extra element. */
2
3
  export { Fragment } from "@reckona/mreact-compat";
3
4
  export { CLIENT_REFERENCE_TYPE, SERVER_REFERENCE_TYPE, createClientReference, createFlightClientManifest, createServerReference, createServerActionHandler, fromReactFlightRows, getReactFlightProtocolCoverage, isClientReference, isServerReference, mergeReactFlightRows, renderFlightPreloadLinks, renderFlightResponseScript, renderToFlightResponse, stringifyFlightResponse, toReactFlightRows, } from "./flight.js";
4
5
  export { createStringSink, } from "./sink.js";
5
6
  export { renderToReadableStream, } from "./stream.js";
6
7
  export { reactSuspenseRevealExternalScript, renderAsyncBoundary, renderHydrationBoundary, renderOutOfOrderBoundary, renderOutOfOrderReorderScript, renderReactSuspenseBoundary, renderReactSuspenseClientRenderBoundary, renderReactSuspenseOutOfOrderBoundary, } from "./boundary.js";
7
8
  export { createEventHydrationManifest, html, renderEventHydrationManifest, renderReactNodeToString, renderScriptAsset, renderSsrState, renderToString, serializeSsrState, } from "./html-helpers.js";
9
+ /** Creates a React-compatible Suspense boundary for server rendering. */
8
10
  export function Suspense(props) {
9
11
  const config = {};
10
12
  if (props.fallback !== undefined) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,mBAAmB,EAC/B,aAAa,GAEd,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAIlD,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,8BAA8B,EAC9B,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AA6BrB,OAAO,EACL,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAQnB,OAAO,EACL,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAKrB,OAAO,EACL,iCAAiC,EACjC,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,6BAA6B,EAC7B,2BAA2B,EAC3B,uCAAuC,EACvC,qCAAqC,GACtC,MAAM,eAAe,CAAC;AAYvB,OAAO,EACL,4BAA4B,EAC5B,IAAI,EACJ,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAa3B,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAA2B,CAAC;IACtD,CAAC;IAED,OAAO,aAAa,CAClB,mBAAmB,EACnB,MAAM,EACN,KAAK,CAAC,QAA2B,CACzB,CAAC;AACb,CAAC","sourcesContent":["import {\n Suspense as ReactCompatSuspense,\n createElement,\n type ReactCompatNode,\n} from \"@reckona/mreact-compat\";\n\nexport { Fragment } from \"@reckona/mreact-compat\";\nexport type { ReactCompatNode } from \"@reckona/mreact-compat\";\nexport type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\n\nexport {\n CLIENT_REFERENCE_TYPE,\n SERVER_REFERENCE_TYPE,\n createClientReference,\n createFlightClientManifest,\n createServerReference,\n createServerActionHandler,\n fromReactFlightRows,\n getReactFlightProtocolCoverage,\n isClientReference,\n isServerReference,\n mergeReactFlightRows,\n renderFlightPreloadLinks,\n renderFlightResponseScript,\n renderToFlightResponse,\n stringifyFlightResponse,\n toReactFlightRows,\n} from \"./flight.js\";\nexport type {\n ClientReference,\n FlightClientManifestEntry,\n FlightClientReference,\n FlightClientReferenceInput,\n FlightClientReferenceModel,\n FlightDataViewModel,\n FlightElementModel,\n FlightFormDataModel,\n FlightIterableModel,\n FlightModel,\n FlightResponse,\n FlightScriptOptions,\n FlightServerReference,\n FlightServerReferenceModel,\n FlightArrayBufferModel,\n FlightTypedArrayModel,\n FlightTypedArrayName,\n ServerAction,\n ServerActionDescriptor,\n ServerActionHandlerOptions,\n ServerActionRegistry,\n ServerActionReplayStore,\n ServerActionRequestReference,\n ServerActionValidationResult,\n ServerReference,\n} from \"./flight.js\";\n\nexport {\n createStringSink,\n} from \"./sink.js\";\nexport type {\n StreamRender,\n StringHtmlSink,\n StringSinkBufferStrategy,\n StringSinkOptions,\n} from \"./sink.js\";\n\nexport {\n renderToReadableStream,\n} from \"./stream.js\";\nexport type {\n RenderToReadableStreamOptions,\n} from \"./stream.js\";\n\nexport {\n reactSuspenseRevealExternalScript,\n renderAsyncBoundary,\n renderHydrationBoundary,\n renderOutOfOrderBoundary,\n renderOutOfOrderReorderScript,\n renderReactSuspenseBoundary,\n renderReactSuspenseClientRenderBoundary,\n renderReactSuspenseOutOfOrderBoundary,\n} from \"./boundary.js\";\nexport type {\n AsyncBoundaryOptions,\n AsyncBoundaryRender,\n HydrationScriptOptions,\n OutOfOrderBoundaryOptions,\n OutOfOrderReorderScriptOptions,\n ReactSuspenseBoundaryOptions,\n ReactSuspenseClientRenderOptions,\n ReactSuspenseScriptOptions,\n} from \"./boundary.js\";\n\nexport {\n createEventHydrationManifest,\n html,\n renderEventHydrationManifest,\n renderReactNodeToString,\n renderScriptAsset,\n renderSsrState,\n renderToString,\n serializeSsrState,\n} from \"./html-helpers.js\";\nexport type {\n EventHydrationEntry,\n EventHydrationManifest,\n HtmlResponseOptions,\n ScriptAssetOptions,\n} from \"./html-helpers.js\";\n\nexport interface SuspenseProps extends Record<string, unknown> {\n fallback?: unknown;\n children?: unknown;\n}\n\nexport function Suspense(props: SuspenseProps): never {\n const config: SuspenseProps = {};\n\n if (props.fallback !== undefined) {\n config.fallback = props.fallback as ReactCompatNode;\n }\n\n return createElement<SuspenseProps>(\n ReactCompatSuspense,\n config,\n props.children as ReactCompatNode,\n ) as never;\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,mBAAmB,EAC/B,aAAa,GAEd,MAAM,wBAAwB,CAAC;AAEhC,gFAAgF;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAMlD,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,yBAAyB,EACzB,mBAAmB,EACnB,8BAA8B,EAC9B,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,iBAAiB,GAClB,MAAM,aAAa,CAAC;AA6BrB,OAAO,EACL,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAQnB,OAAO,EACL,sBAAsB,GACvB,MAAM,aAAa,CAAC;AAKrB,OAAO,EACL,iCAAiC,EACjC,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,6BAA6B,EAC7B,2BAA2B,EAC3B,uCAAuC,EACvC,qCAAqC,GACtC,MAAM,eAAe,CAAC;AAYvB,OAAO,EACL,4BAA4B,EAC5B,IAAI,EACJ,4BAA4B,EAC5B,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAc3B,yEAAyE;AACzE,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC,QAA2B,CAAC;IACtD,CAAC;IAED,OAAO,aAAa,CAClB,mBAAmB,EACnB,MAAM,EACN,KAAK,CAAC,QAA2B,CACzB,CAAC;AACb,CAAC","sourcesContent":["import {\n Suspense as ReactCompatSuspense,\n createElement,\n type ReactCompatNode,\n} from \"@reckona/mreact-compat\";\n\n/** Fragment marker used to group children without emitting an extra element. */\nexport { Fragment } from \"@reckona/mreact-compat\";\n/** Any value accepted by the React-compatible renderer. */\nexport type { ReactCompatNode } from \"@reckona/mreact-compat\";\n/** Receives HTML chunks and deferred work while server rendering. */\nexport type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\n\nexport {\n CLIENT_REFERENCE_TYPE,\n SERVER_REFERENCE_TYPE,\n createClientReference,\n createFlightClientManifest,\n createServerReference,\n createServerActionHandler,\n fromReactFlightRows,\n getReactFlightProtocolCoverage,\n isClientReference,\n isServerReference,\n mergeReactFlightRows,\n renderFlightPreloadLinks,\n renderFlightResponseScript,\n renderToFlightResponse,\n stringifyFlightResponse,\n toReactFlightRows,\n} from \"./flight.js\";\nexport type {\n ClientReference,\n FlightClientManifestEntry,\n FlightClientReference,\n FlightClientReferenceInput,\n FlightClientReferenceModel,\n FlightDataViewModel,\n FlightElementModel,\n FlightFormDataModel,\n FlightIterableModel,\n FlightModel,\n FlightResponse,\n FlightScriptOptions,\n FlightServerReference,\n FlightServerReferenceModel,\n FlightArrayBufferModel,\n FlightTypedArrayModel,\n FlightTypedArrayName,\n ServerAction,\n ServerActionDescriptor,\n ServerActionHandlerOptions,\n ServerActionRegistry,\n ServerActionReplayStore,\n ServerActionRequestReference,\n ServerActionValidationResult,\n ServerReference,\n} from \"./flight.js\";\n\nexport {\n createStringSink,\n} from \"./sink.js\";\nexport type {\n StreamRender,\n StringHtmlSink,\n StringSinkBufferStrategy,\n StringSinkOptions,\n} from \"./sink.js\";\n\nexport {\n renderToReadableStream,\n} from \"./stream.js\";\nexport type {\n RenderToReadableStreamOptions,\n} from \"./stream.js\";\n\nexport {\n reactSuspenseRevealExternalScript,\n renderAsyncBoundary,\n renderHydrationBoundary,\n renderOutOfOrderBoundary,\n renderOutOfOrderReorderScript,\n renderReactSuspenseBoundary,\n renderReactSuspenseClientRenderBoundary,\n renderReactSuspenseOutOfOrderBoundary,\n} from \"./boundary.js\";\nexport type {\n AsyncBoundaryOptions,\n AsyncBoundaryRender,\n HydrationScriptOptions,\n OutOfOrderBoundaryOptions,\n OutOfOrderReorderScriptOptions,\n ReactSuspenseBoundaryOptions,\n ReactSuspenseClientRenderOptions,\n ReactSuspenseScriptOptions,\n} from \"./boundary.js\";\n\nexport {\n createEventHydrationManifest,\n html,\n renderEventHydrationManifest,\n renderReactNodeToString,\n renderScriptAsset,\n renderSsrState,\n renderToString,\n serializeSsrState,\n} from \"./html-helpers.js\";\nexport type {\n EventHydrationEntry,\n EventHydrationManifest,\n HtmlResponseOptions,\n ScriptAssetOptions,\n} from \"./html-helpers.js\";\n\n/** Props accepted by the server Suspense compatibility component. */\nexport interface SuspenseProps extends Record<string, unknown> {\n fallback?: unknown;\n children?: unknown;\n}\n\n/** Creates a React-compatible Suspense boundary for server rendering. */\nexport function Suspense(props: SuspenseProps): never {\n const config: SuspenseProps = {};\n\n if (props.fallback !== undefined) {\n config.fallback = props.fallback as ReactCompatNode;\n }\n\n return createElement<SuspenseProps>(\n ReactCompatSuspense,\n config,\n props.children as ReactCompatNode,\n ) as never;\n}\n"]}
package/dist/reorder.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ /** Moves out-of-order fragments into their matching placeholders within a DOM root. */
1
2
  export declare function applyOutOfOrderFragments(root?: ParentNode): void;
2
3
  //# sourceMappingURL=reorder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reorder.d.ts","sourceRoot":"","sources":["../src/reorder.ts"],"names":[],"mappings":"AAAA,wBAAgB,wBAAwB,CAAC,IAAI,GAAE,UAAqB,GAAG,IAAI,CAkC1E"}
1
+ {"version":3,"file":"reorder.d.ts","sourceRoot":"","sources":["../src/reorder.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,IAAI,GAAE,UAAqB,GAAG,IAAI,CAkC1E"}
package/dist/reorder.js CHANGED
@@ -1,3 +1,4 @@
1
+ /** Moves out-of-order fragments into their matching placeholders within a DOM root. */
1
2
  export function applyOutOfOrderFragments(root = document) {
2
3
  const fragments = Array.from(root.querySelectorAll("template[data-mreact-oob-fragment]"));
3
4
  for (const fragment of fragments) {
@@ -1 +1 @@
1
- {"version":3,"file":"reorder.js","sourceRoot":"","sources":["../src/reorder.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,wBAAwB,CAAC,OAAmB,QAAQ;IAClE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAC1B,IAAI,CAAC,gBAAgB,CACnB,oCAAoC,CACrC,CACF,CAAC;IAEF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC;QAE9C,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,SAAS;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CACjC,IAAI,CAAC,gBAAgB,CAAU,4BAA4B,CAAC,CAC7D,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,0BAA0B,CAAC,KAAK,EAAE,CAAC,CAAC;QAEjF,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CACpC,iCAAiC,SAAS,CAAC,EAAE,CAAC,IAAI,CACnD,CAAC;QAEF,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,SAAS;QACX,CAAC;QAED,WAAW,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,QAAQ,CAAC,MAAM,EAAE,CAAC;QAClB,gBAAgB,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACjE,CAAC","sourcesContent":["export function applyOutOfOrderFragments(root: ParentNode = document): void {\n const fragments = Array.from(\n root.querySelectorAll<HTMLTemplateElement>(\n \"template[data-mreact-oob-fragment]\",\n ),\n );\n\n for (const fragment of fragments) {\n const id = fragment.dataset.mreactOobFragment;\n\n if (id === undefined) {\n continue;\n }\n\n const completionMarker = Array.from(\n root.querySelectorAll<Element>(\"[data-mreact-oob-complete]\"),\n ).find((candidate) => candidate.getAttribute(\"data-mreact-oob-complete\") === id);\n\n if (completionMarker === undefined) {\n continue;\n }\n\n const placeholder = root.querySelector<Element>(\n `[data-mreact-oob-placeholder=\"${cssEscape(id)}\"]`,\n );\n\n if (placeholder === null) {\n continue;\n }\n\n placeholder.replaceWith(fragment.content.cloneNode(true));\n fragment.remove();\n completionMarker.remove();\n }\n}\n\nfunction cssEscape(value: string): string {\n return value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"\\\"\", \"\\\\\\\"\");\n}\n"]}
1
+ {"version":3,"file":"reorder.js","sourceRoot":"","sources":["../src/reorder.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,UAAU,wBAAwB,CAAC,OAAmB,QAAQ;IAClE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAC1B,IAAI,CAAC,gBAAgB,CACnB,oCAAoC,CACrC,CACF,CAAC;IAEF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,iBAAiB,CAAC;QAE9C,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,SAAS;QACX,CAAC;QAED,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI,CACjC,IAAI,CAAC,gBAAgB,CAAU,4BAA4B,CAAC,CAC7D,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,0BAA0B,CAAC,KAAK,EAAE,CAAC,CAAC;QAEjF,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,SAAS;QACX,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CACpC,iCAAiC,SAAS,CAAC,EAAE,CAAC,IAAI,CACnD,CAAC;QAEF,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,SAAS;QACX,CAAC;QAED,WAAW,CAAC,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,QAAQ,CAAC,MAAM,EAAE,CAAC;QAClB,gBAAgB,CAAC,MAAM,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACjE,CAAC","sourcesContent":["/** Moves out-of-order fragments into their matching placeholders within a DOM root. */\nexport function applyOutOfOrderFragments(root: ParentNode = document): void {\n const fragments = Array.from(\n root.querySelectorAll<HTMLTemplateElement>(\n \"template[data-mreact-oob-fragment]\",\n ),\n );\n\n for (const fragment of fragments) {\n const id = fragment.dataset.mreactOobFragment;\n\n if (id === undefined) {\n continue;\n }\n\n const completionMarker = Array.from(\n root.querySelectorAll<Element>(\"[data-mreact-oob-complete]\"),\n ).find((candidate) => candidate.getAttribute(\"data-mreact-oob-complete\") === id);\n\n if (completionMarker === undefined) {\n continue;\n }\n\n const placeholder = root.querySelector<Element>(\n `[data-mreact-oob-placeholder=\"${cssEscape(id)}\"]`,\n );\n\n if (placeholder === null) {\n continue;\n }\n\n placeholder.replaceWith(fragment.content.cloneNode(true));\n fragment.remove();\n completionMarker.remove();\n }\n}\n\nfunction cssEscape(value: string): string {\n return value.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"\\\"\", \"\\\\\\\"\");\n}\n"]}
package/dist/sink.d.ts CHANGED
@@ -1,15 +1,21 @@
1
1
  import type { HtmlSink } from "@reckona/mreact-shared/compiler-contract";
2
+ /** HTML sink that buffers output as a string and can await deferred tasks. */
2
3
  export interface StringHtmlSink extends HtmlSink {
3
4
  bufferStrategy(): StringSinkBufferStrategy;
4
5
  drain(): Promise<void>;
5
6
  toString(): string;
6
7
  }
8
+ /** String buffering strategy used by createStringSink. */
7
9
  export type StringSinkBufferStrategy = "concat" | "array-join";
10
+ /** Options controlling how a string sink buffers appended chunks. */
8
11
  export interface StringSinkOptions {
9
12
  strategy?: StringSinkBufferStrategy | "auto";
10
13
  arrayJoinThreshold?: number;
11
14
  }
15
+ /** Callback that writes server-rendered HTML into a sink. */
12
16
  export type StreamRender = (sink: HtmlSink) => void | PromiseLike<void>;
17
+ /** Creates an HTML sink that stores appended chunks in memory as a string. */
13
18
  export declare function createStringSink(options?: StringSinkOptions): StringHtmlSink;
19
+ /** Returns true when a sink created by createStringSink has deferred tasks. */
14
20
  export declare function hasDeferredTasks(sink: HtmlSink): boolean;
15
21
  //# sourceMappingURL=sink.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAEzE,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C,cAAc,IAAI,wBAAwB,CAAC;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE/D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAAC;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;AAIxE,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,cAAc,CA8DhF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAExD"}
1
+ {"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AAEzE,8EAA8E;AAC9E,MAAM,WAAW,cAAe,SAAQ,QAAQ;IAC9C,cAAc,IAAI,wBAAwB,CAAC;IAC3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED,0DAA0D;AAC1D,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE/D,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAAC;IAC7C,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;AAIxE,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,cAAc,CA8DhF;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAExD"}
package/dist/sink.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const stringSinkDeferredTasks = new WeakMap();
2
+ /** Creates an HTML sink that stores appended chunks in memory as a string. */
2
3
  export function createStringSink(options = {}) {
3
4
  // Default to "concat" - V8 rope flattening yields 2-6x throughput over
4
5
  // `Array#join("")` across all measured fixture sizes (see
@@ -54,6 +55,7 @@ export function createStringSink(options = {}) {
54
55
  stringSinkDeferredTasks.set(sink, deferredTasks);
55
56
  return sink;
56
57
  }
58
+ /** Returns true when a sink created by createStringSink has deferred tasks. */
57
59
  export function hasDeferredTasks(sink) {
58
60
  return (stringSinkDeferredTasks.get(sink)?.length ?? 0) > 0;
59
61
  }
package/dist/sink.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sink.js","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAiBA,MAAM,uBAAuB,GAAG,IAAI,OAAO,EAAiC,CAAC;AAE7E,MAAM,UAAU,gBAAgB,CAAC,UAA6B,EAAE;IAC9D,uEAAuE;IACvE,0DAA0D;IAC1D,0EAA0E;IAC1E,iEAAiE;IACjE,MAAM,iBAAiB,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC;IACvD,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,IAAI,GAAG,CAAC;IAC7D,MAAM,aAAa,GAAwB,EAAE,CAAC;IAC9C,IAAI,QAAQ,GAA6B,iBAAiB,KAAK,MAAM;QACnE,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,iBAAiB,CAAC;IACtB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,uBAAuB,GAAG,GAAG,EAAE;QACnC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,IAAI,GAAG,EAAE,CAAC;QACZ,CAAC;QACD,QAAQ,GAAG,YAAY,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,IAAI,GAAmB;QAC3B,MAAM,CAAC,KAAK;YACV,UAAU,IAAI,CAAC,CAAC;YAEhB,IAAI,iBAAiB,KAAK,MAAM,IAAI,QAAQ,KAAK,QAAQ,IAAI,UAAU,GAAG,kBAAkB,EAAE,CAAC;gBAC7F,uBAAuB,EAAE,CAAC;YAC5B,CAAC;YAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,IAAI,IAAI,KAAK,CAAC;gBACd,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,cAAc;YACZ,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,IAAI;YACR,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;QACD,QAAQ;YACN,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;KACF,CAAC;IAEF,uBAAuB,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAc;IAC7C,OAAO,CAAC,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["import type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\n\nexport interface StringHtmlSink extends HtmlSink {\n bufferStrategy(): StringSinkBufferStrategy;\n drain(): Promise<void>;\n toString(): string;\n}\n\nexport type StringSinkBufferStrategy = \"concat\" | \"array-join\";\n\nexport interface StringSinkOptions {\n strategy?: StringSinkBufferStrategy | \"auto\";\n arrayJoinThreshold?: number;\n}\n\nexport type StreamRender = (sink: HtmlSink) => void | PromiseLike<void>;\n\nconst stringSinkDeferredTasks = new WeakMap<HtmlSink, PromiseLike<void>[]>();\n\nexport function createStringSink(options: StringSinkOptions = {}): StringHtmlSink {\n // Default to \"concat\" - V8 rope flattening yields 2-6x throughput over\n // `Array#join(\"\")` across all measured fixture sizes (see\n // docs/benchmarks/2026-05-12-server-sink-strategy.md). \"array-join\" stays\n // available as opt-in for scenarios that need lower peak memory.\n const requestedStrategy = options.strategy ?? \"concat\";\n const arrayJoinThreshold = options.arrayJoinThreshold ?? 256;\n const deferredTasks: PromiseLike<void>[] = [];\n let strategy: StringSinkBufferStrategy = requestedStrategy === \"auto\"\n ? \"concat\"\n : requestedStrategy;\n let writeCount = 0;\n let text = \"\";\n const chunks: string[] = [];\n\n const switchConcatToArrayJoin = () => {\n if (strategy !== \"concat\") {\n return;\n }\n\n if (text !== \"\") {\n chunks.push(text);\n text = \"\";\n }\n strategy = \"array-join\";\n };\n\n const sink: StringHtmlSink = {\n append(chunk) {\n writeCount += 1;\n\n if (requestedStrategy === \"auto\" && strategy === \"concat\" && writeCount > arrayJoinThreshold) {\n switchConcatToArrayJoin();\n }\n\n if (strategy === \"concat\") {\n text += chunk;\n return;\n }\n\n chunks.push(chunk);\n },\n bufferStrategy() {\n return strategy;\n },\n defer(task) {\n deferredTasks.push(task);\n },\n async drain() {\n await Promise.all(deferredTasks);\n },\n toString() {\n if (strategy === \"concat\") {\n return text;\n }\n\n return chunks.join(\"\");\n },\n };\n\n stringSinkDeferredTasks.set(sink, deferredTasks);\n return sink;\n}\n\nexport function hasDeferredTasks(sink: HtmlSink): boolean {\n return (stringSinkDeferredTasks.get(sink)?.length ?? 0) > 0;\n}\n"]}
1
+ {"version":3,"file":"sink.js","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAqBA,MAAM,uBAAuB,GAAG,IAAI,OAAO,EAAiC,CAAC;AAE7E,8EAA8E;AAC9E,MAAM,UAAU,gBAAgB,CAAC,UAA6B,EAAE;IAC9D,uEAAuE;IACvE,0DAA0D;IAC1D,0EAA0E;IAC1E,iEAAiE;IACjE,MAAM,iBAAiB,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC;IACvD,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,IAAI,GAAG,CAAC;IAC7D,MAAM,aAAa,GAAwB,EAAE,CAAC;IAC9C,IAAI,QAAQ,GAA6B,iBAAiB,KAAK,MAAM;QACnE,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,iBAAiB,CAAC;IACtB,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,uBAAuB,GAAG,GAAG,EAAE;QACnC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YAChB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,IAAI,GAAG,EAAE,CAAC;QACZ,CAAC;QACD,QAAQ,GAAG,YAAY,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,IAAI,GAAmB;QAC3B,MAAM,CAAC,KAAK;YACV,UAAU,IAAI,CAAC,CAAC;YAEhB,IAAI,iBAAiB,KAAK,MAAM,IAAI,QAAQ,KAAK,QAAQ,IAAI,UAAU,GAAG,kBAAkB,EAAE,CAAC;gBAC7F,uBAAuB,EAAE,CAAC;YAC5B,CAAC;YAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,IAAI,IAAI,KAAK,CAAC;gBACd,OAAO;YACT,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,cAAc;YACZ,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,IAAI;YACR,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,KAAK;YACT,MAAM,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC;QACD,QAAQ;YACN,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC1B,OAAO,IAAI,CAAC;YACd,CAAC;YAED,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,CAAC;KACF,CAAC;IAEF,uBAAuB,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,gBAAgB,CAAC,IAAc;IAC7C,OAAO,CAAC,uBAAuB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AAC9D,CAAC","sourcesContent":["import type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\n\n/** HTML sink that buffers output as a string and can await deferred tasks. */\nexport interface StringHtmlSink extends HtmlSink {\n bufferStrategy(): StringSinkBufferStrategy;\n drain(): Promise<void>;\n toString(): string;\n}\n\n/** String buffering strategy used by createStringSink. */\nexport type StringSinkBufferStrategy = \"concat\" | \"array-join\";\n\n/** Options controlling how a string sink buffers appended chunks. */\nexport interface StringSinkOptions {\n strategy?: StringSinkBufferStrategy | \"auto\";\n arrayJoinThreshold?: number;\n}\n\n/** Callback that writes server-rendered HTML into a sink. */\nexport type StreamRender = (sink: HtmlSink) => void | PromiseLike<void>;\n\nconst stringSinkDeferredTasks = new WeakMap<HtmlSink, PromiseLike<void>[]>();\n\n/** Creates an HTML sink that stores appended chunks in memory as a string. */\nexport function createStringSink(options: StringSinkOptions = {}): StringHtmlSink {\n // Default to \"concat\" - V8 rope flattening yields 2-6x throughput over\n // `Array#join(\"\")` across all measured fixture sizes (see\n // docs/benchmarks/2026-05-12-server-sink-strategy.md). \"array-join\" stays\n // available as opt-in for scenarios that need lower peak memory.\n const requestedStrategy = options.strategy ?? \"concat\";\n const arrayJoinThreshold = options.arrayJoinThreshold ?? 256;\n const deferredTasks: PromiseLike<void>[] = [];\n let strategy: StringSinkBufferStrategy = requestedStrategy === \"auto\"\n ? \"concat\"\n : requestedStrategy;\n let writeCount = 0;\n let text = \"\";\n const chunks: string[] = [];\n\n const switchConcatToArrayJoin = () => {\n if (strategy !== \"concat\") {\n return;\n }\n\n if (text !== \"\") {\n chunks.push(text);\n text = \"\";\n }\n strategy = \"array-join\";\n };\n\n const sink: StringHtmlSink = {\n append(chunk) {\n writeCount += 1;\n\n if (requestedStrategy === \"auto\" && strategy === \"concat\" && writeCount > arrayJoinThreshold) {\n switchConcatToArrayJoin();\n }\n\n if (strategy === \"concat\") {\n text += chunk;\n return;\n }\n\n chunks.push(chunk);\n },\n bufferStrategy() {\n return strategy;\n },\n defer(task) {\n deferredTasks.push(task);\n },\n async drain() {\n await Promise.all(deferredTasks);\n },\n toString() {\n if (strategy === \"concat\") {\n return text;\n }\n\n return chunks.join(\"\");\n },\n };\n\n stringSinkDeferredTasks.set(sink, deferredTasks);\n return sink;\n}\n\n/** Returns true when a sink created by createStringSink has deferred tasks. */\nexport function hasDeferredTasks(sink: HtmlSink): boolean {\n return (stringSinkDeferredTasks.get(sink)?.length ?? 0) > 0;\n}\n"]}
package/dist/stream.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { StreamRender } from "./sink.js";
2
+ /** Options controlling server render stream error logging behavior. */
2
3
  export interface RenderToReadableStreamOptions {
3
4
  logAbortedDeferredErrors?: boolean;
4
5
  }
6
+ /** Renders HTML sink output to a WHATWG readable byte stream. */
5
7
  export declare function renderToReadableStream(render: StreamRender, options?: RenderToReadableStreamOptions): ReadableStream<Uint8Array>;
6
8
  //# sourceMappingURL=stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,6BAA6B;IAC5C,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAID,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,6BAAkC,GAC1C,cAAc,CAAC,UAAU,CAAC,CA+N5B"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,uEAAuE;AACvE,MAAM,WAAW,6BAA6B;IAC5C,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAID,iEAAiE;AACjE,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,YAAY,EACpB,OAAO,GAAE,6BAAkC,GAC1C,cAAc,CAAC,UAAU,CAAC,CA+N5B"}
package/dist/stream.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createStreamingBufferSink } from "./buffer-sink.js";
2
2
  const streamQueuedChunkSoftLimitBytes = 1024 * 1024;
3
+ /** Renders HTML sink output to a WHATWG readable byte stream. */
3
4
  export function renderToReadableStream(render, options = {}) {
4
5
  // Issue 084: append calls go into a coalescing Node Buffer sink. The
5
6
  // previous implementation called `controller.enqueue(encoder.encode(chunk))`
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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","sourcesContent":["import { createStreamingBufferSink } from \"./buffer-sink.js\";\nimport type { StreamRender } from \"./sink.js\";\n\nexport interface RenderToReadableStreamOptions {\n logAbortedDeferredErrors?: boolean;\n}\n\nconst streamQueuedChunkSoftLimitBytes = 1024 * 1024;\n\nexport function renderToReadableStream(\n render: StreamRender,\n options: RenderToReadableStreamOptions = {},\n): ReadableStream<Uint8Array> {\n // Issue 084: append calls go into a coalescing Node Buffer sink. The\n // previous implementation called `controller.enqueue(encoder.encode(chunk))`\n // per `sink.append` - one TextEncoder allocation + one WHATWG queue trip\n // per call. Now we emit one chunk per flush boundary:\n // 1. After the sync portion of `render` returns - the \"shell\"\n // pre-flush. Done synchronously so it lands before any deferred\n // task body fires in a microtask.\n // 2. Whenever the accumulated buffer crosses the flushThreshold\n // mid-render (e.g. a single very large list rendering).\n // 3. Each `sink.append` made during the deferred phase flushes\n // immediately - gives each OOB fragment its own HTTP chunk so\n // the browser can swap it in as soon as it arrives.\n // 4. End of stream - any tail bytes.\n const abortController = new AbortController();\n const queuedChunks: Uint8Array[] = [];\n let controllerRef: ReadableStreamDefaultController<Uint8Array> | undefined;\n let cancelled = false;\n let complete = false;\n let queuedBytes = 0;\n let warnedQueuedBytes = false;\n let backpressurePromise: Promise<void> | undefined;\n let resolveBackpressure: (() => void) | undefined;\n\n const enqueueOrQueue = (buffer: Uint8Array) => {\n if (cancelled || abortController.signal.aborted) {\n return;\n }\n\n const controller = controllerRef;\n if (controller === undefined) {\n queueChunk(buffer);\n return;\n }\n\n if (queuedChunks.length === 0 && (controller.desiredSize ?? 0) > 0) {\n controller.enqueue(buffer);\n resolveBackpressureIfReady();\n return;\n }\n\n queueChunk(buffer);\n };\n const drainQueuedChunks = (controller: ReadableStreamDefaultController<Uint8Array>) => {\n while (!cancelled && queuedChunks.length > 0 && (controller.desiredSize ?? 0) > 0) {\n const chunk = queuedChunks.shift();\n if (chunk !== undefined) {\n queuedBytes -= chunk.byteLength;\n controller.enqueue(chunk);\n }\n }\n\n if (!cancelled && complete && queuedChunks.length === 0) {\n controller.close();\n }\n\n resolveBackpressureIfReady();\n };\n\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controllerRef = controller;\n const sink = createStreamingBufferSink({\n onFlush(buffer) {\n enqueueOrQueue(buffer);\n },\n });\n const deferredTasks: PromiseLike<void>[] = [];\n let inDeferredPhase = false;\n let renderResult: void | PromiseLike<void>;\n\n try {\n renderResult = render({\n append(chunk) {\n if (abortController.signal.aborted) {\n return;\n }\n sink.append(chunk);\n if (inDeferredPhase) {\n // OOB pattern: each deferred task ends with exactly one\n // `sink.append(\"<template ...>...\")`. Flushing here\n // promotes that single append to its own chunk so the\n // browser's MutationObserver can apply it without\n // waiting for other deferred fragments.\n sink.flush();\n }\n },\n backpressure() {\n return waitForBackpressure();\n },\n defer(task) {\n deferredTasks.push(ignoreAfterAbort(task, abortController.signal, options));\n },\n signal: abortController.signal,\n });\n } catch (error) {\n if (abortController.signal.aborted) {\n return;\n }\n controller.error(error);\n return;\n }\n\n // Shell pre-flush - synchronous, BEFORE we yield to microtasks.\n // If we awaited render first the deferred tasks' bodies would\n // already have appended their bytes to the same buffer and we\n // would emit one merged chunk.\n sink.flush();\n\n void continueAfterShell();\n\n async function continueAfterShell(): Promise<void> {\n try {\n if (renderResult !== undefined && renderResult !== null) {\n await raceAbort(renderResult, abortController.signal);\n // Async render may have written more before its tail returned.\n // That tail is also \"shell\" - flush it before entering the\n // deferred phase.\n sink.flush();\n }\n\n inDeferredPhase = true;\n await raceAbort(Promise.all(deferredTasks), abortController.signal);\n // Tail flush in case the render closure (or a deferred task)\n // somehow left bytes in the buffer past the per-append flushes.\n sink.flush();\n complete = true;\n drainQueuedChunks(controller);\n } catch (error) {\n if (abortController.signal.aborted) {\n return;\n }\n controller.error(error);\n }\n }\n },\n pull(controller) {\n drainQueuedChunks(controller);\n resolveBackpressureAfterPull();\n },\n cancel(reason) {\n cancelled = true;\n queuedChunks.length = 0;\n queuedBytes = 0;\n abortController.abort(reason);\n resolveBackpressureIfReady();\n },\n });\n\n function hasBackpressure(): boolean {\n if (cancelled || abortController.signal.aborted) {\n return false;\n }\n\n if (queuedChunks.length > 0) {\n return true;\n }\n\n const controller = controllerRef;\n return controller !== undefined && (controller.desiredSize ?? 0) <= 0;\n }\n\n function waitForBackpressure(): Promise<void> {\n if (!hasBackpressure()) {\n return Promise.resolve();\n }\n\n if (backpressurePromise === undefined) {\n backpressurePromise = new Promise<void>((resolve) => {\n resolveBackpressure = resolve;\n });\n }\n\n return backpressurePromise;\n }\n\n function resolveBackpressureIfReady(): void {\n if (resolveBackpressure === undefined || hasBackpressure()) {\n return;\n }\n\n resolveBackpressureWaiter();\n }\n\n function resolveBackpressureAfterPull(): void {\n if (\n resolveBackpressure === undefined ||\n queuedChunks.length > 0 ||\n cancelled ||\n abortController.signal.aborted\n ) {\n return;\n }\n\n resolveBackpressureWaiter();\n }\n\n function resolveBackpressureWaiter(): void {\n const resolve = resolveBackpressure;\n if (resolve === undefined) {\n return;\n }\n\n backpressurePromise = undefined;\n resolveBackpressure = undefined;\n resolve();\n }\n\n function queueChunk(buffer: Uint8Array): void {\n queuedChunks.push(buffer);\n queuedBytes += buffer.byteLength;\n\n if (\n !warnedQueuedBytes &&\n queuedBytes > streamQueuedChunkSoftLimitBytes &&\n shouldWarnAboutQueuedStreamBytes()\n ) {\n warnedQueuedBytes = true;\n console.warn(\n `[mreact] renderToReadableStream queued ${queuedBytes} bytes because the downstream reader is slower than the renderer.`,\n );\n }\n }\n}\n\nfunction shouldWarnAboutQueuedStreamBytes(): boolean {\n return (\n typeof process !== \"undefined\" &&\n process.env !== undefined &&\n process.env.NODE_ENV !== \"production\"\n );\n}\n\nasync function raceAbort<T>(task: PromiseLike<T>, signal: AbortSignal): Promise<T | undefined> {\n if (signal.aborted) {\n return undefined;\n }\n\n return Promise.race([\n task,\n new Promise<undefined>((resolve) => {\n signal.addEventListener(\"abort\", () => resolve(undefined), { once: true });\n }),\n ]);\n}\n\nfunction ignoreAfterAbort(\n task: PromiseLike<void>,\n signal: AbortSignal,\n options: RenderToReadableStreamOptions,\n): Promise<void> {\n return Promise.resolve(task).catch((error) => {\n if (!signal.aborted) {\n throw error;\n }\n\n if (options.logAbortedDeferredErrors === true && process.env.NODE_ENV !== \"production\") {\n console.warn(\"[mreact] ignored deferred task error after abort:\", error);\n }\n });\n}\n"]}
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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","sourcesContent":["import { createStreamingBufferSink } from \"./buffer-sink.js\";\nimport type { StreamRender } from \"./sink.js\";\n\n/** Options controlling server render stream error logging behavior. */\nexport interface RenderToReadableStreamOptions {\n logAbortedDeferredErrors?: boolean;\n}\n\nconst streamQueuedChunkSoftLimitBytes = 1024 * 1024;\n\n/** Renders HTML sink output to a WHATWG readable byte stream. */\nexport function renderToReadableStream(\n render: StreamRender,\n options: RenderToReadableStreamOptions = {},\n): ReadableStream<Uint8Array> {\n // Issue 084: append calls go into a coalescing Node Buffer sink. The\n // previous implementation called `controller.enqueue(encoder.encode(chunk))`\n // per `sink.append` - one TextEncoder allocation + one WHATWG queue trip\n // per call. Now we emit one chunk per flush boundary:\n // 1. After the sync portion of `render` returns - the \"shell\"\n // pre-flush. Done synchronously so it lands before any deferred\n // task body fires in a microtask.\n // 2. Whenever the accumulated buffer crosses the flushThreshold\n // mid-render (e.g. a single very large list rendering).\n // 3. Each `sink.append` made during the deferred phase flushes\n // immediately - gives each OOB fragment its own HTTP chunk so\n // the browser can swap it in as soon as it arrives.\n // 4. End of stream - any tail bytes.\n const abortController = new AbortController();\n const queuedChunks: Uint8Array[] = [];\n let controllerRef: ReadableStreamDefaultController<Uint8Array> | undefined;\n let cancelled = false;\n let complete = false;\n let queuedBytes = 0;\n let warnedQueuedBytes = false;\n let backpressurePromise: Promise<void> | undefined;\n let resolveBackpressure: (() => void) | undefined;\n\n const enqueueOrQueue = (buffer: Uint8Array) => {\n if (cancelled || abortController.signal.aborted) {\n return;\n }\n\n const controller = controllerRef;\n if (controller === undefined) {\n queueChunk(buffer);\n return;\n }\n\n if (queuedChunks.length === 0 && (controller.desiredSize ?? 0) > 0) {\n controller.enqueue(buffer);\n resolveBackpressureIfReady();\n return;\n }\n\n queueChunk(buffer);\n };\n const drainQueuedChunks = (controller: ReadableStreamDefaultController<Uint8Array>) => {\n while (!cancelled && queuedChunks.length > 0 && (controller.desiredSize ?? 0) > 0) {\n const chunk = queuedChunks.shift();\n if (chunk !== undefined) {\n queuedBytes -= chunk.byteLength;\n controller.enqueue(chunk);\n }\n }\n\n if (!cancelled && complete && queuedChunks.length === 0) {\n controller.close();\n }\n\n resolveBackpressureIfReady();\n };\n\n return new ReadableStream<Uint8Array>({\n start(controller) {\n controllerRef = controller;\n const sink = createStreamingBufferSink({\n onFlush(buffer) {\n enqueueOrQueue(buffer);\n },\n });\n const deferredTasks: PromiseLike<void>[] = [];\n let inDeferredPhase = false;\n let renderResult: void | PromiseLike<void>;\n\n try {\n renderResult = render({\n append(chunk) {\n if (abortController.signal.aborted) {\n return;\n }\n sink.append(chunk);\n if (inDeferredPhase) {\n // OOB pattern: each deferred task ends with exactly one\n // `sink.append(\"<template ...>...\")`. Flushing here\n // promotes that single append to its own chunk so the\n // browser's MutationObserver can apply it without\n // waiting for other deferred fragments.\n sink.flush();\n }\n },\n backpressure() {\n return waitForBackpressure();\n },\n defer(task) {\n deferredTasks.push(ignoreAfterAbort(task, abortController.signal, options));\n },\n signal: abortController.signal,\n });\n } catch (error) {\n if (abortController.signal.aborted) {\n return;\n }\n controller.error(error);\n return;\n }\n\n // Shell pre-flush - synchronous, BEFORE we yield to microtasks.\n // If we awaited render first the deferred tasks' bodies would\n // already have appended their bytes to the same buffer and we\n // would emit one merged chunk.\n sink.flush();\n\n void continueAfterShell();\n\n async function continueAfterShell(): Promise<void> {\n try {\n if (renderResult !== undefined && renderResult !== null) {\n await raceAbort(renderResult, abortController.signal);\n // Async render may have written more before its tail returned.\n // That tail is also \"shell\" - flush it before entering the\n // deferred phase.\n sink.flush();\n }\n\n inDeferredPhase = true;\n await raceAbort(Promise.all(deferredTasks), abortController.signal);\n // Tail flush in case the render closure (or a deferred task)\n // somehow left bytes in the buffer past the per-append flushes.\n sink.flush();\n complete = true;\n drainQueuedChunks(controller);\n } catch (error) {\n if (abortController.signal.aborted) {\n return;\n }\n controller.error(error);\n }\n }\n },\n pull(controller) {\n drainQueuedChunks(controller);\n resolveBackpressureAfterPull();\n },\n cancel(reason) {\n cancelled = true;\n queuedChunks.length = 0;\n queuedBytes = 0;\n abortController.abort(reason);\n resolveBackpressureIfReady();\n },\n });\n\n function hasBackpressure(): boolean {\n if (cancelled || abortController.signal.aborted) {\n return false;\n }\n\n if (queuedChunks.length > 0) {\n return true;\n }\n\n const controller = controllerRef;\n return controller !== undefined && (controller.desiredSize ?? 0) <= 0;\n }\n\n function waitForBackpressure(): Promise<void> {\n if (!hasBackpressure()) {\n return Promise.resolve();\n }\n\n if (backpressurePromise === undefined) {\n backpressurePromise = new Promise<void>((resolve) => {\n resolveBackpressure = resolve;\n });\n }\n\n return backpressurePromise;\n }\n\n function resolveBackpressureIfReady(): void {\n if (resolveBackpressure === undefined || hasBackpressure()) {\n return;\n }\n\n resolveBackpressureWaiter();\n }\n\n function resolveBackpressureAfterPull(): void {\n if (\n resolveBackpressure === undefined ||\n queuedChunks.length > 0 ||\n cancelled ||\n abortController.signal.aborted\n ) {\n return;\n }\n\n resolveBackpressureWaiter();\n }\n\n function resolveBackpressureWaiter(): void {\n const resolve = resolveBackpressure;\n if (resolve === undefined) {\n return;\n }\n\n backpressurePromise = undefined;\n resolveBackpressure = undefined;\n resolve();\n }\n\n function queueChunk(buffer: Uint8Array): void {\n queuedChunks.push(buffer);\n queuedBytes += buffer.byteLength;\n\n if (\n !warnedQueuedBytes &&\n queuedBytes > streamQueuedChunkSoftLimitBytes &&\n shouldWarnAboutQueuedStreamBytes()\n ) {\n warnedQueuedBytes = true;\n console.warn(\n `[mreact] renderToReadableStream queued ${queuedBytes} bytes because the downstream reader is slower than the renderer.`,\n );\n }\n }\n}\n\nfunction shouldWarnAboutQueuedStreamBytes(): boolean {\n return (\n typeof process !== \"undefined\" &&\n process.env !== undefined &&\n process.env.NODE_ENV !== \"production\"\n );\n}\n\nasync function raceAbort<T>(task: PromiseLike<T>, signal: AbortSignal): Promise<T | undefined> {\n if (signal.aborted) {\n return undefined;\n }\n\n return Promise.race([\n task,\n new Promise<undefined>((resolve) => {\n signal.addEventListener(\"abort\", () => resolve(undefined), { once: true });\n }),\n ]);\n}\n\nfunction ignoreAfterAbort(\n task: PromiseLike<void>,\n signal: AbortSignal,\n options: RenderToReadableStreamOptions,\n): Promise<void> {\n return Promise.resolve(task).catch((error) => {\n if (!signal.aborted) {\n throw error;\n }\n\n if (options.logAbortedDeferredErrors === true && process.env.NODE_ENV !== \"production\") {\n console.warn(\"[mreact] ignored deferred task error after abort:\", error);\n }\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reckona/mreact-server",
3
- "version": "0.0.160",
3
+ "version": "0.0.161",
4
4
  "description": "Server rendering, streaming, hydration, and Flight primitives for mreact.",
5
5
  "keywords": [
6
6
  "flight",
@@ -61,7 +61,7 @@
61
61
  "access": "public"
62
62
  },
63
63
  "dependencies": {
64
- "@reckona/mreact-compat": "0.0.160",
65
- "@reckona/mreact-shared": "0.0.160"
64
+ "@reckona/mreact-compat": "0.0.161",
65
+ "@reckona/mreact-shared": "0.0.161"
66
66
  }
67
67
  }
package/src/boundary.ts CHANGED
@@ -7,41 +7,49 @@ import {
7
7
  } from "./html-internals.js";
8
8
  import { createStringSink, type StringHtmlSink } from "./sink.js";
9
9
 
10
+ /** Options shared by async boundaries that render resolved values or caught errors. */
10
11
  export interface AsyncBoundaryOptions {
11
12
  catch?: (sink: HtmlSink, error: unknown) => void | PromiseLike<void>;
12
13
  hydrationAwaitId?: string;
13
14
  }
14
15
 
16
+ /** Options for rendering a boundary whose resolved content can arrive out of order. */
15
17
  export interface OutOfOrderBoundaryOptions extends AsyncBoundaryOptions {
16
18
  hydration?: boolean;
17
19
  placeholder?: (sink: HtmlSink) => void;
18
20
  placeholderTag?: string;
19
21
  }
20
22
 
23
+ /** Options for emitting the out-of-order fragment reorder script. */
21
24
  export interface OutOfOrderReorderScriptOptions {
22
25
  nonce?: string;
23
26
  src?: string;
24
27
  }
25
28
 
29
+ /** Options for script tags that hydrate server-rendered data. */
26
30
  export interface HydrationScriptOptions {
27
31
  nonce?: string;
28
32
  }
29
33
 
34
+ /** Options for scripts that reveal React Suspense segments. */
30
35
  export interface ReactSuspenseScriptOptions {
31
36
  nonce?: string;
32
37
  src?: string;
33
38
  }
34
39
 
40
+ /** Options for React Suspense boundaries rendered with streamed segments. */
35
41
  export interface ReactSuspenseBoundaryOptions extends AsyncBoundaryOptions {
36
42
  fallback?: (sink: HtmlSink) => void | PromiseLike<void>;
37
43
  nonce?: string;
38
44
  }
39
45
 
46
+ /** Error metadata used when forcing a React Suspense boundary to client render. */
40
47
  export interface ReactSuspenseClientRenderOptions {
41
48
  message?: string;
42
49
  stack?: string;
43
50
  }
44
51
 
52
+ /** Renderer invoked with an async boundary's resolved value. */
45
53
  export type AsyncBoundaryRender<T> = (
46
54
  sink: HtmlSink,
47
55
  value: Awaited<T>,
@@ -49,6 +57,7 @@ export type AsyncBoundaryRender<T> = (
49
57
 
50
58
  const outOfOrderBoundaryInstances = new WeakMap<HtmlSink, Map<string, number>>();
51
59
 
60
+ /** Renders a value once it resolves, or renders a configured catch branch on error. */
52
61
  export async function renderAsyncBoundary<T>(
53
62
  sink: HtmlSink,
54
63
  value: T,
@@ -217,6 +226,7 @@ function inheritBackpressure(childSink: StringHtmlSink, parentSink: HtmlSink): S
217
226
  };
218
227
  }
219
228
 
229
+ /** Emits a placeholder immediately and defers resolved HTML as an out-of-order fragment. */
220
230
  export function renderOutOfOrderBoundary<T>(
221
231
  sink: HtmlSink,
222
232
  id: string,
@@ -288,6 +298,7 @@ async function renderOutOfOrderFragment<T>(
288
298
  }
289
299
  }
290
300
 
301
+ /** Emits the client script that swaps out-of-order fragments into their placeholders. */
291
302
  export function renderOutOfOrderReorderScript(
292
303
  sink: HtmlSink,
293
304
  options: OutOfOrderReorderScriptOptions = {},
@@ -312,6 +323,7 @@ function renderOutOfOrderFragmentHtml(id: string, html: string): string {
312
323
  return `<template data-mreact-oob-fragment="${escapedId}">${html}</template><mreact-oob-complete hidden data-mreact-oob-complete="${escapedId}"></mreact-oob-complete>`;
313
324
  }
314
325
 
326
+ /** Wraps streamed content in React Suspense completion markers. */
315
327
  export function renderReactSuspenseBoundary(
316
328
  sink: HtmlSink,
317
329
  render: (sink: HtmlSink) => void | PromiseLike<void>,
@@ -328,6 +340,7 @@ export function renderReactSuspenseBoundary(
328
340
  sink.append("<!--/$-->");
329
341
  }
330
342
 
343
+ /** Emits a React Suspense fallback and streams the resolved segment out of order. */
331
344
  export function renderReactSuspenseOutOfOrderBoundary<T>(
332
345
  sink: HtmlSink,
333
346
  boundaryId: string,
@@ -376,6 +389,7 @@ function nextOutOfOrderBoundaryInstanceId(sink: HtmlSink, id: string): string {
376
389
  return count === 0 ? id : `${id}-${count.toString(36)}`;
377
390
  }
378
391
 
392
+ /** Emits a React Suspense boundary that instructs the client to render the fallback. */
379
393
  export function renderReactSuspenseClientRenderBoundary(
380
394
  sink: HtmlSink,
381
395
  fallback: (sink: HtmlSink) => void | PromiseLike<void>,
@@ -435,6 +449,7 @@ function renderReactSuspenseRevealScript(
435
449
  return `<script${renderNonceAttribute(options.nonce)}>${reactSuspenseRevealScriptBody};$RC(${serializeScriptJson(boundaryId)},${serializeScriptJson(segmentId)})</script>`;
436
450
  }
437
451
 
452
+ /** Wraps server-rendered HTML in hydration start and end markers. */
438
453
  export function renderHydrationBoundary(
439
454
  sink: HtmlSink,
440
455
  id: string,
@@ -461,4 +476,5 @@ const outOfOrderReorderScript = `(()=>{function apply(root){const fragments=Arra
461
476
 
462
477
  const reactSuspenseRevealScriptBody = `(self.$RC=self.$RC||function(bid,sid){var b=document.getElementById(bid);var s=document.getElementById(sid);if(!b||!s)return;var p=b.parentNode;var e=b.nextSibling;var d=0;var r=[];for(var n=e;n;n=n.nextSibling){if(n.nodeType===8){if(n.data==="$"||n.data==="$?"||n.data==="$!")d++;else if(n.data==="/$"){if(d===0){e=n;break;}d--;}}r.push(n);}for(var i=0;r[i];i++)p.removeChild(r[i]);while(s.firstChild)p.insertBefore(s.firstChild,e);s.remove();b.data="$";})`;
463
478
 
479
+ /** External script body that reveals a React Suspense segment when loaded. */
464
480
  export const reactSuspenseRevealExternalScript = `(()=>{${reactSuspenseRevealScriptBody};var s=document.currentScript;if(!s)return;var b=s.getAttribute("data-boundary-id");var seg=s.getAttribute("data-segment-id");if(b!==null&&seg!==null)self.$RC(b,seg);})();`;