@reckona/mreact-server 0.0.138 → 0.0.139

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../src/boundary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"boundary.d.ts","sourceRoot":"","sources":["../src/boundary.ts"],"names":[],"mappings":"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"}
package/dist/boundary.js CHANGED
@@ -23,6 +23,7 @@ export async function renderAsyncBoundary(sink, value, render, options = {}) {
23
23
  // "you're sending a lot of data" hint pattern used by other frameworks.
24
24
  const AWAIT_PAYLOAD_WARN_BYTES = 100 * 1024;
25
25
  const AWAIT_PAYLOAD_ERROR_BYTES = 1024 * 1024;
26
+ const textEncoder = typeof TextEncoder !== "undefined" ? new TextEncoder() : undefined;
26
27
  function isProductionMode() {
27
28
  // `process` may not exist in cross-runtime environments (Cloudflare/Deno).
28
29
  // The server tsconfig does not include `@types/node`, so we look it up
@@ -83,7 +84,10 @@ function containsNonSerializableSurface(value) {
83
84
  return false;
84
85
  }
85
86
  function reportAwaitPayloadSize(json, awaitId) {
86
- const byteLength = typeof TextEncoder !== "undefined" ? new TextEncoder().encode(json).length : json.length;
87
+ if (json.length * 3 < AWAIT_PAYLOAD_WARN_BYTES) {
88
+ return;
89
+ }
90
+ const byteLength = textEncoder?.encode(json).length ?? json.length;
87
91
  if (byteLength > AWAIT_PAYLOAD_ERROR_BYTES) {
88
92
  console.error(`[mreact] <Await> payload for "${awaitId}" is ${(byteLength / 1024 / 1024).toFixed(2)}MB, ` +
89
93
  `exceeding the 1MB error threshold. Large payloads inflate HTML response size and ` +
@@ -1 +1 @@
1
- {"version":3,"file":"boundary.js","sourceRoot":"","sources":["../src/boundary.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\nimport {\n escapeAttribute,\n isPromiseLikeUnknown,\n renderNonceAttribute,\n serializeScriptJson,\n} from \"./html-internals.js\";\nimport { createStringSink, type StringHtmlSink } from \"./sink.js\";\n\nexport interface AsyncBoundaryOptions {\n catch?: (sink: HtmlSink, error: unknown) => void | PromiseLike<void>;\n hydrationAwaitId?: string;\n}\n\nexport interface OutOfOrderBoundaryOptions extends AsyncBoundaryOptions {\n hydration?: boolean;\n placeholder?: (sink: HtmlSink) => void | PromiseLike<void>;\n placeholderTag?: string;\n}\n\nexport interface OutOfOrderReorderScriptOptions {\n nonce?: string;\n src?: string;\n}\n\nexport interface HydrationScriptOptions {\n nonce?: string;\n}\n\nexport interface ReactSuspenseScriptOptions {\n nonce?: string;\n src?: string;\n}\n\nexport interface ReactSuspenseBoundaryOptions extends AsyncBoundaryOptions {\n fallback?: (sink: HtmlSink) => void | PromiseLike<void>;\n nonce?: string;\n}\n\nexport interface ReactSuspenseClientRenderOptions {\n message?: string;\n stack?: string;\n}\n\nexport type AsyncBoundaryRender<T> = (\n sink: HtmlSink,\n value: Awaited<T>,\n) => void | PromiseLike<void>;\n\nconst outOfOrderBoundaryInstances = new WeakMap<HtmlSink, Map<string, number>>();\n\nexport async function renderAsyncBoundary<T>(\n sink: HtmlSink,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: AsyncBoundaryOptions = {},\n): Promise<void> {\n try {\n const resolved = await value;\n await sink.backpressure?.();\n await render(sink, resolved);\n if (options.hydrationAwaitId !== undefined) {\n appendAwaitHydrationData(sink, options.hydrationAwaitId, resolved);\n }\n } catch (error) {\n if (options.catch === undefined) {\n throw error;\n }\n\n await sink.backpressure?.();\n await options.catch(sink, error);\n }\n}\n\n// Threshold for `<Await>` payload size warnings (UTF-8 byte length of\n// JSON-serialized representation). 100KB warn / 1MB error follow the\n// \"you're sending a lot of data\" hint pattern used by other frameworks.\nconst AWAIT_PAYLOAD_WARN_BYTES = 100 * 1024;\nconst AWAIT_PAYLOAD_ERROR_BYTES = 1024 * 1024;\n\nfunction isProductionMode(): boolean {\n // `process` may not exist in cross-runtime environments (Cloudflare/Deno).\n // The server tsconfig does not include `@types/node`, so we look it up\n // through `globalThis` with a minimal local typing.\n const globalProcess = (globalThis as { process?: { env?: Record<string, string | undefined> } })\n .process;\n\n try {\n return globalProcess?.env?.[\"NODE_ENV\"] === \"production\";\n } catch {\n return false;\n }\n}\n\nfunction appendAwaitHydrationData(\n sink: HtmlSink,\n awaitId: string,\n resolved: unknown,\n): void {\n const serialized = serializeAwaitHydrationValue(resolved, awaitId);\n\n if (serialized === undefined) {\n return;\n }\n\n const idLiteral = JSON.stringify(awaitId).replaceAll(\"<\", \"\\\\u003c\");\n sink.append(\n `<script data-mreact-await=\"${escapeAttribute(awaitId)}\">(self.__mreactAwaitData||(self.__mreactAwaitData={}))[${idLiteral}]={value:${serialized}}</script>`,\n );\n}\n\n// Emits a single console.warn in dev when `resolved` contains shapes the\n// wire format will silently drop or coerce (Date / Map / Set / RegExp /\n// class instance / function / Symbol / nested non-POJO).\nfunction warnIfNonSerializableAwaitValue(value: unknown, awaitId: string): void {\n if (isProductionMode()) {\n return;\n }\n\n if (!containsNonSerializableSurface(value)) {\n return;\n }\n\n console.warn(\n `[mreact] <Await value={...}> for \"${awaitId}\" includes non-serializable ` +\n `data (Date / Map / Set / RegExp / class instance / function / Symbol). ` +\n `The wire format uses JSON.stringify, so the client-side renderer may ` +\n `receive a different shape after the JSON round-trip. Convert to plain ` +\n `JSON-serializable data before it reaches <Await>. See ` +\n `https://github.com/t-k/mreact#streaming-loading-and-await.`,\n );\n}\n\nfunction containsNonSerializableSurface(value: unknown): boolean {\n if (value === null || value === undefined || typeof value !== \"object\") {\n return false;\n }\n\n if (value instanceof Date || value instanceof Map || value instanceof Set || value instanceof RegExp) {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.some((entry) => containsNonSerializableSurface(entry));\n }\n\n const proto = Object.getPrototypeOf(value);\n\n if (proto !== Object.prototype && proto !== null) {\n return true;\n }\n\n for (const entry of Object.values(value as Record<string, unknown>)) {\n if (containsNonSerializableSurface(entry)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction reportAwaitPayloadSize(json: string, awaitId: string): void {\n const byteLength =\n typeof TextEncoder !== \"undefined\" ? new TextEncoder().encode(json).length : json.length;\n\n if (byteLength > AWAIT_PAYLOAD_ERROR_BYTES) {\n console.error(\n `[mreact] <Await> payload for \"${awaitId}\" is ${(byteLength / 1024 / 1024).toFixed(2)}MB, ` +\n `exceeding the 1MB error threshold. Large payloads inflate HTML response size and ` +\n `client memory pressure. Stream the data via loader or split into smaller boundaries.`,\n );\n return;\n }\n\n if (byteLength > AWAIT_PAYLOAD_WARN_BYTES) {\n console.warn(\n `[mreact] large await payload for \"${awaitId}\": ${(byteLength / 1024).toFixed(1)}KB ` +\n `(over the 100KB warning threshold). Consider streaming the data via loader or ` +\n `splitting into smaller boundaries.`,\n );\n }\n}\n\nfunction serializeAwaitHydrationValue(value: unknown, awaitId: string): string | undefined {\n try {\n const json = JSON.stringify(value);\n if (json === undefined) {\n return undefined;\n }\n\n warnIfNonSerializableAwaitValue(value, awaitId);\n reportAwaitPayloadSize(json, awaitId);\n\n // Defuse `</script>` and runaway control characters so the data can be\n // safely embedded inside a `<script>` element.\n return json\n .replaceAll(\"<\", \"\\\\u003c\")\n .replaceAll(\"\\u2028\", \"\\\\u2028\")\n .replaceAll(\"\\u2029\", \"\\\\u2029\");\n } catch {\n return undefined;\n }\n}\n\nfunction inheritBackpressure(childSink: StringHtmlSink, parentSink: HtmlSink): StringHtmlSink {\n if (parentSink.backpressure === undefined) {\n return childSink;\n }\n\n return {\n ...childSink,\n backpressure: parentSink.backpressure,\n };\n}\n\nexport function renderOutOfOrderBoundary<T>(\n sink: HtmlSink,\n id: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: OutOfOrderBoundaryOptions = {},\n): void {\n const boundaryId = nextOutOfOrderBoundaryInstanceId(sink, id);\n const placeholderSink = createStringSink();\n void options.placeholder?.(placeholderSink);\n const placeholderTag = normalizeOutOfOrderPlaceholderTag(options.placeholderTag);\n const hydrationStart =\n options.hydration === true ? `<!--mreact-h:start:${encodeURIComponent(boundaryId)}-->` : \"\";\n const hydrationEnd =\n options.hydration === true ? `<!--mreact-h:end:${encodeURIComponent(boundaryId)}-->` : \"\";\n sink.append(\n `${hydrationStart}<${placeholderTag} data-mreact-oob-placeholder=\"${escapeAttribute(boundaryId)}\">${placeholderSink.toString()}</${placeholderTag}>${hydrationEnd}`,\n );\n\n const task = renderOutOfOrderFragment(sink, boundaryId, value, render, options);\n\n if (sink.defer === undefined) {\n void task;\n return;\n }\n\n sink.defer(task);\n}\n\nfunction normalizeOutOfOrderPlaceholderTag(tag: unknown): string {\n if (typeof tag !== \"string\") {\n return \"span\";\n }\n\n const normalized = tag.trim().toLowerCase();\n return /^[a-z][a-z0-9-]*$/.test(normalized) ? normalized : \"span\";\n}\n\nasync function renderOutOfOrderFragment<T>(\n sink: HtmlSink,\n id: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: OutOfOrderBoundaryOptions,\n): Promise<void> {\n const fragmentSink = inheritBackpressure(createStringSink(), sink);\n let resolvedValue: unknown;\n let hasResolvedValue = false;\n\n await renderAsyncBoundary(\n fragmentSink,\n value,\n async (childSink, resolved) => {\n resolvedValue = resolved;\n hasResolvedValue = true;\n await render(childSink, resolved);\n },\n options.catch === undefined ? {} : { catch: options.catch },\n );\n await fragmentSink.drain();\n\n sink.append(\n `<template data-mreact-oob-fragment=\"${escapeAttribute(id)}\">${fragmentSink.toString()}</template>`,\n );\n\n if (hasResolvedValue && options.hydrationAwaitId !== undefined) {\n appendAwaitHydrationData(sink, options.hydrationAwaitId, resolvedValue);\n }\n}\n\nexport function renderOutOfOrderReorderScript(\n sink: HtmlSink,\n options: OutOfOrderReorderScriptOptions = {},\n): void {\n const nonceAttribute =\n options.nonce === undefined ? \"\" : ` nonce=\"${escapeAttribute(options.nonce)}\"`;\n\n if (options.src !== undefined) {\n sink.append(\n `<script data-mreact-oob-reorder${nonceAttribute} src=\"${escapeAttribute(options.src)}\"></script>`,\n );\n return;\n }\n\n sink.append(\n `<script data-mreact-oob-reorder${nonceAttribute}>${outOfOrderReorderScript}</script>`,\n );\n}\n\nexport function renderReactSuspenseBoundary(\n sink: HtmlSink,\n render: (sink: HtmlSink) => void | PromiseLike<void>,\n): void | PromiseLike<void> {\n sink.append(\"<!--$-->\");\n const result = render(sink);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(\"<!--/$-->\");\n });\n }\n\n sink.append(\"<!--/$-->\");\n}\n\nexport function renderReactSuspenseOutOfOrderBoundary<T>(\n sink: HtmlSink,\n boundaryId: string,\n segmentId: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: ReactSuspenseBoundaryOptions = {},\n): void {\n const actualBoundaryId = nextOutOfOrderBoundaryInstanceId(sink, boundaryId);\n const suffix = actualBoundaryId.slice(boundaryId.length);\n const actualSegmentId = `${segmentId}${suffix}`;\n const fallbackSink = createStringSink();\n void options.fallback?.(fallbackSink);\n sink.append(\n `<!--$?--><template id=\"${escapeAttribute(actualBoundaryId)}\"></template>${fallbackSink.toString()}<!--/$-->`,\n );\n\n const task = renderReactSuspenseSegment(\n sink,\n actualBoundaryId,\n actualSegmentId,\n value,\n render,\n options,\n );\n\n if (sink.defer === undefined) {\n void task;\n return;\n }\n\n sink.defer(task);\n}\n\nfunction nextOutOfOrderBoundaryInstanceId(sink: HtmlSink, id: string): string {\n let instances = outOfOrderBoundaryInstances.get(sink);\n\n if (instances === undefined) {\n instances = new Map();\n outOfOrderBoundaryInstances.set(sink, instances);\n }\n\n const count = instances.get(id) ?? 0;\n instances.set(id, count + 1);\n\n return count === 0 ? id : `${id}-${count.toString(36)}`;\n}\n\nexport function renderReactSuspenseClientRenderBoundary(\n sink: HtmlSink,\n fallback: (sink: HtmlSink) => void | PromiseLike<void>,\n options: ReactSuspenseClientRenderOptions = {},\n): void | PromiseLike<void> {\n sink.append(`<!--$!--><template${renderReactSuspenseErrorAttributes(options)}></template>`);\n const result = fallback(sink);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(\"<!--/$-->\");\n });\n }\n\n sink.append(\"<!--/$-->\");\n}\n\nasync function renderReactSuspenseSegment<T>(\n sink: HtmlSink,\n boundaryId: string,\n segmentId: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: ReactSuspenseBoundaryOptions,\n): Promise<void> {\n const segmentSink = inheritBackpressure(createStringSink(), sink);\n\n await renderAsyncBoundary(\n segmentSink,\n value,\n render,\n options.catch === undefined ? {} : { catch: options.catch },\n );\n\n sink.append(\n `<div hidden id=\"${escapeAttribute(segmentId)}\">${segmentSink.toString()}</div>${renderReactSuspenseRevealScript(boundaryId, segmentId, options)}`,\n );\n}\n\nfunction renderReactSuspenseErrorAttributes(options: ReactSuspenseClientRenderOptions): string {\n const message =\n options.message === undefined ? \"\" : ` data-msg=\"${escapeAttribute(options.message)}\"`;\n const stack = options.stack === undefined ? \"\" : ` data-stck=\"${escapeAttribute(options.stack)}\"`;\n\n return `${message}${stack}`;\n}\n\nfunction renderReactSuspenseRevealScript(\n boundaryId: string,\n segmentId: string,\n options: ReactSuspenseScriptOptions = {},\n): string {\n if (options.src !== undefined) {\n return `<script data-mreact-react-suspense-reveal${renderNonceAttribute(options.nonce)} src=\"${escapeAttribute(options.src)}\" data-boundary-id=\"${escapeAttribute(boundaryId)}\" data-segment-id=\"${escapeAttribute(segmentId)}\"></script>`;\n }\n\n return `<script${renderNonceAttribute(options.nonce)}>${reactSuspenseRevealScriptBody};$RC(${serializeScriptJson(boundaryId)},${serializeScriptJson(segmentId)})</script>`;\n}\n\nexport function renderHydrationBoundary(\n sink: HtmlSink,\n id: string,\n render: (sink: HtmlSink) => void | PromiseLike<void>,\n): void | PromiseLike<void> {\n const markerId = encodeURIComponent(id);\n sink.append(`<!--mreact-h:start:${markerId}-->`);\n const result = render(sink);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(`<!--mreact-h:end:${markerId}-->`);\n });\n }\n\n sink.append(`<!--mreact-h:end:${markerId}-->`);\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<void> {\n return isPromiseLikeUnknown(value);\n}\n\nconst outOfOrderReorderScript = `(()=>{function apply(root){const fragments=Array.from(root.querySelectorAll(\"template[data-mreact-oob-fragment]\"));for(const fragment of fragments){const id=fragment.getAttribute(\"data-mreact-oob-fragment\");if(id===null)continue;const placeholders=Array.from(root.querySelectorAll(\"[data-mreact-oob-placeholder]\"));const placeholder=placeholders.find((candidate)=>candidate.getAttribute(\"data-mreact-oob-placeholder\")===id);if(placeholder===undefined)continue;placeholder.replaceWith(fragment.content.cloneNode(true));fragment.remove();}}apply(document);new MutationObserver(()=>apply(document)).observe(document.documentElement,{childList:true,subtree:true});})();`;\n\nconst 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=\"$\";})`;\n\nexport 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);})();`;\n"]}
1
+ {"version":3,"file":"boundary.js","sourceRoot":"","sources":["../src/boundary.ts"],"names":[],"mappings":"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","sourcesContent":["import type { HtmlSink } from \"@reckona/mreact-shared/compiler-contract\";\nimport {\n escapeAttribute,\n isPromiseLikeUnknown,\n renderNonceAttribute,\n serializeScriptJson,\n} from \"./html-internals.js\";\nimport { createStringSink, type StringHtmlSink } from \"./sink.js\";\n\nexport interface AsyncBoundaryOptions {\n catch?: (sink: HtmlSink, error: unknown) => void | PromiseLike<void>;\n hydrationAwaitId?: string;\n}\n\nexport interface OutOfOrderBoundaryOptions extends AsyncBoundaryOptions {\n hydration?: boolean;\n placeholder?: (sink: HtmlSink) => void | PromiseLike<void>;\n placeholderTag?: string;\n}\n\nexport interface OutOfOrderReorderScriptOptions {\n nonce?: string;\n src?: string;\n}\n\nexport interface HydrationScriptOptions {\n nonce?: string;\n}\n\nexport interface ReactSuspenseScriptOptions {\n nonce?: string;\n src?: string;\n}\n\nexport interface ReactSuspenseBoundaryOptions extends AsyncBoundaryOptions {\n fallback?: (sink: HtmlSink) => void | PromiseLike<void>;\n nonce?: string;\n}\n\nexport interface ReactSuspenseClientRenderOptions {\n message?: string;\n stack?: string;\n}\n\nexport type AsyncBoundaryRender<T> = (\n sink: HtmlSink,\n value: Awaited<T>,\n) => void | PromiseLike<void>;\n\nconst outOfOrderBoundaryInstances = new WeakMap<HtmlSink, Map<string, number>>();\n\nexport async function renderAsyncBoundary<T>(\n sink: HtmlSink,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: AsyncBoundaryOptions = {},\n): Promise<void> {\n try {\n const resolved = await value;\n await sink.backpressure?.();\n await render(sink, resolved);\n if (options.hydrationAwaitId !== undefined) {\n appendAwaitHydrationData(sink, options.hydrationAwaitId, resolved);\n }\n } catch (error) {\n if (options.catch === undefined) {\n throw error;\n }\n\n await sink.backpressure?.();\n await options.catch(sink, error);\n }\n}\n\n// Threshold for `<Await>` payload size warnings (UTF-8 byte length of\n// JSON-serialized representation). 100KB warn / 1MB error follow the\n// \"you're sending a lot of data\" hint pattern used by other frameworks.\nconst AWAIT_PAYLOAD_WARN_BYTES = 100 * 1024;\nconst AWAIT_PAYLOAD_ERROR_BYTES = 1024 * 1024;\nconst textEncoder = typeof TextEncoder !== \"undefined\" ? new TextEncoder() : undefined;\n\nfunction isProductionMode(): boolean {\n // `process` may not exist in cross-runtime environments (Cloudflare/Deno).\n // The server tsconfig does not include `@types/node`, so we look it up\n // through `globalThis` with a minimal local typing.\n const globalProcess = (globalThis as { process?: { env?: Record<string, string | undefined> } })\n .process;\n\n try {\n return globalProcess?.env?.[\"NODE_ENV\"] === \"production\";\n } catch {\n return false;\n }\n}\n\nfunction appendAwaitHydrationData(\n sink: HtmlSink,\n awaitId: string,\n resolved: unknown,\n): void {\n const serialized = serializeAwaitHydrationValue(resolved, awaitId);\n\n if (serialized === undefined) {\n return;\n }\n\n const idLiteral = JSON.stringify(awaitId).replaceAll(\"<\", \"\\\\u003c\");\n sink.append(\n `<script data-mreact-await=\"${escapeAttribute(awaitId)}\">(self.__mreactAwaitData||(self.__mreactAwaitData={}))[${idLiteral}]={value:${serialized}}</script>`,\n );\n}\n\n// Emits a single console.warn in dev when `resolved` contains shapes the\n// wire format will silently drop or coerce (Date / Map / Set / RegExp /\n// class instance / function / Symbol / nested non-POJO).\nfunction warnIfNonSerializableAwaitValue(value: unknown, awaitId: string): void {\n if (isProductionMode()) {\n return;\n }\n\n if (!containsNonSerializableSurface(value)) {\n return;\n }\n\n console.warn(\n `[mreact] <Await value={...}> for \"${awaitId}\" includes non-serializable ` +\n `data (Date / Map / Set / RegExp / class instance / function / Symbol). ` +\n `The wire format uses JSON.stringify, so the client-side renderer may ` +\n `receive a different shape after the JSON round-trip. Convert to plain ` +\n `JSON-serializable data before it reaches <Await>. See ` +\n `https://github.com/t-k/mreact#streaming-loading-and-await.`,\n );\n}\n\nfunction containsNonSerializableSurface(value: unknown): boolean {\n if (value === null || value === undefined || typeof value !== \"object\") {\n return false;\n }\n\n if (value instanceof Date || value instanceof Map || value instanceof Set || value instanceof RegExp) {\n return true;\n }\n\n if (Array.isArray(value)) {\n return value.some((entry) => containsNonSerializableSurface(entry));\n }\n\n const proto = Object.getPrototypeOf(value);\n\n if (proto !== Object.prototype && proto !== null) {\n return true;\n }\n\n for (const entry of Object.values(value as Record<string, unknown>)) {\n if (containsNonSerializableSurface(entry)) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction reportAwaitPayloadSize(json: string, awaitId: string): void {\n if (json.length * 3 < AWAIT_PAYLOAD_WARN_BYTES) {\n return;\n }\n\n const byteLength = textEncoder?.encode(json).length ?? json.length;\n\n if (byteLength > AWAIT_PAYLOAD_ERROR_BYTES) {\n console.error(\n `[mreact] <Await> payload for \"${awaitId}\" is ${(byteLength / 1024 / 1024).toFixed(2)}MB, ` +\n `exceeding the 1MB error threshold. Large payloads inflate HTML response size and ` +\n `client memory pressure. Stream the data via loader or split into smaller boundaries.`,\n );\n return;\n }\n\n if (byteLength > AWAIT_PAYLOAD_WARN_BYTES) {\n console.warn(\n `[mreact] large await payload for \"${awaitId}\": ${(byteLength / 1024).toFixed(1)}KB ` +\n `(over the 100KB warning threshold). Consider streaming the data via loader or ` +\n `splitting into smaller boundaries.`,\n );\n }\n}\n\nfunction serializeAwaitHydrationValue(value: unknown, awaitId: string): string | undefined {\n try {\n const json = JSON.stringify(value);\n if (json === undefined) {\n return undefined;\n }\n\n warnIfNonSerializableAwaitValue(value, awaitId);\n reportAwaitPayloadSize(json, awaitId);\n\n // Defuse `</script>` and runaway control characters so the data can be\n // safely embedded inside a `<script>` element.\n return json\n .replaceAll(\"<\", \"\\\\u003c\")\n .replaceAll(\"\\u2028\", \"\\\\u2028\")\n .replaceAll(\"\\u2029\", \"\\\\u2029\");\n } catch {\n return undefined;\n }\n}\n\nfunction inheritBackpressure(childSink: StringHtmlSink, parentSink: HtmlSink): StringHtmlSink {\n if (parentSink.backpressure === undefined) {\n return childSink;\n }\n\n return {\n ...childSink,\n backpressure: parentSink.backpressure,\n };\n}\n\nexport function renderOutOfOrderBoundary<T>(\n sink: HtmlSink,\n id: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: OutOfOrderBoundaryOptions = {},\n): void {\n const boundaryId = nextOutOfOrderBoundaryInstanceId(sink, id);\n const placeholderSink = createStringSink();\n void options.placeholder?.(placeholderSink);\n const placeholderTag = normalizeOutOfOrderPlaceholderTag(options.placeholderTag);\n const hydrationStart =\n options.hydration === true ? `<!--mreact-h:start:${encodeURIComponent(boundaryId)}-->` : \"\";\n const hydrationEnd =\n options.hydration === true ? `<!--mreact-h:end:${encodeURIComponent(boundaryId)}-->` : \"\";\n sink.append(\n `${hydrationStart}<${placeholderTag} data-mreact-oob-placeholder=\"${escapeAttribute(boundaryId)}\">${placeholderSink.toString()}</${placeholderTag}>${hydrationEnd}`,\n );\n\n const task = renderOutOfOrderFragment(sink, boundaryId, value, render, options);\n\n if (sink.defer === undefined) {\n void task;\n return;\n }\n\n sink.defer(task);\n}\n\nfunction normalizeOutOfOrderPlaceholderTag(tag: unknown): string {\n if (typeof tag !== \"string\") {\n return \"span\";\n }\n\n const normalized = tag.trim().toLowerCase();\n return /^[a-z][a-z0-9-]*$/.test(normalized) ? normalized : \"span\";\n}\n\nasync function renderOutOfOrderFragment<T>(\n sink: HtmlSink,\n id: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: OutOfOrderBoundaryOptions,\n): Promise<void> {\n const fragmentSink = inheritBackpressure(createStringSink(), sink);\n let resolvedValue: unknown;\n let hasResolvedValue = false;\n\n await renderAsyncBoundary(\n fragmentSink,\n value,\n async (childSink, resolved) => {\n resolvedValue = resolved;\n hasResolvedValue = true;\n await render(childSink, resolved);\n },\n options.catch === undefined ? {} : { catch: options.catch },\n );\n await fragmentSink.drain();\n\n sink.append(\n `<template data-mreact-oob-fragment=\"${escapeAttribute(id)}\">${fragmentSink.toString()}</template>`,\n );\n\n if (hasResolvedValue && options.hydrationAwaitId !== undefined) {\n appendAwaitHydrationData(sink, options.hydrationAwaitId, resolvedValue);\n }\n}\n\nexport function renderOutOfOrderReorderScript(\n sink: HtmlSink,\n options: OutOfOrderReorderScriptOptions = {},\n): void {\n const nonceAttribute =\n options.nonce === undefined ? \"\" : ` nonce=\"${escapeAttribute(options.nonce)}\"`;\n\n if (options.src !== undefined) {\n sink.append(\n `<script data-mreact-oob-reorder${nonceAttribute} src=\"${escapeAttribute(options.src)}\"></script>`,\n );\n return;\n }\n\n sink.append(\n `<script data-mreact-oob-reorder${nonceAttribute}>${outOfOrderReorderScript}</script>`,\n );\n}\n\nexport function renderReactSuspenseBoundary(\n sink: HtmlSink,\n render: (sink: HtmlSink) => void | PromiseLike<void>,\n): void | PromiseLike<void> {\n sink.append(\"<!--$-->\");\n const result = render(sink);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(\"<!--/$-->\");\n });\n }\n\n sink.append(\"<!--/$-->\");\n}\n\nexport function renderReactSuspenseOutOfOrderBoundary<T>(\n sink: HtmlSink,\n boundaryId: string,\n segmentId: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: ReactSuspenseBoundaryOptions = {},\n): void {\n const actualBoundaryId = nextOutOfOrderBoundaryInstanceId(sink, boundaryId);\n const suffix = actualBoundaryId.slice(boundaryId.length);\n const actualSegmentId = `${segmentId}${suffix}`;\n const fallbackSink = createStringSink();\n void options.fallback?.(fallbackSink);\n sink.append(\n `<!--$?--><template id=\"${escapeAttribute(actualBoundaryId)}\"></template>${fallbackSink.toString()}<!--/$-->`,\n );\n\n const task = renderReactSuspenseSegment(\n sink,\n actualBoundaryId,\n actualSegmentId,\n value,\n render,\n options,\n );\n\n if (sink.defer === undefined) {\n void task;\n return;\n }\n\n sink.defer(task);\n}\n\nfunction nextOutOfOrderBoundaryInstanceId(sink: HtmlSink, id: string): string {\n let instances = outOfOrderBoundaryInstances.get(sink);\n\n if (instances === undefined) {\n instances = new Map();\n outOfOrderBoundaryInstances.set(sink, instances);\n }\n\n const count = instances.get(id) ?? 0;\n instances.set(id, count + 1);\n\n return count === 0 ? id : `${id}-${count.toString(36)}`;\n}\n\nexport function renderReactSuspenseClientRenderBoundary(\n sink: HtmlSink,\n fallback: (sink: HtmlSink) => void | PromiseLike<void>,\n options: ReactSuspenseClientRenderOptions = {},\n): void | PromiseLike<void> {\n sink.append(`<!--$!--><template${renderReactSuspenseErrorAttributes(options)}></template>`);\n const result = fallback(sink);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(\"<!--/$-->\");\n });\n }\n\n sink.append(\"<!--/$-->\");\n}\n\nasync function renderReactSuspenseSegment<T>(\n sink: HtmlSink,\n boundaryId: string,\n segmentId: string,\n value: T,\n render: AsyncBoundaryRender<T>,\n options: ReactSuspenseBoundaryOptions,\n): Promise<void> {\n const segmentSink = inheritBackpressure(createStringSink(), sink);\n\n await renderAsyncBoundary(\n segmentSink,\n value,\n render,\n options.catch === undefined ? {} : { catch: options.catch },\n );\n\n sink.append(\n `<div hidden id=\"${escapeAttribute(segmentId)}\">${segmentSink.toString()}</div>${renderReactSuspenseRevealScript(boundaryId, segmentId, options)}`,\n );\n}\n\nfunction renderReactSuspenseErrorAttributes(options: ReactSuspenseClientRenderOptions): string {\n const message =\n options.message === undefined ? \"\" : ` data-msg=\"${escapeAttribute(options.message)}\"`;\n const stack = options.stack === undefined ? \"\" : ` data-stck=\"${escapeAttribute(options.stack)}\"`;\n\n return `${message}${stack}`;\n}\n\nfunction renderReactSuspenseRevealScript(\n boundaryId: string,\n segmentId: string,\n options: ReactSuspenseScriptOptions = {},\n): string {\n if (options.src !== undefined) {\n return `<script data-mreact-react-suspense-reveal${renderNonceAttribute(options.nonce)} src=\"${escapeAttribute(options.src)}\" data-boundary-id=\"${escapeAttribute(boundaryId)}\" data-segment-id=\"${escapeAttribute(segmentId)}\"></script>`;\n }\n\n return `<script${renderNonceAttribute(options.nonce)}>${reactSuspenseRevealScriptBody};$RC(${serializeScriptJson(boundaryId)},${serializeScriptJson(segmentId)})</script>`;\n}\n\nexport function renderHydrationBoundary(\n sink: HtmlSink,\n id: string,\n render: (sink: HtmlSink) => void | PromiseLike<void>,\n): void | PromiseLike<void> {\n const markerId = encodeURIComponent(id);\n sink.append(`<!--mreact-h:start:${markerId}-->`);\n const result = render(sink);\n\n if (isPromiseLike(result)) {\n return result.then(() => {\n sink.append(`<!--mreact-h:end:${markerId}-->`);\n });\n }\n\n sink.append(`<!--mreact-h:end:${markerId}-->`);\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<void> {\n return isPromiseLikeUnknown(value);\n}\n\nconst outOfOrderReorderScript = `(()=>{function apply(root){const fragments=Array.from(root.querySelectorAll(\"template[data-mreact-oob-fragment]\"));for(const fragment of fragments){const id=fragment.getAttribute(\"data-mreact-oob-fragment\");if(id===null)continue;const placeholders=Array.from(root.querySelectorAll(\"[data-mreact-oob-placeholder]\"));const placeholder=placeholders.find((candidate)=>candidate.getAttribute(\"data-mreact-oob-placeholder\")===id);if(placeholder===undefined)continue;placeholder.replaceWith(fragment.content.cloneNode(true));fragment.remove();}}apply(document);new MutationObserver(()=>apply(document)).observe(document.documentElement,{childList:true,subtree:true});})();`;\n\nconst 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=\"$\";})`;\n\nexport 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);})();`;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"buffer-sink.d.ts","sourceRoot":"","sources":["../src/buffer-sink.ts"],"names":[],"mappings":"AAcA,UAAU,UAAW,SAAQ,UAAU;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CACpD;AAaD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACzC,QAAQ,IAAI,UAAU,CAAC;IACvB,QAAQ,IAAI,MAAM,CAAC;IACnB,IAAI,IAAI,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC;oEACgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;6DACyD;IACzD,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;CACnC;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CA6BrB;AAyDD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU,CAkD5E"}
1
+ {"version":3,"file":"buffer-sink.d.ts","sourceRoot":"","sources":["../src/buffer-sink.ts"],"names":[],"mappings":"AAcA,UAAU,UAAW,SAAQ,UAAU;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CACpD;AAaD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC;IACzC,QAAQ,IAAI,UAAU,CAAC;IACvB,QAAQ,IAAI,MAAM,CAAC;IACnB,IAAI,IAAI,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,KAAK,IAAI,IAAI,CAAC;IACd,IAAI,IAAI,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IACzC;oEACgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;6DACyD;IACzD,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;CACnC;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,mBAAmB,CA6BrB;AAyDD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU,CA8C5E"}
@@ -110,11 +110,7 @@ export function createBufferSink(options = {}) {
110
110
  return {
111
111
  append(chunk) {
112
112
  if (typeof chunk === "string") {
113
- // Reserve worst-case byte length (4 bytes/char) up front so we
114
- // can encode in a single `write()` call without a measurement
115
- // pass; the actual encoded length is returned by `write()`.
116
- const upperBound = chunk.length * 4;
117
- ensure(upperBound);
113
+ ensure(Buffer.byteLength(chunk, "utf8"));
118
114
  offset += buffer.write(chunk, offset, "utf8");
119
115
  return;
120
116
  }
@@ -1 +1 @@
1
- {"version":3,"file":"buffer-sink.js","sourceRoot":"","sources":["../src/buffer-sink.ts"],"names":[],"mappings":"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","sourcesContent":["// Node 専用 buffer sink — issue 050 の対応。\n//\n// `createStringSink` (cross-runtime, string accumulator) と並べて、\n// Node の `Buffer` を直接 accumulate する sink を提供する。HTTP response\n// body へ `response.write(buffer)` で直接渡すと string → UTF-8 encode の\n// cost を 1 回にまとめられる利点がある。\n//\n// 注: Cloudflare Workers / Deno など `Buffer` を持たない runtime では\n// import 時に runtime error になる。cross-runtime ポータビリティが必要な\n// callsite は `@reckona/mreact-server` 本体の `createStringSink` を使う。\n//\n// tsconfig は `lib: ES2022 + DOM`, `types: []` なので `@types/node` に\n// 依存しないよう、`Buffer` の最小型を本 file 内で declare する。\n\ninterface NodeBuffer extends Uint8Array {\n toString(encoding?: string, start?: number, end?: number): string;\n write(input: string, offset: number, encoding?: string): number;\n copy(target: NodeBuffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number;\n subarray(start?: number, end?: number): NodeBuffer;\n}\n\ninterface BufferConstructor {\n from(input: string, encoding?: string): NodeBuffer;\n from(input: ArrayBufferLike | ArrayLike<number>): NodeBuffer;\n alloc(size: number): NodeBuffer;\n allocUnsafe(size: number): NodeBuffer;\n byteLength(input: string, encoding?: string): number;\n isBuffer(input: unknown): input is NodeBuffer;\n}\n\ndeclare const Buffer: BufferConstructor;\n\nexport interface BufferSink {\n append(chunk: string | NodeBuffer): void;\n toBuffer(): NodeBuffer;\n toString(): string;\n size(): number;\n}\n\nexport interface BufferSinkOptions {\n /**\n * Initial backing buffer size (UTF-8 bytes). The buffer grows\n * geometrically as needed. Default: 8192.\n */\n initialSize?: number;\n /**\n * Growth multiplier when the backing buffer needs to expand.\n * Default: 2.\n */\n growthFactor?: number;\n}\n\n/**\n * Creates a Node-only buffer sink with a single pre-allocated growing\n * backing `Buffer`. UTF-8 encoding happens in-place at the current write\n * offset, avoiding per-chunk Buffer allocation and a final concat.\n *\n * Compared to `Buffer.concat`-style implementations, this trades a small\n * amount of headroom memory for ~5-10x throughput on small chunks\n * (see docs/benchmarks/2026-05-12-server-sink-strategy.md).\n */\n/**\n * A streaming-flavored buffer sink used by\n * `renderToReadableStream`. Coalesces successive `append(chunk)` calls\n * into a single byte buffer, then hands the buffer to a consumer\n * callback either on demand (`flush()`) or automatically once the\n * accumulated UTF-8 byte length crosses a threshold.\n *\n * The contract:\n * - Each call to `flush()` (or an auto-flush triggered from within\n * `append`) delivers **exactly one** non-empty byte buffer to the\n * consumer. Empty buffers are never delivered — callers do not\n * need to filter them out.\n * - The delivered buffer is exclusively owned by the consumer; the\n * sink will not mutate it afterwards. Internally we allocate a\n * fresh backing buffer per epoch, so handing off a `subarray` view\n * is safe with no copy.\n *\n * Issue 084: motivated by the streaming SSR throughput gap to\n * marko-run (mreact was at 0.66x marko's ops/sec because the previous\n * implementation paid a `TextEncoder.encode` + Web Streams\n * `controller.enqueue` round-trip per `sink.append()` call).\n */\nexport interface StreamingBufferSink {\n append(chunk: string): void;\n flush(): void;\n size(): number;\n}\n\nexport interface StreamingBufferSinkOptions {\n /** UTF-8 byte threshold that triggers an automatic flush from inside\n * `append`. Default 8 KiB (one common TCP segment payload). */\n flushThreshold?: number;\n /** Initial backing buffer size; same semantics as `BufferSinkOptions`. */\n initialSize?: number;\n /** Consumer hook — invoked at most once per `flush()` (manual or\n * automatic), and only with a non-empty byte buffer. */\n onFlush(buffer: Uint8Array): void;\n}\n\nexport function createStreamingBufferSink(\n options: StreamingBufferSinkOptions,\n): StreamingBufferSink {\n if (!hasNodeBuffer()) {\n return createStreamingEncodedSink(options);\n }\n\n const flushThreshold = options.flushThreshold ?? 8192;\n const initialSize = options.initialSize ?? flushThreshold;\n let inner = createBufferSink({ initialSize });\n const emitAndReset = () => {\n const buf = inner.toBuffer();\n inner = createBufferSink({ initialSize });\n options.onFlush(buf);\n };\n return {\n append(chunk) {\n if (chunk === \"\") return;\n inner.append(chunk);\n if (inner.size() >= flushThreshold) {\n emitAndReset();\n }\n },\n flush() {\n if (inner.size() === 0) return;\n emitAndReset();\n },\n size() {\n return inner.size();\n },\n };\n}\n\nfunction createStreamingEncodedSink(options: StreamingBufferSinkOptions): StreamingBufferSink {\n const flushThreshold = options.flushThreshold ?? 8192;\n const encoder = new TextEncoder();\n let chunks: Uint8Array[] = [];\n let byteLength = 0;\n\n const emitAndReset = () => {\n const output = concatUint8Arrays(chunks, byteLength);\n chunks = [];\n byteLength = 0;\n options.onFlush(output);\n };\n\n return {\n append(chunk) {\n if (chunk === \"\") return;\n\n const bytes = encoder.encode(chunk);\n chunks.push(bytes);\n byteLength += bytes.byteLength;\n\n if (byteLength >= flushThreshold) {\n emitAndReset();\n }\n },\n flush() {\n if (byteLength === 0) return;\n emitAndReset();\n },\n size() {\n return byteLength;\n },\n };\n}\n\nfunction concatUint8Arrays(chunks: Uint8Array[], byteLength: number): Uint8Array {\n if (chunks.length === 1) {\n return chunks[0] ?? new Uint8Array();\n }\n\n const output = new Uint8Array(byteLength);\n let offset = 0;\n\n for (const chunk of chunks) {\n output.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return output;\n}\n\nfunction hasNodeBuffer(): boolean {\n return typeof Buffer !== \"undefined\" && typeof Buffer.allocUnsafe === \"function\";\n}\n\nexport function createBufferSink(options: BufferSinkOptions = {}): BufferSink {\n const initialSize = options.initialSize ?? 8192;\n const growthFactor = options.growthFactor ?? 2;\n let buffer = Buffer.allocUnsafe(initialSize);\n let offset = 0;\n\n function ensure(requiredBytes: number): void {\n const required = offset + requiredBytes;\n\n if (required <= buffer.length) {\n return;\n }\n\n let newCapacity = buffer.length === 0 ? initialSize : buffer.length;\n\n while (newCapacity < required) {\n newCapacity = Math.ceil(newCapacity * growthFactor);\n }\n\n const grown = Buffer.allocUnsafe(newCapacity);\n buffer.copy(grown, 0, 0, offset);\n buffer = grown;\n }\n\n return {\n append(chunk) {\n if (typeof chunk === \"string\") {\n // Reserve worst-case byte length (4 bytes/char) up front so we\n // can encode in a single `write()` call without a measurement\n // pass; the actual encoded length is returned by `write()`.\n const upperBound = chunk.length * 4;\n ensure(upperBound);\n offset += buffer.write(chunk, offset, \"utf8\");\n return;\n }\n\n ensure(chunk.length);\n chunk.copy(buffer, offset);\n offset += chunk.length;\n },\n toBuffer() {\n return buffer.subarray(0, offset);\n },\n toString() {\n return buffer.toString(\"utf8\", 0, offset);\n },\n size() {\n return offset;\n },\n };\n}\n"]}
1
+ {"version":3,"file":"buffer-sink.js","sourceRoot":"","sources":["../src/buffer-sink.ts"],"names":[],"mappings":"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","sourcesContent":["// Node 専用 buffer sink — issue 050 の対応。\n//\n// `createStringSink` (cross-runtime, string accumulator) と並べて、\n// Node の `Buffer` を直接 accumulate する sink を提供する。HTTP response\n// body へ `response.write(buffer)` で直接渡すと string → UTF-8 encode の\n// cost を 1 回にまとめられる利点がある。\n//\n// 注: Cloudflare Workers / Deno など `Buffer` を持たない runtime では\n// import 時に runtime error になる。cross-runtime ポータビリティが必要な\n// callsite は `@reckona/mreact-server` 本体の `createStringSink` を使う。\n//\n// tsconfig は `lib: ES2022 + DOM`, `types: []` なので `@types/node` に\n// 依存しないよう、`Buffer` の最小型を本 file 内で declare する。\n\ninterface NodeBuffer extends Uint8Array {\n toString(encoding?: string, start?: number, end?: number): string;\n write(input: string, offset: number, encoding?: string): number;\n copy(target: NodeBuffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number;\n subarray(start?: number, end?: number): NodeBuffer;\n}\n\ninterface BufferConstructor {\n from(input: string, encoding?: string): NodeBuffer;\n from(input: ArrayBufferLike | ArrayLike<number>): NodeBuffer;\n alloc(size: number): NodeBuffer;\n allocUnsafe(size: number): NodeBuffer;\n byteLength(input: string, encoding?: string): number;\n isBuffer(input: unknown): input is NodeBuffer;\n}\n\ndeclare const Buffer: BufferConstructor;\n\nexport interface BufferSink {\n append(chunk: string | NodeBuffer): void;\n toBuffer(): NodeBuffer;\n toString(): string;\n size(): number;\n}\n\nexport interface BufferSinkOptions {\n /**\n * Initial backing buffer size (UTF-8 bytes). The buffer grows\n * geometrically as needed. Default: 8192.\n */\n initialSize?: number;\n /**\n * Growth multiplier when the backing buffer needs to expand.\n * Default: 2.\n */\n growthFactor?: number;\n}\n\n/**\n * Creates a Node-only buffer sink with a single pre-allocated growing\n * backing `Buffer`. UTF-8 encoding happens in-place at the current write\n * offset, avoiding per-chunk Buffer allocation and a final concat.\n *\n * Compared to `Buffer.concat`-style implementations, this trades a small\n * amount of headroom memory for ~5-10x throughput on small chunks\n * (see docs/benchmarks/2026-05-12-server-sink-strategy.md).\n */\n/**\n * A streaming-flavored buffer sink used by\n * `renderToReadableStream`. Coalesces successive `append(chunk)` calls\n * into a single byte buffer, then hands the buffer to a consumer\n * callback either on demand (`flush()`) or automatically once the\n * accumulated UTF-8 byte length crosses a threshold.\n *\n * The contract:\n * - Each call to `flush()` (or an auto-flush triggered from within\n * `append`) delivers **exactly one** non-empty byte buffer to the\n * consumer. Empty buffers are never delivered — callers do not\n * need to filter them out.\n * - The delivered buffer is exclusively owned by the consumer; the\n * sink will not mutate it afterwards. Internally we allocate a\n * fresh backing buffer per epoch, so handing off a `subarray` view\n * is safe with no copy.\n *\n * Issue 084: motivated by the streaming SSR throughput gap to\n * marko-run (mreact was at 0.66x marko's ops/sec because the previous\n * implementation paid a `TextEncoder.encode` + Web Streams\n * `controller.enqueue` round-trip per `sink.append()` call).\n */\nexport interface StreamingBufferSink {\n append(chunk: string): void;\n flush(): void;\n size(): number;\n}\n\nexport interface StreamingBufferSinkOptions {\n /** UTF-8 byte threshold that triggers an automatic flush from inside\n * `append`. Default 8 KiB (one common TCP segment payload). */\n flushThreshold?: number;\n /** Initial backing buffer size; same semantics as `BufferSinkOptions`. */\n initialSize?: number;\n /** Consumer hook — invoked at most once per `flush()` (manual or\n * automatic), and only with a non-empty byte buffer. */\n onFlush(buffer: Uint8Array): void;\n}\n\nexport function createStreamingBufferSink(\n options: StreamingBufferSinkOptions,\n): StreamingBufferSink {\n if (!hasNodeBuffer()) {\n return createStreamingEncodedSink(options);\n }\n\n const flushThreshold = options.flushThreshold ?? 8192;\n const initialSize = options.initialSize ?? flushThreshold;\n let inner = createBufferSink({ initialSize });\n const emitAndReset = () => {\n const buf = inner.toBuffer();\n inner = createBufferSink({ initialSize });\n options.onFlush(buf);\n };\n return {\n append(chunk) {\n if (chunk === \"\") return;\n inner.append(chunk);\n if (inner.size() >= flushThreshold) {\n emitAndReset();\n }\n },\n flush() {\n if (inner.size() === 0) return;\n emitAndReset();\n },\n size() {\n return inner.size();\n },\n };\n}\n\nfunction createStreamingEncodedSink(options: StreamingBufferSinkOptions): StreamingBufferSink {\n const flushThreshold = options.flushThreshold ?? 8192;\n const encoder = new TextEncoder();\n let chunks: Uint8Array[] = [];\n let byteLength = 0;\n\n const emitAndReset = () => {\n const output = concatUint8Arrays(chunks, byteLength);\n chunks = [];\n byteLength = 0;\n options.onFlush(output);\n };\n\n return {\n append(chunk) {\n if (chunk === \"\") return;\n\n const bytes = encoder.encode(chunk);\n chunks.push(bytes);\n byteLength += bytes.byteLength;\n\n if (byteLength >= flushThreshold) {\n emitAndReset();\n }\n },\n flush() {\n if (byteLength === 0) return;\n emitAndReset();\n },\n size() {\n return byteLength;\n },\n };\n}\n\nfunction concatUint8Arrays(chunks: Uint8Array[], byteLength: number): Uint8Array {\n if (chunks.length === 1) {\n return chunks[0] ?? new Uint8Array();\n }\n\n const output = new Uint8Array(byteLength);\n let offset = 0;\n\n for (const chunk of chunks) {\n output.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return output;\n}\n\nfunction hasNodeBuffer(): boolean {\n return typeof Buffer !== \"undefined\" && typeof Buffer.allocUnsafe === \"function\";\n}\n\nexport function createBufferSink(options: BufferSinkOptions = {}): BufferSink {\n const initialSize = options.initialSize ?? 8192;\n const growthFactor = options.growthFactor ?? 2;\n let buffer = Buffer.allocUnsafe(initialSize);\n let offset = 0;\n\n function ensure(requiredBytes: number): void {\n const required = offset + requiredBytes;\n\n if (required <= buffer.length) {\n return;\n }\n\n let newCapacity = buffer.length === 0 ? initialSize : buffer.length;\n\n while (newCapacity < required) {\n newCapacity = Math.ceil(newCapacity * growthFactor);\n }\n\n const grown = Buffer.allocUnsafe(newCapacity);\n buffer.copy(grown, 0, 0, offset);\n buffer = grown;\n }\n\n return {\n append(chunk) {\n if (typeof chunk === \"string\") {\n ensure(Buffer.byteLength(chunk, \"utf8\"));\n offset += buffer.write(chunk, offset, \"utf8\");\n return;\n }\n\n ensure(chunk.length);\n chunk.copy(buffer, offset);\n offset += chunk.length;\n },\n toBuffer() {\n return buffer.subarray(0, offset);\n },\n toString() {\n return buffer.toString(\"utf8\", 0, offset);\n },\n size() {\n return offset;\n },\n };\n}\n"]}
package/dist/flight.js CHANGED
@@ -352,7 +352,9 @@ export function renderFlightPreloadLinks(response, options = {}) {
352
352
  .map((chunk) => `<link rel="modulepreload" href="${escapeAttribute(chunk)}"${nonceAttribute}>`)
353
353
  .join("");
354
354
  }
355
- function resolveFlightPromiseChunks(model, modelChunks, errorChunks) {
355
+ function resolveFlightPromiseChunks(model, modelChunks, errorChunks, depth = 0, context = createFlightDecodeContext()) {
356
+ if (depth > MAX_FLIGHT_DECODE_DEPTH)
357
+ flightTooDeep();
356
358
  if (model === null ||
357
359
  typeof model === "string" ||
358
360
  typeof model === "number" ||
@@ -360,7 +362,7 @@ function resolveFlightPromiseChunks(model, modelChunks, errorChunks) {
360
362
  return model;
361
363
  }
362
364
  if (Array.isArray(model)) {
363
- return model.map((item) => resolveFlightPromiseChunks(item, modelChunks, errorChunks));
365
+ return model.map((item) => resolveFlightPromiseChunks(item, modelChunks, errorChunks, depth + 1, context));
364
366
  }
365
367
  if (model.kind === "promise") {
366
368
  const error = errorChunks.get(model.id);
@@ -368,7 +370,16 @@ function resolveFlightPromiseChunks(model, modelChunks, errorChunks) {
368
370
  return error;
369
371
  }
370
372
  if (modelChunks.has(model.id)) {
371
- return decodeReactFlightModel(modelChunks.get(model.id), modelChunks, errorChunks);
373
+ if (context.inProgressChunkIds.has(model.id)) {
374
+ flightCycle(model.id);
375
+ }
376
+ context.inProgressChunkIds.add(model.id);
377
+ try {
378
+ return decodeReactFlightModel(modelChunks.get(model.id), modelChunks, errorChunks, depth + 1, context);
379
+ }
380
+ finally {
381
+ context.inProgressChunkIds.delete(model.id);
382
+ }
372
383
  }
373
384
  return model;
374
385
  }
@@ -377,7 +388,7 @@ function resolveFlightPromiseChunks(model, modelChunks, errorChunks) {
377
388
  ...model,
378
389
  props: Object.fromEntries(Object.entries(model.props).map(([key, value]) => [
379
390
  key,
380
- resolveFlightPromiseChunks(value, modelChunks, errorChunks),
391
+ resolveFlightPromiseChunks(value, modelChunks, errorChunks, depth + 1, context),
381
392
  ])),
382
393
  };
383
394
  }
@@ -385,15 +396,15 @@ function resolveFlightPromiseChunks(model, modelChunks, errorChunks) {
385
396
  return {
386
397
  ...model,
387
398
  entries: model.entries.map(([key, value]) => [
388
- resolveFlightPromiseChunks(key, modelChunks, errorChunks),
389
- resolveFlightPromiseChunks(value, modelChunks, errorChunks),
399
+ resolveFlightPromiseChunks(key, modelChunks, errorChunks, depth + 1, context),
400
+ resolveFlightPromiseChunks(value, modelChunks, errorChunks, depth + 1, context),
390
401
  ]),
391
402
  };
392
403
  }
393
404
  if (model.kind === "set") {
394
405
  return {
395
406
  ...model,
396
- values: model.values.map((value) => resolveFlightPromiseChunks(value, modelChunks, errorChunks)),
407
+ values: model.values.map((value) => resolveFlightPromiseChunks(value, modelChunks, errorChunks, depth + 1, context)),
397
408
  };
398
409
  }
399
410
  if ("kind" in model) {
@@ -401,7 +412,9 @@ function resolveFlightPromiseChunks(model, modelChunks, errorChunks) {
401
412
  }
402
413
  return Object.fromEntries(Object.entries(model).map(([key, value]) => [
403
414
  key,
404
- value === undefined ? undefined : resolveFlightPromiseChunks(value, modelChunks, errorChunks),
415
+ value === undefined
416
+ ? undefined
417
+ : resolveFlightPromiseChunks(value, modelChunks, errorChunks, depth + 1, context),
405
418
  ]));
406
419
  }
407
420
  function encodeReactFlightModel(model, state) {
@@ -713,7 +726,15 @@ class FlightDecodeError extends Error {
713
726
  function flightTooDeep() {
714
727
  throw new FlightDecodeError(`MR_FLIGHT_TOO_DEEP: nested deeper than ${MAX_FLIGHT_DECODE_DEPTH} levels`);
715
728
  }
716
- function decodeReactFlightModel(value, modelChunks = new Map(), errorChunks = new Map(), depth = 0) {
729
+ function flightCycle(id) {
730
+ throw new FlightDecodeError(`MR_FLIGHT_CYCLE: cyclic chunk reference ${id}`);
731
+ }
732
+ function createFlightDecodeContext() {
733
+ return {
734
+ inProgressChunkIds: new Set(),
735
+ };
736
+ }
737
+ function decodeReactFlightModel(value, modelChunks = new Map(), errorChunks = new Map(), depth = 0, context = createFlightDecodeContext()) {
717
738
  if (depth > MAX_FLIGHT_DECODE_DEPTH)
718
739
  flightTooDeep();
719
740
  if (value === null ||
@@ -722,7 +743,7 @@ function decodeReactFlightModel(value, modelChunks = new Map(), errorChunks = ne
722
743
  return value;
723
744
  }
724
745
  if (typeof value === "string") {
725
- return decodeReactFlightString(value, modelChunks, errorChunks);
746
+ return decodeReactFlightString(value, modelChunks, errorChunks, depth, context);
726
747
  }
727
748
  if (Array.isArray(value)) {
728
749
  if (value[0] === "$") {
@@ -730,20 +751,20 @@ function decodeReactFlightModel(value, modelChunks = new Map(), errorChunks = ne
730
751
  kind: "element",
731
752
  type: decodeReactFlightElementType(value[1]),
732
753
  key: typeof value[2] === "string" ? value[2] : null,
733
- props: decodeReactFlightProps(valueIsObject(value[3]) ? value[3] : {}, modelChunks, errorChunks, depth + 1),
754
+ props: decodeReactFlightProps(valueIsObject(value[3]) ? value[3] : {}, modelChunks, errorChunks, depth + 1, context),
734
755
  };
735
756
  }
736
- return value.map((item) => decodeReactFlightModel(item, modelChunks, errorChunks, depth + 1));
757
+ return value.map((item) => decodeReactFlightModel(item, modelChunks, errorChunks, depth + 1, context));
737
758
  }
738
759
  if (isReactFlightBinaryModel(value)) {
739
760
  return value;
740
761
  }
741
762
  if (valueIsObject(value)) {
742
- return decodeReactFlightProps(value, modelChunks, errorChunks, depth + 1);
763
+ return decodeReactFlightProps(value, modelChunks, errorChunks, depth + 1, context);
743
764
  }
744
765
  return { kind: "undefined" };
745
766
  }
746
- function decodeReactFlightString(value, modelChunks, errorChunks) {
767
+ function decodeReactFlightString(value, modelChunks, errorChunks, depth, context) {
747
768
  if (value === "$undefined" || value === "$u") {
748
769
  return { kind: "undefined" };
749
770
  }
@@ -769,7 +790,7 @@ function decodeReactFlightString(value, modelChunks, errorChunks) {
769
790
  return { kind: "bigint", value: value.slice(2) };
770
791
  }
771
792
  if (/^\$[AOoUSsLlGgMmV][0-9a-f]+$/.test(value)) {
772
- return decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
793
+ return decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks, depth + 1, context);
773
794
  }
774
795
  if (value.startsWith("$S")) {
775
796
  return { kind: "symbol", name: value.slice(2) };
@@ -793,7 +814,7 @@ function decodeReactFlightString(value, modelChunks, errorChunks) {
793
814
  };
794
815
  }
795
816
  if (/^\$Q[0-9a-f]+$/i.test(value)) {
796
- const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
817
+ const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks, depth + 1, context);
797
818
  const entries = Array.isArray(decoded)
798
819
  ? decoded.map((entry) => Array.isArray(entry) ? [entry[0] ?? { kind: "undefined" }, entry[1] ?? { kind: "undefined" }] : [entry, { kind: "undefined" }])
799
820
  : [];
@@ -803,14 +824,14 @@ function decodeReactFlightString(value, modelChunks, errorChunks) {
803
824
  };
804
825
  }
805
826
  if (/^\$W[0-9a-f]+$/i.test(value)) {
806
- const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
827
+ const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks, depth + 1, context);
807
828
  return {
808
829
  kind: "set",
809
830
  values: Array.isArray(decoded) ? decoded : [],
810
831
  };
811
832
  }
812
833
  if (/^\$K[0-9a-f]+$/i.test(value)) {
813
- const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
834
+ const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks, depth + 1, context);
814
835
  const entries = Array.isArray(decoded)
815
836
  ? decoded.flatMap((entry) => Array.isArray(entry) && typeof entry[0] === "string"
816
837
  ? [[entry[0], entry[1] ?? { kind: "undefined" }]]
@@ -822,7 +843,7 @@ function decodeReactFlightString(value, modelChunks, errorChunks) {
822
843
  };
823
844
  }
824
845
  if (/^\$i[0-9a-f]+$/i.test(value)) {
825
- const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks);
846
+ const decoded = decodeReactFlightChunk(value.slice(2), modelChunks, errorChunks, depth + 1, context);
826
847
  return {
827
848
  kind: "iterable",
828
849
  values: Array.isArray(decoded) ? decoded : [],
@@ -839,11 +860,13 @@ function decodeReactFlightString(value, modelChunks, errorChunks) {
839
860
  return { kind: "undefined" };
840
861
  }
841
862
  if (/^\$[0-9a-f]+$/i.test(value)) {
842
- return decodeReactFlightChunk(value.slice(1), modelChunks, errorChunks);
863
+ return decodeReactFlightChunk(value.slice(1), modelChunks, errorChunks, depth + 1, context);
843
864
  }
844
865
  return value;
845
866
  }
846
- function decodeReactFlightChunk(id, modelChunks, errorChunks) {
867
+ function decodeReactFlightChunk(id, modelChunks, errorChunks, depth, context) {
868
+ if (depth > MAX_FLIGHT_DECODE_DEPTH)
869
+ flightTooDeep();
847
870
  const numericId = parseReactFlightId(id);
848
871
  const error = errorChunks.get(numericId);
849
872
  if (error !== undefined) {
@@ -855,7 +878,16 @@ function decodeReactFlightChunk(id, modelChunks, errorChunks) {
855
878
  id: numericId,
856
879
  };
857
880
  }
858
- return decodeReactFlightModel(modelChunks.get(numericId), modelChunks, errorChunks);
881
+ if (context.inProgressChunkIds.has(numericId)) {
882
+ flightCycle(numericId);
883
+ }
884
+ context.inProgressChunkIds.add(numericId);
885
+ try {
886
+ return decodeReactFlightModel(modelChunks.get(numericId), modelChunks, errorChunks, depth, context);
887
+ }
888
+ finally {
889
+ context.inProgressChunkIds.delete(numericId);
890
+ }
859
891
  }
860
892
  function decodeReactFlightElementType(value) {
861
893
  if (value === "$Sreact.fragment") {
@@ -869,12 +901,12 @@ function decodeReactFlightElementType(value) {
869
901
  }
870
902
  return typeof value === "string" ? value : String(value);
871
903
  }
872
- function decodeReactFlightProps(value, modelChunks, errorChunks, depth = 0) {
904
+ function decodeReactFlightProps(value, modelChunks, errorChunks, depth = 0, context = createFlightDecodeContext()) {
873
905
  if (depth > MAX_FLIGHT_DECODE_DEPTH)
874
906
  flightTooDeep();
875
907
  return Object.fromEntries(Object.entries(value).map(([key, child]) => [
876
908
  key,
877
- decodeReactFlightModel(child, modelChunks, errorChunks, depth + 1),
909
+ decodeReactFlightModel(child, modelChunks, errorChunks, depth + 1, context),
878
910
  ]));
879
911
  }
880
912
  function isReactFlightBinaryModel(value) {