@reckona/mreact-server 0.0.160 → 0.0.162
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boundary.d.ts +16 -0
- package/dist/boundary.d.ts.map +1 -1
- package/dist/boundary.js +8 -0
- package/dist/boundary.js.map +1 -1
- package/dist/buffer-sink.d.ts +8 -9
- package/dist/buffer-sink.d.ts.map +1 -1
- package/dist/buffer-sink.js +5 -0
- package/dist/buffer-sink.js.map +1 -1
- package/dist/flight.d.ts +51 -0
- package/dist/flight.d.ts.map +1 -1
- package/dist/flight.js +16 -0
- package/dist/flight.js.map +1 -1
- package/dist/html-helpers.d.ts +12 -0
- package/dist/html-helpers.d.ts.map +1 -1
- package/dist/html-helpers.js +8 -0
- package/dist/html-helpers.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/reorder.d.ts +1 -0
- package/dist/reorder.d.ts.map +1 -1
- package/dist/reorder.js +1 -0
- package/dist/reorder.js.map +1 -1
- package/dist/sink.d.ts +6 -0
- package/dist/sink.d.ts.map +1 -1
- package/dist/sink.js +2 -0
- package/dist/sink.js.map +1 -1
- package/dist/stream.d.ts +2 -0
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +1 -0
- package/dist/stream.js.map +1 -1
- package/package.json +3 -3
- package/src/boundary.ts +16 -0
- package/src/buffer-sink.ts +8 -9
- package/src/flight.ts +51 -0
- package/src/html-helpers.ts +12 -0
- package/src/index.ts +5 -0
- package/src/reorder.ts +1 -0
- package/src/sink.ts +6 -0
- package/src/stream.ts +2 -0
package/dist/html-helpers.js
CHANGED
|
@@ -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 };
|
package/dist/html-helpers.js.map
CHANGED
|
@@ -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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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;
|
|
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
package/dist/reorder.d.ts.map
CHANGED
|
@@ -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) {
|
package/dist/reorder.js.map
CHANGED
|
@@ -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":["
|
|
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
|
package/dist/sink.d.ts.map
CHANGED
|
@@ -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":"
|
|
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
|
package/dist/stream.d.ts.map
CHANGED
|
@@ -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))`
|
package/dist/stream.js.map
CHANGED
|
@@ -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.
|
|
3
|
+
"version": "0.0.162",
|
|
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.
|
|
65
|
-
"@reckona/mreact-shared": "0.0.
|
|
64
|
+
"@reckona/mreact-compat": "0.0.162",
|
|
65
|
+
"@reckona/mreact-shared": "0.0.162"
|
|
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);})();`;
|