@tanstack/router-core 1.143.6 → 1.145.6
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/cjs/index.cjs +5 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -0
- package/dist/cjs/scroll-restoration.cjs +10 -1
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/RawStream.cjs +288 -0
- package/dist/cjs/ssr/serializer/RawStream.cjs.map +1 -0
- package/dist/cjs/ssr/serializer/RawStream.d.cts +64 -0
- package/dist/cjs/ssr/serializer/seroval-plugins.cjs +3 -0
- package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +1 -1
- package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/transformer.d.cts +3 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/scroll-restoration.js +10 -1
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/ssr/serializer/RawStream.d.ts +64 -0
- package/dist/esm/ssr/serializer/RawStream.js +288 -0
- package/dist/esm/ssr/serializer/RawStream.js.map +1 -0
- package/dist/esm/ssr/serializer/seroval-plugins.d.ts +1 -1
- package/dist/esm/ssr/serializer/seroval-plugins.js +3 -0
- package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -1
- package/dist/esm/ssr/serializer/transformer.d.ts +3 -0
- package/dist/esm/ssr/serializer/transformer.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +12 -0
- package/src/scroll-restoration.ts +10 -4
- package/src/ssr/serializer/RawStream.ts +464 -0
- package/src/ssr/serializer/seroval-plugins.ts +3 -0
- package/src/ssr/serializer/transformer.ts +3 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -18,6 +18,7 @@ const notFound = require("./not-found.cjs");
|
|
|
18
18
|
const scrollRestoration = require("./scroll-restoration.cjs");
|
|
19
19
|
const transformer = require("./ssr/serializer/transformer.cjs");
|
|
20
20
|
const serovalPlugins = require("./ssr/serializer/seroval-plugins.cjs");
|
|
21
|
+
const RawStream = require("./ssr/serializer/RawStream.cjs");
|
|
21
22
|
const rewrite = require("./rewrite.cjs");
|
|
22
23
|
exports.TSR_DEFERRED_PROMISE = defer.TSR_DEFERRED_PROMISE;
|
|
23
24
|
exports.defer = defer.defer;
|
|
@@ -81,6 +82,10 @@ exports.createSerializationAdapter = transformer.createSerializationAdapter;
|
|
|
81
82
|
exports.makeSerovalPlugin = transformer.makeSerovalPlugin;
|
|
82
83
|
exports.makeSsrSerovalPlugin = transformer.makeSsrSerovalPlugin;
|
|
83
84
|
exports.defaultSerovalPlugins = serovalPlugins.defaultSerovalPlugins;
|
|
85
|
+
exports.RawStream = RawStream.RawStream;
|
|
86
|
+
exports.RawStreamSSRPlugin = RawStream.RawStreamSSRPlugin;
|
|
87
|
+
exports.createRawStreamDeserializePlugin = RawStream.createRawStreamDeserializePlugin;
|
|
88
|
+
exports.createRawStreamRPCPlugin = RawStream.createRawStreamRPCPlugin;
|
|
84
89
|
exports.composeRewrites = rewrite.composeRewrites;
|
|
85
90
|
exports.executeRewriteInput = rewrite.executeRewriteInput;
|
|
86
91
|
exports.executeRewriteOutput = rewrite.executeRewriteOutput;
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -43,5 +43,7 @@ export type { ValidateFromPath, ValidateToPath, ValidateSearch, ValidateParams,
|
|
|
43
43
|
export type { AnySerializationAdapter, SerializationAdapter, ValidateSerializableInput, ValidateSerializableInputResult, SerializerExtensions, ValidateSerializable, RegisteredSerializableInput, SerializableExtensions, DefaultSerializable, Serializable, TSR_SERIALIZABLE, TsrSerializable, } from './ssr/serializer/transformer.cjs';
|
|
44
44
|
export { createSerializationAdapter, makeSerovalPlugin, makeSsrSerovalPlugin, } from './ssr/serializer/transformer.cjs';
|
|
45
45
|
export { defaultSerovalPlugins } from './ssr/serializer/seroval-plugins.cjs';
|
|
46
|
+
export { RawStream, RawStreamSSRPlugin, createRawStreamRPCPlugin, createRawStreamDeserializePlugin, } from './ssr/serializer/RawStream.cjs';
|
|
47
|
+
export type { OnRawStreamCallback, RawStreamHint, RawStreamOptions, } from './ssr/serializer/RawStream.cjs';
|
|
46
48
|
export { composeRewrites, executeRewriteInput, executeRewriteOutput, } from './rewrite.cjs';
|
|
47
49
|
export type { LocationRewrite, LocationRewriteFunction } from './router.cjs';
|
|
@@ -34,7 +34,16 @@ function createScrollRestorationCache() {
|
|
|
34
34
|
// This setter is simply to make sure that we set the sessionStorage right
|
|
35
35
|
// after the state is updated. It doesn't necessarily need to be a functional
|
|
36
36
|
// update.
|
|
37
|
-
set: (updater) =>
|
|
37
|
+
set: (updater) => {
|
|
38
|
+
state = utils.functionalUpdate(updater, state) || state;
|
|
39
|
+
try {
|
|
40
|
+
safeSessionStorage.setItem(storageKey, JSON.stringify(state));
|
|
41
|
+
} catch {
|
|
42
|
+
console.warn(
|
|
43
|
+
"[ts-router] Could not persist scroll restoration state to sessionStorage."
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
38
47
|
};
|
|
39
48
|
}
|
|
40
49
|
const scrollRestorationCache = createScrollRestorationCache();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scroll-restoration.cjs","sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { functionalUpdate } from './utils'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\nimport type { HistoryLocation } from '@tanstack/history'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\nexport type ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\nexport type ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\nexport type ScrollRestorationCache = {\n state: ScrollRestorationByKey\n set: (updater: NonNullableUpdater<ScrollRestorationByKey>) => void\n}\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n if (\n typeof window !== 'undefined' &&\n typeof window.sessionStorage === 'object'\n ) {\n return window.sessionStorage\n }\n } catch {\n // silent\n }\n return undefined\n}\n\n/** SessionStorage key used to persist scroll restoration state. */\n/** SessionStorage key used to store scroll positions across navigations. */\n/** SessionStorage key used to store scroll positions across navigations. */\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\n\nconst throttle = (fn: (...args: Array<any>) => void, wait: number) => {\n let timeout: any\n return (...args: Array<any>) => {\n if (!timeout) {\n timeout = setTimeout(() => {\n fn(...args)\n timeout = null\n }, wait)\n }\n }\n}\n\nfunction createScrollRestorationCache(): ScrollRestorationCache | null {\n const safeSessionStorage = getSafeSessionStorage()\n if (!safeSessionStorage) {\n return null\n }\n\n const persistedState = safeSessionStorage.getItem(storageKey)\n let state: ScrollRestorationByKey = persistedState\n ? JSON.parse(persistedState)\n : {}\n\n return {\n state,\n // This setter is simply to make sure that we set the sessionStorage right\n // after the state is updated. It doesn't necessarily need to be a functional\n // update.\n set: (updater) => (\n (state = functionalUpdate(updater, state) || state),\n safeSessionStorage.setItem(storageKey, JSON.stringify(state))\n ),\n }\n}\n\n/** In-memory handle to the persisted scroll restoration cache. */\nexport const scrollRestorationCache = createScrollRestorationCache()\n\n/**\n * The default `getKey` function for `useScrollRestoration`.\n * It returns the `key` from the location state or the `href` of the location.\n *\n * The `location.href` is used as a fallback to support the use case where the location state is not available like the initial render.\n */\n\n/**\n * Default scroll restoration cache key: location state key or full href.\n */\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\n/** Best-effort nth-child CSS selector for a given element. */\nexport function getCssSelector(el: any): string {\n const path = []\n let parent: HTMLElement\n while ((parent = el.parentNode)) {\n path.push(\n `${el.tagName}:nth-child(${Array.prototype.indexOf.call(parent.children, el) + 1})`,\n )\n el = parent\n }\n return `${path.reverse().join(' > ')}`.toLowerCase()\n}\n\nlet ignoreScroll = false\n\n// NOTE: This function must remain pure and not use any outside variables\n// unless they are passed in as arguments. Why? Because we need to be able to\n// toString() it into a script tag to execute as early as possible in the browser\n// during SSR. Additionally, we also call it from within the router lifecycle\nexport function restoreScroll({\n storageKey,\n key,\n behavior,\n shouldScrollRestoration,\n scrollToTopSelectors,\n location,\n}: {\n storageKey: string\n key?: string\n behavior?: ScrollToOptions['behavior']\n shouldScrollRestoration?: boolean\n scrollToTopSelectors?: Array<string | (() => Element | null | undefined)>\n location?: HistoryLocation\n}) {\n let byKey: ScrollRestorationByKey\n\n try {\n byKey = JSON.parse(sessionStorage.getItem(storageKey) || '{}')\n } catch (error) {\n console.error(error)\n return\n }\n\n const resolvedKey = key || window.history.state?.__TSR_key\n const elementEntries = byKey[resolvedKey]\n\n //\n ignoreScroll = true\n\n //\n scroll: {\n // If we have a cached entry for this location state,\n // we always need to prefer that over the hash scroll.\n if (\n shouldScrollRestoration &&\n elementEntries &&\n Object.keys(elementEntries).length > 0\n ) {\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]!\n if (elementSelector === 'window') {\n window.scrollTo({\n top: entry.scrollY,\n left: entry.scrollX,\n behavior,\n })\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n element.scrollLeft = entry.scrollX\n element.scrollTop = entry.scrollY\n }\n }\n }\n\n break scroll\n }\n\n // If we don't have a cached entry for the hash,\n // Which means we've never seen this location before,\n // we need to check if there is a hash in the URL.\n // If there is, we need to scroll it's ID into view.\n const hash = (location ?? window.location).hash.split('#', 2)[1]\n\n if (hash) {\n const hashScrollIntoViewOptions =\n window.history.state?.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions) {\n const el = document.getElementById(hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n\n break scroll\n }\n\n // If there is no cached entry for the hash and there is no hash in the URL,\n // we need to scroll to the top of the page for every scrollToTop element\n const scrollOptions = { top: 0, left: 0, behavior }\n window.scrollTo(scrollOptions)\n if (scrollToTopSelectors) {\n for (const selector of scrollToTopSelectors) {\n if (selector === 'window') continue\n const element =\n typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n if (element) element.scrollTo(scrollOptions)\n }\n }\n }\n\n //\n ignoreScroll = false\n}\n\n/** Setup global listeners and hooks to support scroll restoration. */\n/** Setup global listeners and hooks to support scroll restoration. */\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n if (!scrollRestorationCache && !router.isServer) {\n return\n }\n const shouldScrollRestoration =\n force ?? router.options.scrollRestoration ?? false\n\n if (shouldScrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if (\n router.isServer ||\n router.isScrollRestorationSetup ||\n !scrollRestorationCache\n ) {\n return\n }\n\n router.isScrollRestorationSetup = true\n\n //\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n\n window.history.scrollRestoration = 'manual'\n\n // // Create a MutationObserver to monitor DOM changes\n // const mutationObserver = new MutationObserver(() => {\n // ;ignoreScroll = true\n // requestAnimationFrame(() => {\n // ;ignoreScroll = false\n\n // // Attempt to restore scroll position on each dom\n // // mutation until the user scrolls. We do this\n // // because dynamic content may come in at different\n // // ticks after the initial render and we want to\n // // keep up with that content as much as possible.\n // // As soon as the user scrolls, we no longer need\n // // to attempt router.\n // // console.log('mutation observer restoreScroll')\n // restoreScroll(\n // storageKey,\n // getKey(router.state.location),\n // router.options.scrollRestorationBehavior,\n // )\n // })\n // })\n\n // const observeDom = () => {\n // // Observe changes to the entire document\n // mutationObserver.observe(document, {\n // childList: true, // Detect added or removed child nodes\n // subtree: true, // Monitor all descendants\n // characterData: true, // Detect text content changes\n // })\n // }\n\n // const unobserveDom = () => {\n // mutationObserver.disconnect()\n // }\n\n // observeDom()\n\n const onScroll = (event: Event) => {\n // unobserveDom()\n\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n let elementSelector = ''\n\n if (event.target === document || event.target === window) {\n elementSelector = 'window'\n } else {\n const attrId = (event.target as Element).getAttribute(\n 'data-scroll-restoration-id',\n )\n\n if (attrId) {\n elementSelector = `[data-scroll-restoration-id=\"${attrId}\"]`\n } else {\n elementSelector = getCssSelector(event.target)\n }\n }\n\n const restoreKey = getKey(router.state.location)\n\n scrollRestorationCache.set((state) => {\n const keyEntry = (state[restoreKey] ||= {} as ScrollRestorationByElement)\n\n const elementEntry = (keyEntry[elementSelector] ||=\n {} as ScrollRestorationEntry)\n\n if (elementSelector === 'window') {\n elementEntry.scrollX = window.scrollX || 0\n elementEntry.scrollY = window.scrollY || 0\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n elementEntry.scrollX = element.scrollLeft || 0\n elementEntry.scrollY = element.scrollTop || 0\n }\n }\n\n return state\n })\n }\n\n // Throttle the scroll event to avoid excessive updates\n if (typeof document !== 'undefined') {\n document.addEventListener('scroll', throttle(onScroll, 100), true)\n }\n\n router.subscribe('onRendered', (event) => {\n // unobserveDom()\n\n const cacheKey = getKey(event.toLocation)\n\n // If the user doesn't want to restore the scroll position,\n // we don't need to do anything.\n if (!router.resetNextScroll) {\n router.resetNextScroll = true\n return\n }\n if (typeof router.options.scrollRestoration === 'function') {\n const shouldRestore = router.options.scrollRestoration({\n location: router.latestLocation,\n })\n if (!shouldRestore) {\n return\n }\n }\n\n restoreScroll({\n storageKey,\n key: cacheKey,\n behavior: router.options.scrollRestorationBehavior,\n shouldScrollRestoration: router.isScrollRestoring,\n scrollToTopSelectors: router.options.scrollToTopSelectors,\n location: router.history.location,\n })\n\n if (router.isScrollRestoring) {\n // Mark the location as having been seen\n scrollRestorationCache.set((state) => {\n state[cacheKey] ||= {} as ScrollRestorationByElement\n\n return state\n })\n }\n })\n}\n\n/**\n * @private\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific <Transitioner> components during the onResolved event.\n *\n * Provides hash scrolling for programmatic navigation when default browser handling is prevented.\n * @param router The router instance containing current location and state\n */\n/**\n * @private\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific Transitioners.\n */\nexport function handleHashScroll(router: AnyRouter) {\n if (typeof document !== 'undefined' && (document as any).querySelector) {\n const hashScrollIntoViewOptions =\n router.state.location.state.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions && router.state.location.hash !== '') {\n const el = document.getElementById(router.state.location.hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n }\n}\n"],"names":["functionalUpdate","storageKey"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scroll-restoration.cjs","sources":["../../src/scroll-restoration.ts"],"sourcesContent":["import { functionalUpdate } from './utils'\nimport type { AnyRouter } from './router'\nimport type { ParsedLocation } from './location'\nimport type { NonNullableUpdater } from './utils'\nimport type { HistoryLocation } from '@tanstack/history'\n\nexport type ScrollRestorationEntry = { scrollX: number; scrollY: number }\n\nexport type ScrollRestorationByElement = Record<string, ScrollRestorationEntry>\n\nexport type ScrollRestorationByKey = Record<string, ScrollRestorationByElement>\n\nexport type ScrollRestorationCache = {\n state: ScrollRestorationByKey\n set: (updater: NonNullableUpdater<ScrollRestorationByKey>) => void\n}\nexport type ScrollRestorationOptions = {\n getKey?: (location: ParsedLocation) => string\n scrollBehavior?: ScrollToOptions['behavior']\n}\n\nfunction getSafeSessionStorage() {\n try {\n if (\n typeof window !== 'undefined' &&\n typeof window.sessionStorage === 'object'\n ) {\n return window.sessionStorage\n }\n } catch {\n // silent\n }\n return undefined\n}\n\n/** SessionStorage key used to persist scroll restoration state. */\n/** SessionStorage key used to store scroll positions across navigations. */\n/** SessionStorage key used to store scroll positions across navigations. */\nexport const storageKey = 'tsr-scroll-restoration-v1_3'\n\nconst throttle = (fn: (...args: Array<any>) => void, wait: number) => {\n let timeout: any\n return (...args: Array<any>) => {\n if (!timeout) {\n timeout = setTimeout(() => {\n fn(...args)\n timeout = null\n }, wait)\n }\n }\n}\n\nfunction createScrollRestorationCache(): ScrollRestorationCache | null {\n const safeSessionStorage = getSafeSessionStorage()\n if (!safeSessionStorage) {\n return null\n }\n\n const persistedState = safeSessionStorage.getItem(storageKey)\n let state: ScrollRestorationByKey = persistedState\n ? JSON.parse(persistedState)\n : {}\n\n return {\n state,\n // This setter is simply to make sure that we set the sessionStorage right\n // after the state is updated. It doesn't necessarily need to be a functional\n // update.\n set: (updater) => {\n state = functionalUpdate(updater, state) || state\n try {\n safeSessionStorage.setItem(storageKey, JSON.stringify(state))\n } catch {\n console.warn(\n '[ts-router] Could not persist scroll restoration state to sessionStorage.',\n )\n }\n },\n }\n}\n\n/** In-memory handle to the persisted scroll restoration cache. */\nexport const scrollRestorationCache = createScrollRestorationCache()\n\n/**\n * The default `getKey` function for `useScrollRestoration`.\n * It returns the `key` from the location state or the `href` of the location.\n *\n * The `location.href` is used as a fallback to support the use case where the location state is not available like the initial render.\n */\n\n/**\n * Default scroll restoration cache key: location state key or full href.\n */\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\n/** Best-effort nth-child CSS selector for a given element. */\nexport function getCssSelector(el: any): string {\n const path = []\n let parent: HTMLElement\n while ((parent = el.parentNode)) {\n path.push(\n `${el.tagName}:nth-child(${Array.prototype.indexOf.call(parent.children, el) + 1})`,\n )\n el = parent\n }\n return `${path.reverse().join(' > ')}`.toLowerCase()\n}\n\nlet ignoreScroll = false\n\n// NOTE: This function must remain pure and not use any outside variables\n// unless they are passed in as arguments. Why? Because we need to be able to\n// toString() it into a script tag to execute as early as possible in the browser\n// during SSR. Additionally, we also call it from within the router lifecycle\nexport function restoreScroll({\n storageKey,\n key,\n behavior,\n shouldScrollRestoration,\n scrollToTopSelectors,\n location,\n}: {\n storageKey: string\n key?: string\n behavior?: ScrollToOptions['behavior']\n shouldScrollRestoration?: boolean\n scrollToTopSelectors?: Array<string | (() => Element | null | undefined)>\n location?: HistoryLocation\n}) {\n let byKey: ScrollRestorationByKey\n\n try {\n byKey = JSON.parse(sessionStorage.getItem(storageKey) || '{}')\n } catch (error) {\n console.error(error)\n return\n }\n\n const resolvedKey = key || window.history.state?.__TSR_key\n const elementEntries = byKey[resolvedKey]\n\n //\n ignoreScroll = true\n\n //\n scroll: {\n // If we have a cached entry for this location state,\n // we always need to prefer that over the hash scroll.\n if (\n shouldScrollRestoration &&\n elementEntries &&\n Object.keys(elementEntries).length > 0\n ) {\n for (const elementSelector in elementEntries) {\n const entry = elementEntries[elementSelector]!\n if (elementSelector === 'window') {\n window.scrollTo({\n top: entry.scrollY,\n left: entry.scrollX,\n behavior,\n })\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n element.scrollLeft = entry.scrollX\n element.scrollTop = entry.scrollY\n }\n }\n }\n\n break scroll\n }\n\n // If we don't have a cached entry for the hash,\n // Which means we've never seen this location before,\n // we need to check if there is a hash in the URL.\n // If there is, we need to scroll it's ID into view.\n const hash = (location ?? window.location).hash.split('#', 2)[1]\n\n if (hash) {\n const hashScrollIntoViewOptions =\n window.history.state?.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions) {\n const el = document.getElementById(hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n\n break scroll\n }\n\n // If there is no cached entry for the hash and there is no hash in the URL,\n // we need to scroll to the top of the page for every scrollToTop element\n const scrollOptions = { top: 0, left: 0, behavior }\n window.scrollTo(scrollOptions)\n if (scrollToTopSelectors) {\n for (const selector of scrollToTopSelectors) {\n if (selector === 'window') continue\n const element =\n typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n if (element) element.scrollTo(scrollOptions)\n }\n }\n }\n\n //\n ignoreScroll = false\n}\n\n/** Setup global listeners and hooks to support scroll restoration. */\n/** Setup global listeners and hooks to support scroll restoration. */\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n if (!scrollRestorationCache && !router.isServer) {\n return\n }\n const shouldScrollRestoration =\n force ?? router.options.scrollRestoration ?? false\n\n if (shouldScrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if (\n router.isServer ||\n router.isScrollRestorationSetup ||\n !scrollRestorationCache\n ) {\n return\n }\n\n router.isScrollRestorationSetup = true\n\n //\n ignoreScroll = false\n\n const getKey =\n router.options.getScrollRestorationKey || defaultGetScrollRestorationKey\n\n window.history.scrollRestoration = 'manual'\n\n // // Create a MutationObserver to monitor DOM changes\n // const mutationObserver = new MutationObserver(() => {\n // ;ignoreScroll = true\n // requestAnimationFrame(() => {\n // ;ignoreScroll = false\n\n // // Attempt to restore scroll position on each dom\n // // mutation until the user scrolls. We do this\n // // because dynamic content may come in at different\n // // ticks after the initial render and we want to\n // // keep up with that content as much as possible.\n // // As soon as the user scrolls, we no longer need\n // // to attempt router.\n // // console.log('mutation observer restoreScroll')\n // restoreScroll(\n // storageKey,\n // getKey(router.state.location),\n // router.options.scrollRestorationBehavior,\n // )\n // })\n // })\n\n // const observeDom = () => {\n // // Observe changes to the entire document\n // mutationObserver.observe(document, {\n // childList: true, // Detect added or removed child nodes\n // subtree: true, // Monitor all descendants\n // characterData: true, // Detect text content changes\n // })\n // }\n\n // const unobserveDom = () => {\n // mutationObserver.disconnect()\n // }\n\n // observeDom()\n\n const onScroll = (event: Event) => {\n // unobserveDom()\n\n if (ignoreScroll || !router.isScrollRestoring) {\n return\n }\n\n let elementSelector = ''\n\n if (event.target === document || event.target === window) {\n elementSelector = 'window'\n } else {\n const attrId = (event.target as Element).getAttribute(\n 'data-scroll-restoration-id',\n )\n\n if (attrId) {\n elementSelector = `[data-scroll-restoration-id=\"${attrId}\"]`\n } else {\n elementSelector = getCssSelector(event.target)\n }\n }\n\n const restoreKey = getKey(router.state.location)\n\n scrollRestorationCache.set((state) => {\n const keyEntry = (state[restoreKey] ||= {} as ScrollRestorationByElement)\n\n const elementEntry = (keyEntry[elementSelector] ||=\n {} as ScrollRestorationEntry)\n\n if (elementSelector === 'window') {\n elementEntry.scrollX = window.scrollX || 0\n elementEntry.scrollY = window.scrollY || 0\n } else if (elementSelector) {\n const element = document.querySelector(elementSelector)\n if (element) {\n elementEntry.scrollX = element.scrollLeft || 0\n elementEntry.scrollY = element.scrollTop || 0\n }\n }\n\n return state\n })\n }\n\n // Throttle the scroll event to avoid excessive updates\n if (typeof document !== 'undefined') {\n document.addEventListener('scroll', throttle(onScroll, 100), true)\n }\n\n router.subscribe('onRendered', (event) => {\n // unobserveDom()\n\n const cacheKey = getKey(event.toLocation)\n\n // If the user doesn't want to restore the scroll position,\n // we don't need to do anything.\n if (!router.resetNextScroll) {\n router.resetNextScroll = true\n return\n }\n if (typeof router.options.scrollRestoration === 'function') {\n const shouldRestore = router.options.scrollRestoration({\n location: router.latestLocation,\n })\n if (!shouldRestore) {\n return\n }\n }\n\n restoreScroll({\n storageKey,\n key: cacheKey,\n behavior: router.options.scrollRestorationBehavior,\n shouldScrollRestoration: router.isScrollRestoring,\n scrollToTopSelectors: router.options.scrollToTopSelectors,\n location: router.history.location,\n })\n\n if (router.isScrollRestoring) {\n // Mark the location as having been seen\n scrollRestorationCache.set((state) => {\n state[cacheKey] ||= {} as ScrollRestorationByElement\n\n return state\n })\n }\n })\n}\n\n/**\n * @private\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific <Transitioner> components during the onResolved event.\n *\n * Provides hash scrolling for programmatic navigation when default browser handling is prevented.\n * @param router The router instance containing current location and state\n */\n/**\n * @private\n * Handles hash-based scrolling after navigation completes.\n * To be used in framework-specific Transitioners.\n */\nexport function handleHashScroll(router: AnyRouter) {\n if (typeof document !== 'undefined' && (document as any).querySelector) {\n const hashScrollIntoViewOptions =\n router.state.location.state.__hashScrollIntoViewOptions ?? true\n\n if (hashScrollIntoViewOptions && router.state.location.hash !== '') {\n const el = document.getElementById(router.state.location.hash)\n if (el) {\n el.scrollIntoView(hashScrollIntoViewOptions)\n }\n }\n }\n}\n"],"names":["functionalUpdate","storageKey"],"mappings":"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"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const seroval = require("seroval");
|
|
4
|
+
class RawStream {
|
|
5
|
+
constructor(stream, options) {
|
|
6
|
+
this.stream = stream;
|
|
7
|
+
this.hint = options?.hint ?? "binary";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const BufferCtor = globalThis.Buffer;
|
|
11
|
+
const hasNodeBuffer = !!BufferCtor && typeof BufferCtor.from === "function";
|
|
12
|
+
function uint8ArrayToBase64(bytes) {
|
|
13
|
+
if (bytes.length === 0) return "";
|
|
14
|
+
if (hasNodeBuffer) {
|
|
15
|
+
return BufferCtor.from(bytes).toString("base64");
|
|
16
|
+
}
|
|
17
|
+
const CHUNK_SIZE = 32768;
|
|
18
|
+
const chunks = [];
|
|
19
|
+
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
|
20
|
+
const chunk = bytes.subarray(i, i + CHUNK_SIZE);
|
|
21
|
+
chunks.push(String.fromCharCode.apply(null, chunk));
|
|
22
|
+
}
|
|
23
|
+
return btoa(chunks.join(""));
|
|
24
|
+
}
|
|
25
|
+
function base64ToUint8Array(base64) {
|
|
26
|
+
if (base64.length === 0) return new Uint8Array(0);
|
|
27
|
+
if (hasNodeBuffer) {
|
|
28
|
+
const buf = BufferCtor.from(base64, "base64");
|
|
29
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
30
|
+
}
|
|
31
|
+
const binary = atob(base64);
|
|
32
|
+
const bytes = new Uint8Array(binary.length);
|
|
33
|
+
for (let i = 0; i < binary.length; i++) {
|
|
34
|
+
bytes[i] = binary.charCodeAt(i);
|
|
35
|
+
}
|
|
36
|
+
return bytes;
|
|
37
|
+
}
|
|
38
|
+
const RAW_STREAM_FACTORY_BINARY = /* @__PURE__ */ Object.create(null);
|
|
39
|
+
const RAW_STREAM_FACTORY_TEXT = /* @__PURE__ */ Object.create(null);
|
|
40
|
+
const RAW_STREAM_FACTORY_CONSTRUCTOR_BINARY = (stream) => new ReadableStream({
|
|
41
|
+
start(controller) {
|
|
42
|
+
stream.on({
|
|
43
|
+
next(base64) {
|
|
44
|
+
try {
|
|
45
|
+
controller.enqueue(base64ToUint8Array(base64));
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
throw(error) {
|
|
50
|
+
controller.error(error);
|
|
51
|
+
},
|
|
52
|
+
return() {
|
|
53
|
+
try {
|
|
54
|
+
controller.close();
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
const textEncoderForFactory = new TextEncoder();
|
|
62
|
+
const RAW_STREAM_FACTORY_CONSTRUCTOR_TEXT = (stream) => {
|
|
63
|
+
return new ReadableStream({
|
|
64
|
+
start(controller) {
|
|
65
|
+
stream.on({
|
|
66
|
+
next(value) {
|
|
67
|
+
try {
|
|
68
|
+
if (typeof value === "string") {
|
|
69
|
+
controller.enqueue(textEncoderForFactory.encode(value));
|
|
70
|
+
} else {
|
|
71
|
+
controller.enqueue(base64ToUint8Array(value.$b64));
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
throw(error) {
|
|
77
|
+
controller.error(error);
|
|
78
|
+
},
|
|
79
|
+
return() {
|
|
80
|
+
try {
|
|
81
|
+
controller.close();
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
const FACTORY_BINARY = `(s=>new ReadableStream({start(c){s.on({next(b){try{const d=atob(b),a=new Uint8Array(d.length);for(let i=0;i<d.length;i++)a[i]=d.charCodeAt(i);c.enqueue(a)}catch(_){}},throw(e){c.error(e)},return(){try{c.close()}catch(_){}}})}}))`;
|
|
90
|
+
const FACTORY_TEXT = `(s=>{const e=new TextEncoder();return new ReadableStream({start(c){s.on({next(v){try{if(typeof v==='string'){c.enqueue(e.encode(v))}else{const d=atob(v.$b64),a=new Uint8Array(d.length);for(let i=0;i<d.length;i++)a[i]=d.charCodeAt(i);c.enqueue(a)}}catch(_){}},throw(x){c.error(x)},return(){try{c.close()}catch(_){}}})}})})`;
|
|
91
|
+
function toBinaryStream(readable) {
|
|
92
|
+
const stream = seroval.createStream();
|
|
93
|
+
const reader = readable.getReader();
|
|
94
|
+
(async () => {
|
|
95
|
+
try {
|
|
96
|
+
while (true) {
|
|
97
|
+
const { done, value } = await reader.read();
|
|
98
|
+
if (done) {
|
|
99
|
+
stream.return(void 0);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
stream.next(uint8ArrayToBase64(value));
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
stream.throw(error);
|
|
106
|
+
} finally {
|
|
107
|
+
reader.releaseLock();
|
|
108
|
+
}
|
|
109
|
+
})();
|
|
110
|
+
return stream;
|
|
111
|
+
}
|
|
112
|
+
function toTextStream(readable) {
|
|
113
|
+
const stream = seroval.createStream();
|
|
114
|
+
const reader = readable.getReader();
|
|
115
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
116
|
+
(async () => {
|
|
117
|
+
try {
|
|
118
|
+
while (true) {
|
|
119
|
+
const { done, value } = await reader.read();
|
|
120
|
+
if (done) {
|
|
121
|
+
try {
|
|
122
|
+
const remaining = decoder.decode();
|
|
123
|
+
if (remaining.length > 0) {
|
|
124
|
+
stream.next(remaining);
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
}
|
|
128
|
+
stream.return(void 0);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const text = decoder.decode(value, { stream: true });
|
|
133
|
+
if (text.length > 0) {
|
|
134
|
+
stream.next(text);
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
stream.next({ $b64: uint8ArrayToBase64(value) });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
} catch (error) {
|
|
141
|
+
stream.throw(error);
|
|
142
|
+
} finally {
|
|
143
|
+
reader.releaseLock();
|
|
144
|
+
}
|
|
145
|
+
})();
|
|
146
|
+
return stream;
|
|
147
|
+
}
|
|
148
|
+
const RawStreamFactoryBinaryPlugin = seroval.createPlugin({
|
|
149
|
+
tag: "tss/RawStreamFactory",
|
|
150
|
+
test(value) {
|
|
151
|
+
return value === RAW_STREAM_FACTORY_BINARY;
|
|
152
|
+
},
|
|
153
|
+
parse: {
|
|
154
|
+
sync() {
|
|
155
|
+
return void 0;
|
|
156
|
+
},
|
|
157
|
+
async() {
|
|
158
|
+
return Promise.resolve(void 0);
|
|
159
|
+
},
|
|
160
|
+
stream() {
|
|
161
|
+
return void 0;
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
serialize() {
|
|
165
|
+
return FACTORY_BINARY;
|
|
166
|
+
},
|
|
167
|
+
deserialize() {
|
|
168
|
+
return RAW_STREAM_FACTORY_BINARY;
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
const RawStreamFactoryTextPlugin = seroval.createPlugin({
|
|
172
|
+
tag: "tss/RawStreamFactoryText",
|
|
173
|
+
test(value) {
|
|
174
|
+
return value === RAW_STREAM_FACTORY_TEXT;
|
|
175
|
+
},
|
|
176
|
+
parse: {
|
|
177
|
+
sync() {
|
|
178
|
+
return void 0;
|
|
179
|
+
},
|
|
180
|
+
async() {
|
|
181
|
+
return Promise.resolve(void 0);
|
|
182
|
+
},
|
|
183
|
+
stream() {
|
|
184
|
+
return void 0;
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
serialize() {
|
|
188
|
+
return FACTORY_TEXT;
|
|
189
|
+
},
|
|
190
|
+
deserialize() {
|
|
191
|
+
return RAW_STREAM_FACTORY_TEXT;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
const RawStreamSSRPlugin = seroval.createPlugin({
|
|
195
|
+
tag: "tss/RawStream",
|
|
196
|
+
extends: [RawStreamFactoryBinaryPlugin, RawStreamFactoryTextPlugin],
|
|
197
|
+
test(value) {
|
|
198
|
+
return value instanceof RawStream;
|
|
199
|
+
},
|
|
200
|
+
parse: {
|
|
201
|
+
sync(value, ctx) {
|
|
202
|
+
const factory = value.hint === "text" ? RAW_STREAM_FACTORY_TEXT : RAW_STREAM_FACTORY_BINARY;
|
|
203
|
+
return {
|
|
204
|
+
hint: value.hint,
|
|
205
|
+
factory: ctx.parse(factory),
|
|
206
|
+
stream: ctx.parse(seroval.createStream())
|
|
207
|
+
};
|
|
208
|
+
},
|
|
209
|
+
async async(value, ctx) {
|
|
210
|
+
const factory = value.hint === "text" ? RAW_STREAM_FACTORY_TEXT : RAW_STREAM_FACTORY_BINARY;
|
|
211
|
+
const encodedStream = value.hint === "text" ? toTextStream(value.stream) : toBinaryStream(value.stream);
|
|
212
|
+
return {
|
|
213
|
+
hint: value.hint,
|
|
214
|
+
factory: await ctx.parse(factory),
|
|
215
|
+
stream: await ctx.parse(encodedStream)
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
stream(value, ctx) {
|
|
219
|
+
const factory = value.hint === "text" ? RAW_STREAM_FACTORY_TEXT : RAW_STREAM_FACTORY_BINARY;
|
|
220
|
+
const encodedStream = value.hint === "text" ? toTextStream(value.stream) : toBinaryStream(value.stream);
|
|
221
|
+
return {
|
|
222
|
+
hint: value.hint,
|
|
223
|
+
factory: ctx.parse(factory),
|
|
224
|
+
stream: ctx.parse(encodedStream)
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
serialize(node, ctx) {
|
|
229
|
+
return "(" + ctx.serialize(node.factory) + ")(" + ctx.serialize(node.stream) + ")";
|
|
230
|
+
},
|
|
231
|
+
deserialize(node, ctx) {
|
|
232
|
+
const stream = ctx.deserialize(node.stream);
|
|
233
|
+
return node.hint === "text" ? RAW_STREAM_FACTORY_CONSTRUCTOR_TEXT(stream) : RAW_STREAM_FACTORY_CONSTRUCTOR_BINARY(stream);
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
function createRawStreamRPCPlugin(onRawStream) {
|
|
237
|
+
let nextStreamId = 1;
|
|
238
|
+
return seroval.createPlugin({
|
|
239
|
+
tag: "tss/RawStream",
|
|
240
|
+
test(value) {
|
|
241
|
+
return value instanceof RawStream;
|
|
242
|
+
},
|
|
243
|
+
parse: {
|
|
244
|
+
async(value) {
|
|
245
|
+
const streamId = nextStreamId++;
|
|
246
|
+
onRawStream(streamId, value.stream);
|
|
247
|
+
return Promise.resolve({ streamId });
|
|
248
|
+
},
|
|
249
|
+
stream(value) {
|
|
250
|
+
const streamId = nextStreamId++;
|
|
251
|
+
onRawStream(streamId, value.stream);
|
|
252
|
+
return { streamId };
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
serialize() {
|
|
256
|
+
throw new Error(
|
|
257
|
+
"RawStreamRPCPlugin.serialize should not be called. RPC uses JSON serialization, not JS code generation."
|
|
258
|
+
);
|
|
259
|
+
},
|
|
260
|
+
deserialize() {
|
|
261
|
+
throw new Error(
|
|
262
|
+
"RawStreamRPCPlugin.deserialize should not be called. Use createRawStreamDeserializePlugin on client."
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
function createRawStreamDeserializePlugin(getOrCreateStream) {
|
|
268
|
+
return seroval.createPlugin({
|
|
269
|
+
tag: "tss/RawStream",
|
|
270
|
+
test: () => false,
|
|
271
|
+
// Client never serializes RawStream
|
|
272
|
+
parse: {},
|
|
273
|
+
// Client only deserializes, never parses
|
|
274
|
+
serialize() {
|
|
275
|
+
throw new Error(
|
|
276
|
+
"RawStreamDeserializePlugin.serialize should not be called. Client only deserializes."
|
|
277
|
+
);
|
|
278
|
+
},
|
|
279
|
+
deserialize(node) {
|
|
280
|
+
return getOrCreateStream(node.streamId);
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
exports.RawStream = RawStream;
|
|
285
|
+
exports.RawStreamSSRPlugin = RawStreamSSRPlugin;
|
|
286
|
+
exports.createRawStreamDeserializePlugin = createRawStreamDeserializePlugin;
|
|
287
|
+
exports.createRawStreamRPCPlugin = createRawStreamRPCPlugin;
|
|
288
|
+
//# sourceMappingURL=RawStream.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RawStream.cjs","sources":["../../../../src/ssr/serializer/RawStream.ts"],"sourcesContent":["import { createPlugin, createStream } from 'seroval'\nimport type { Plugin } from 'seroval'\n\n/**\n * Hint for RawStream encoding strategy during SSR serialization.\n * - 'binary': Always use base64 encoding (best for binary data like files, images)\n * - 'text': Try UTF-8 first, fallback to base64 (best for text-heavy data like RSC payloads)\n */\nexport type RawStreamHint = 'binary' | 'text'\n\n/**\n * Options for RawStream configuration.\n */\nexport interface RawStreamOptions {\n /**\n * Encoding hint for SSR serialization.\n * - 'binary' (default): Always use base64 encoding\n * - 'text': Try UTF-8 first, fallback to base64 for invalid UTF-8 chunks\n */\n hint?: RawStreamHint\n}\n\n/**\n * Marker class for ReadableStream<Uint8Array> that should be serialized\n * with base64 encoding (SSR) or binary framing (server functions).\n *\n * Wrap your binary streams with this to get efficient serialization:\n * ```ts\n * // For binary data (files, images, etc.)\n * return { data: new RawStream(file.stream()) }\n *\n * // For text-heavy data (RSC payloads, etc.)\n * return { data: new RawStream(rscStream, { hint: 'text' }) }\n * ```\n */\nexport class RawStream {\n public readonly hint: RawStreamHint\n\n constructor(\n public readonly stream: ReadableStream<Uint8Array>,\n options?: RawStreamOptions,\n ) {\n this.hint = options?.hint ?? 'binary'\n }\n}\n\n/**\n * Callback type for RPC plugin to register raw streams with multiplexer\n */\nexport type OnRawStreamCallback = (\n streamId: number,\n stream: ReadableStream<Uint8Array>,\n) => void\n\n// Base64 helpers used in both Node and browser.\n// In Node-like runtimes, prefer Buffer for speed and compatibility.\nconst BufferCtor: any = (globalThis as any).Buffer\nconst hasNodeBuffer = !!BufferCtor && typeof BufferCtor.from === 'function'\n\nfunction uint8ArrayToBase64(bytes: Uint8Array): string {\n if (bytes.length === 0) return ''\n\n if (hasNodeBuffer) {\n return BufferCtor.from(bytes).toString('base64')\n }\n\n // Browser fallback: chunked String.fromCharCode + btoa\n const CHUNK_SIZE = 0x8000 // 32KB chunks to avoid stack overflow\n const chunks: Array<string> = []\n for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {\n const chunk = bytes.subarray(i, i + CHUNK_SIZE)\n chunks.push(String.fromCharCode.apply(null, chunk as any))\n }\n return btoa(chunks.join(''))\n}\n\nfunction base64ToUint8Array(base64: string): Uint8Array {\n if (base64.length === 0) return new Uint8Array(0)\n\n if (hasNodeBuffer) {\n const buf = BufferCtor.from(base64, 'base64')\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)\n }\n\n const binary = atob(base64)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return bytes\n}\n\n// Factory sentinels - use null-proto objects to avoid prototype surprises\nconst RAW_STREAM_FACTORY_BINARY: Record<string, never> = Object.create(null)\nconst RAW_STREAM_FACTORY_TEXT: Record<string, never> = Object.create(null)\n\n// Factory constructor for binary mode - converts seroval stream to ReadableStream<Uint8Array>\n// All chunks are base64 encoded strings\nconst RAW_STREAM_FACTORY_CONSTRUCTOR_BINARY = (\n stream: ReturnType<typeof createStream>,\n) =>\n new ReadableStream<Uint8Array>({\n start(controller) {\n stream.on({\n next(base64: string) {\n try {\n controller.enqueue(base64ToUint8Array(base64))\n } catch {\n // Stream may be closed\n }\n },\n throw(error: unknown) {\n controller.error(error)\n },\n return() {\n try {\n controller.close()\n } catch {\n // Stream may already be closed\n }\n },\n })\n },\n })\n\n// Factory constructor for text mode - converts seroval stream to ReadableStream<Uint8Array>\n// Chunks are either strings (UTF-8) or { $b64: string } (base64 fallback)\n// Use module-level TextEncoder to avoid per-factory allocation\nconst textEncoderForFactory = new TextEncoder()\nconst RAW_STREAM_FACTORY_CONSTRUCTOR_TEXT = (\n stream: ReturnType<typeof createStream>,\n) => {\n return new ReadableStream<Uint8Array>({\n start(controller) {\n stream.on({\n next(value: string | { $b64: string }) {\n try {\n if (typeof value === 'string') {\n controller.enqueue(textEncoderForFactory.encode(value))\n } else {\n controller.enqueue(base64ToUint8Array(value.$b64))\n }\n } catch {\n // Stream may be closed\n }\n },\n throw(error: unknown) {\n controller.error(error)\n },\n return() {\n try {\n controller.close()\n } catch {\n // Stream may already be closed\n }\n },\n })\n },\n })\n}\n\n// Minified factory function for binary mode - all chunks are base64 strings\n// This must be self-contained since it's injected into the HTML\nconst FACTORY_BINARY = `(s=>new ReadableStream({start(c){s.on({next(b){try{const d=atob(b),a=new Uint8Array(d.length);for(let i=0;i<d.length;i++)a[i]=d.charCodeAt(i);c.enqueue(a)}catch(_){}},throw(e){c.error(e)},return(){try{c.close()}catch(_){}}})}}))`\n\n// Minified factory function for text mode - chunks are string or {$b64: string}\n// Uses cached TextEncoder for performance\nconst FACTORY_TEXT = `(s=>{const e=new TextEncoder();return new ReadableStream({start(c){s.on({next(v){try{if(typeof v==='string'){c.enqueue(e.encode(v))}else{const d=atob(v.$b64),a=new Uint8Array(d.length);for(let i=0;i<d.length;i++)a[i]=d.charCodeAt(i);c.enqueue(a)}}catch(_){}},throw(x){c.error(x)},return(){try{c.close()}catch(_){}}})}})})`\n\n// Convert ReadableStream<Uint8Array> to seroval stream with base64-encoded chunks (binary mode)\nfunction toBinaryStream(readable: ReadableStream<Uint8Array>) {\n const stream = createStream()\n const reader = readable.getReader()\n\n // Use iterative loop instead of recursive async to avoid stack accumulation\n ;(async () => {\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) {\n stream.return(undefined)\n break\n }\n stream.next(uint8ArrayToBase64(value))\n }\n } catch (error) {\n stream.throw(error)\n } finally {\n reader.releaseLock()\n }\n })()\n\n return stream\n}\n\n// Convert ReadableStream<Uint8Array> to seroval stream with UTF-8 first, base64 fallback (text mode)\nfunction toTextStream(readable: ReadableStream<Uint8Array>) {\n const stream = createStream()\n const reader = readable.getReader()\n const decoder = new TextDecoder('utf-8', { fatal: true })\n\n // Use iterative loop instead of recursive async to avoid stack accumulation\n ;(async () => {\n try {\n while (true) {\n const { done, value } = await reader.read()\n if (done) {\n // Flush any remaining bytes in the decoder\n try {\n const remaining = decoder.decode()\n if (remaining.length > 0) {\n stream.next(remaining)\n }\n } catch {\n // Ignore decode errors on flush\n }\n stream.return(undefined)\n break\n }\n\n try {\n // Try UTF-8 decode first\n const text = decoder.decode(value, { stream: true })\n if (text.length > 0) {\n stream.next(text)\n }\n } catch {\n // UTF-8 decode failed, fallback to base64\n stream.next({ $b64: uint8ArrayToBase64(value) })\n }\n }\n } catch (error) {\n stream.throw(error)\n } finally {\n reader.releaseLock()\n }\n })()\n\n return stream\n}\n\n// Factory plugin for binary mode\nconst RawStreamFactoryBinaryPlugin = createPlugin<\n Record<string, never>,\n undefined\n>({\n tag: 'tss/RawStreamFactory',\n test(value) {\n return value === RAW_STREAM_FACTORY_BINARY\n },\n parse: {\n sync() {\n return undefined\n },\n async() {\n return Promise.resolve(undefined)\n },\n stream() {\n return undefined\n },\n },\n serialize() {\n return FACTORY_BINARY\n },\n deserialize() {\n return RAW_STREAM_FACTORY_BINARY\n },\n})\n\n// Factory plugin for text mode\nconst RawStreamFactoryTextPlugin = createPlugin<\n Record<string, never>,\n undefined\n>({\n tag: 'tss/RawStreamFactoryText',\n test(value) {\n return value === RAW_STREAM_FACTORY_TEXT\n },\n parse: {\n sync() {\n return undefined\n },\n async() {\n return Promise.resolve(undefined)\n },\n stream() {\n return undefined\n },\n },\n serialize() {\n return FACTORY_TEXT\n },\n deserialize() {\n return RAW_STREAM_FACTORY_TEXT\n },\n})\n\n/**\n * SSR Plugin - uses base64 or UTF-8+base64 encoding for chunks, delegates to seroval's stream mechanism.\n * Used during SSR when serializing to JavaScript code for HTML injection.\n *\n * Supports two modes based on RawStream hint:\n * - 'binary': Always base64 encode (default)\n * - 'text': Try UTF-8 first, fallback to base64 for invalid UTF-8\n */\nexport const RawStreamSSRPlugin: Plugin<any, any> = createPlugin({\n tag: 'tss/RawStream',\n extends: [RawStreamFactoryBinaryPlugin, RawStreamFactoryTextPlugin],\n\n test(value: unknown) {\n return value instanceof RawStream\n },\n\n parse: {\n sync(value: RawStream, ctx) {\n // Sync parse not really supported for streams, return empty stream\n const factory =\n value.hint === 'text'\n ? RAW_STREAM_FACTORY_TEXT\n : RAW_STREAM_FACTORY_BINARY\n return {\n hint: value.hint,\n factory: ctx.parse(factory),\n stream: ctx.parse(createStream()),\n }\n },\n async async(value: RawStream, ctx) {\n const factory =\n value.hint === 'text'\n ? RAW_STREAM_FACTORY_TEXT\n : RAW_STREAM_FACTORY_BINARY\n const encodedStream =\n value.hint === 'text'\n ? toTextStream(value.stream)\n : toBinaryStream(value.stream)\n return {\n hint: value.hint,\n factory: await ctx.parse(factory),\n stream: await ctx.parse(encodedStream),\n }\n },\n stream(value: RawStream, ctx) {\n const factory =\n value.hint === 'text'\n ? RAW_STREAM_FACTORY_TEXT\n : RAW_STREAM_FACTORY_BINARY\n const encodedStream =\n value.hint === 'text'\n ? toTextStream(value.stream)\n : toBinaryStream(value.stream)\n return {\n hint: value.hint,\n factory: ctx.parse(factory),\n stream: ctx.parse(encodedStream),\n }\n },\n },\n\n serialize(node: { hint: RawStreamHint; factory: any; stream: any }, ctx) {\n return (\n '(' +\n ctx.serialize(node.factory) +\n ')(' +\n ctx.serialize(node.stream) +\n ')'\n )\n },\n\n deserialize(\n node: { hint: RawStreamHint; factory: any; stream: any },\n ctx,\n ): any {\n const stream: ReturnType<typeof createStream> = ctx.deserialize(node.stream)\n return node.hint === 'text'\n ? RAW_STREAM_FACTORY_CONSTRUCTOR_TEXT(stream)\n : RAW_STREAM_FACTORY_CONSTRUCTOR_BINARY(stream)\n },\n}) as Plugin<any, any>\n\n/**\n * Node type for RPC plugin serialization\n */\ninterface RawStreamRPCNode {\n streamId: number\n}\n\n/**\n * Creates an RPC plugin instance that registers raw streams with a multiplexer.\n * Used for server function responses where we want binary framing.\n * Note: RPC always uses binary framing regardless of hint.\n *\n * @param onRawStream Callback invoked when a RawStream is encountered during serialization\n */\nexport function createRawStreamRPCPlugin(\n onRawStream: OnRawStreamCallback,\n): Plugin<any, any> {\n // Own stream counter - sequential IDs starting at 1, independent of seroval internals\n let nextStreamId = 1\n\n return createPlugin({\n tag: 'tss/RawStream',\n\n test(value: unknown) {\n return value instanceof RawStream\n },\n\n parse: {\n async(value: RawStream) {\n const streamId = nextStreamId++\n onRawStream(streamId, value.stream)\n return Promise.resolve({ streamId })\n },\n stream(value: RawStream) {\n const streamId = nextStreamId++\n onRawStream(streamId, value.stream)\n return { streamId }\n },\n },\n\n serialize(): never {\n // RPC uses toCrossJSONStream which produces JSON nodes, not JS code.\n // This method is only called by crossSerialize* which we don't use.\n throw new Error(\n 'RawStreamRPCPlugin.serialize should not be called. RPC uses JSON serialization, not JS code generation.',\n )\n },\n\n deserialize(): never {\n // Client uses createRawStreamDeserializePlugin instead\n throw new Error(\n 'RawStreamRPCPlugin.deserialize should not be called. Use createRawStreamDeserializePlugin on client.',\n )\n },\n }) as Plugin<any, any>\n}\n\n/**\n * Creates a deserialize-only plugin for client-side stream reconstruction.\n * Used in serverFnFetcher to wire up streams from frame decoder.\n *\n * @param getOrCreateStream Function to get/create a stream by ID from frame decoder\n */\nexport function createRawStreamDeserializePlugin(\n getOrCreateStream: (id: number) => ReadableStream<Uint8Array>,\n): Plugin<any, any> {\n return createPlugin({\n tag: 'tss/RawStream',\n\n test: () => false, // Client never serializes RawStream\n\n parse: {}, // Client only deserializes, never parses\n\n serialize(): never {\n // Client never serializes RawStream back to server\n throw new Error(\n 'RawStreamDeserializePlugin.serialize should not be called. Client only deserializes.',\n )\n },\n\n deserialize(node: RawStreamRPCNode) {\n return getOrCreateStream(node.streamId)\n },\n }) as Plugin<any, any>\n}\n"],"names":["createStream","createPlugin"],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Plugin } from 'seroval';
|
|
2
|
+
/**
|
|
3
|
+
* Hint for RawStream encoding strategy during SSR serialization.
|
|
4
|
+
* - 'binary': Always use base64 encoding (best for binary data like files, images)
|
|
5
|
+
* - 'text': Try UTF-8 first, fallback to base64 (best for text-heavy data like RSC payloads)
|
|
6
|
+
*/
|
|
7
|
+
export type RawStreamHint = 'binary' | 'text';
|
|
8
|
+
/**
|
|
9
|
+
* Options for RawStream configuration.
|
|
10
|
+
*/
|
|
11
|
+
export interface RawStreamOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Encoding hint for SSR serialization.
|
|
14
|
+
* - 'binary' (default): Always use base64 encoding
|
|
15
|
+
* - 'text': Try UTF-8 first, fallback to base64 for invalid UTF-8 chunks
|
|
16
|
+
*/
|
|
17
|
+
hint?: RawStreamHint;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Marker class for ReadableStream<Uint8Array> that should be serialized
|
|
21
|
+
* with base64 encoding (SSR) or binary framing (server functions).
|
|
22
|
+
*
|
|
23
|
+
* Wrap your binary streams with this to get efficient serialization:
|
|
24
|
+
* ```ts
|
|
25
|
+
* // For binary data (files, images, etc.)
|
|
26
|
+
* return { data: new RawStream(file.stream()) }
|
|
27
|
+
*
|
|
28
|
+
* // For text-heavy data (RSC payloads, etc.)
|
|
29
|
+
* return { data: new RawStream(rscStream, { hint: 'text' }) }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare class RawStream {
|
|
33
|
+
readonly stream: ReadableStream<Uint8Array>;
|
|
34
|
+
readonly hint: RawStreamHint;
|
|
35
|
+
constructor(stream: ReadableStream<Uint8Array>, options?: RawStreamOptions);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Callback type for RPC plugin to register raw streams with multiplexer
|
|
39
|
+
*/
|
|
40
|
+
export type OnRawStreamCallback = (streamId: number, stream: ReadableStream<Uint8Array>) => void;
|
|
41
|
+
/**
|
|
42
|
+
* SSR Plugin - uses base64 or UTF-8+base64 encoding for chunks, delegates to seroval's stream mechanism.
|
|
43
|
+
* Used during SSR when serializing to JavaScript code for HTML injection.
|
|
44
|
+
*
|
|
45
|
+
* Supports two modes based on RawStream hint:
|
|
46
|
+
* - 'binary': Always base64 encode (default)
|
|
47
|
+
* - 'text': Try UTF-8 first, fallback to base64 for invalid UTF-8
|
|
48
|
+
*/
|
|
49
|
+
export declare const RawStreamSSRPlugin: Plugin<any, any>;
|
|
50
|
+
/**
|
|
51
|
+
* Creates an RPC plugin instance that registers raw streams with a multiplexer.
|
|
52
|
+
* Used for server function responses where we want binary framing.
|
|
53
|
+
* Note: RPC always uses binary framing regardless of hint.
|
|
54
|
+
*
|
|
55
|
+
* @param onRawStream Callback invoked when a RawStream is encountered during serialization
|
|
56
|
+
*/
|
|
57
|
+
export declare function createRawStreamRPCPlugin(onRawStream: OnRawStreamCallback): Plugin<any, any>;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a deserialize-only plugin for client-side stream reconstruction.
|
|
60
|
+
* Used in serverFnFetcher to wire up streams from frame decoder.
|
|
61
|
+
*
|
|
62
|
+
* @param getOrCreateStream Function to get/create a stream by ID from frame decoder
|
|
63
|
+
*/
|
|
64
|
+
export declare function createRawStreamDeserializePlugin(getOrCreateStream: (id: number) => ReadableStream<Uint8Array>): Plugin<any, any>;
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const web = require("seroval-plugins/web");
|
|
4
4
|
const ShallowErrorPlugin = require("./ShallowErrorPlugin.cjs");
|
|
5
|
+
const RawStream = require("./RawStream.cjs");
|
|
5
6
|
const defaultSerovalPlugins = [
|
|
6
7
|
ShallowErrorPlugin.ShallowErrorPlugin,
|
|
8
|
+
// RawStreamSSRPlugin must come before ReadableStreamPlugin to match first
|
|
9
|
+
RawStream.RawStreamSSRPlugin,
|
|
7
10
|
// ReadableStreamNode is not exported by seroval
|
|
8
11
|
web.ReadableStreamPlugin
|
|
9
12
|
];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seroval-plugins.cjs","sources":["../../../../src/ssr/serializer/seroval-plugins.ts"],"sourcesContent":["import { ReadableStreamPlugin } from 'seroval-plugins/web'\nimport { ShallowErrorPlugin } from './ShallowErrorPlugin'\nimport type { Plugin } from 'seroval'\n\nexport const defaultSerovalPlugins = [\n ShallowErrorPlugin as Plugin<Error, any>,\n // ReadableStreamNode is not exported by seroval\n ReadableStreamPlugin as Plugin<ReadableStream, any>,\n]\n"],"names":["ShallowErrorPlugin","ReadableStreamPlugin"],"mappings":"
|
|
1
|
+
{"version":3,"file":"seroval-plugins.cjs","sources":["../../../../src/ssr/serializer/seroval-plugins.ts"],"sourcesContent":["import { ReadableStreamPlugin } from 'seroval-plugins/web'\nimport { ShallowErrorPlugin } from './ShallowErrorPlugin'\nimport { RawStreamSSRPlugin } from './RawStream'\nimport type { Plugin } from 'seroval'\n\nexport const defaultSerovalPlugins = [\n ShallowErrorPlugin as Plugin<Error, any>,\n // RawStreamSSRPlugin must come before ReadableStreamPlugin to match first\n RawStreamSSRPlugin,\n // ReadableStreamNode is not exported by seroval\n ReadableStreamPlugin as Plugin<ReadableStream, any>,\n]\n"],"names":["ShallowErrorPlugin","RawStreamSSRPlugin","ReadableStreamPlugin"],"mappings":";;;;;AAKO,MAAM,wBAAwB;AAAA,EACnCA,mBAAAA;AAAAA;AAAAA,EAEAC,UAAAA;AAAAA;AAAAA,EAEAC,IAAAA;AACF;;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Plugin } from 'seroval';
|
|
2
|
-
export declare const defaultSerovalPlugins: (Plugin<Error, any> | Plugin<ReadableStream<any>, any>)[];
|
|
2
|
+
export declare const defaultSerovalPlugins: (Plugin<any, any> | Plugin<Error, any> | Plugin<ReadableStream<any>, any>)[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.cjs","sources":["../../../../src/ssr/serializer/transformer.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport { GLOBAL_TSR } from '../constants'\nimport type { Plugin, SerovalNode } from 'seroval'\nimport type {\n RegisteredConfigType,\n RegisteredSsr,\n SSROption,\n} from '../../router'\nimport type { LooseReturnType } from '../../utils'\nimport type { AnyRoute, ResolveAllSSR } from '../../route'\n\ndeclare const TSR_SERIALIZABLE: unique symbol\nexport type TSR_SERIALIZABLE = typeof TSR_SERIALIZABLE\n\nexport type TsrSerializable = { [TSR_SERIALIZABLE]: true }\nexport interface DefaultSerializable {\n number: number\n string: string\n boolean: boolean\n null: null\n undefined: undefined\n bigint: bigint\n Date: Date\n TsrSerializable: TsrSerializable\n}\n\nexport interface SerializableExtensions extends DefaultSerializable {}\n\nexport type Serializable = SerializableExtensions[keyof SerializableExtensions]\n\nexport type UnionizeSerializationAdaptersInput<\n TAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> = TAdapters[number]['~types']['input']\n\n/**\n * Create a strongly-typed serialization adapter for SSR hydration.\n * Use to register custom types with the router serializer.\n */\nexport function createSerializationAdapter<\n TInput = unknown,\n TOutput = unknown,\n const TExtendsAdapters extends\n | ReadonlyArray<AnySerializationAdapter>\n | never = never,\n>(\n opts: CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters>,\n): SerializationAdapter<TInput, TOutput, TExtendsAdapters> {\n return opts as unknown as SerializationAdapter<\n TInput,\n TOutput,\n TExtendsAdapters\n >\n}\n\nexport interface CreateSerializationAdapterOptions<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never,\n> {\n key: string\n extends?: TExtendsAdapters\n test: (value: unknown) => value is TInput\n toSerializable: (\n value: TInput,\n ) => ValidateSerializable<\n TOutput,\n Serializable | UnionizeSerializationAdaptersInput<TExtendsAdapters>\n >\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport type ValidateSerializable<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'input'>\n : T extends TSerializable\n ? T\n : T extends (...args: Array<any>) => any\n ? 'Function is not serializable'\n : T extends Promise<any>\n ? ValidateSerializablePromise<T, TSerializable>\n : T extends ReadableStream<any>\n ? ValidateReadableStream<T, TSerializable>\n : T extends Set<any>\n ? ValidateSerializableSet<T, TSerializable>\n : T extends Map<any, any>\n ? ValidateSerializableMap<T, TSerializable>\n : T extends AsyncGenerator<any, any>\n ? ValidateSerializableAsyncGenerator<T, TSerializable>\n : {\n [K in keyof T]: ValidateSerializable<T[K], TSerializable>\n }\n\nexport type ValidateSerializableAsyncGenerator<T, TSerializable> =\n T extends AsyncGenerator<infer T, infer TReturn, infer TNext>\n ? AsyncGenerator<\n ValidateSerializable<T, TSerializable>,\n ValidateSerializable<TReturn, TSerializable>,\n TNext\n >\n : never\n\nexport type ValidateSerializablePromise<T, TSerializable> =\n T extends Promise<infer TAwaited>\n ? Promise<ValidateSerializable<TAwaited, TSerializable>>\n : never\n\nexport type ValidateReadableStream<T, TSerializable> =\n T extends ReadableStream<infer TStreamed>\n ? ReadableStream<ValidateSerializable<TStreamed, TSerializable>>\n : never\n\nexport type ValidateSerializableSet<T, TSerializable> =\n T extends Set<infer TItem>\n ? Set<ValidateSerializable<TItem, TSerializable>>\n : never\n\nexport type ValidateSerializableMap<T, TSerializable> =\n T extends Map<infer TKey, infer TValue>\n ? Map<\n ValidateSerializable<TKey, TSerializable>,\n ValidateSerializable<TValue, TSerializable>\n >\n : never\n\nexport type RegisteredReadableStream =\n unknown extends SerializerExtensions['ReadableStream']\n ? never\n : SerializerExtensions['ReadableStream']\n\nexport interface DefaultSerializerExtensions {\n ReadableStream: unknown\n}\n\nexport interface SerializerExtensions extends DefaultSerializerExtensions {}\n\nexport interface SerializationAdapter<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> {\n '~types': SerializationAdapterTypes<TInput, TOutput, TExtendsAdapters>\n key: string\n extends?: TExtendsAdapters\n test: (value: unknown) => value is TInput\n toSerializable: (value: TInput) => TOutput\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport interface SerializationAdapterTypes<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> {\n input: TInput | UnionizeSerializationAdaptersInput<TExtendsAdapters>\n output: TOutput\n extends: TExtendsAdapters\n}\n\nexport type AnySerializationAdapter = SerializationAdapter<any, any, any>\n\n/** Create a Seroval plugin for server-side serialization only. */\nexport function makeSsrSerovalPlugin(\n serializationAdapter: AnySerializationAdapter,\n options: { didRun: boolean },\n): Plugin<any, SerovalNode> {\n return createPlugin<any, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n test: serializationAdapter.test,\n parse: {\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n serialize(node, ctx) {\n options.didRun = true\n return (\n GLOBAL_TSR +\n '.t.get(\"' +\n serializationAdapter.key +\n '\")(' +\n ctx.serialize(node) +\n ')'\n )\n },\n // we never deserialize on the server during SSR\n deserialize: undefined as never,\n })\n}\n\n/** Create a Seroval plugin for client/server symmetric (de)serialization. */\nexport function makeSerovalPlugin(\n serializationAdapter: AnySerializationAdapter,\n): Plugin<any, SerovalNode> {\n return createPlugin<any, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n test: serializationAdapter.test,\n parse: {\n sync(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n async async(value, ctx) {\n return await ctx.parse(serializationAdapter.toSerializable(value))\n },\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n // we don't generate JS code outside of SSR (for now)\n serialize: undefined as never,\n deserialize(node, ctx) {\n return serializationAdapter.fromSerializable(ctx.deserialize(node))\n },\n })\n}\n\nexport type ValidateSerializableInput<TRegister, T> = ValidateSerializable<\n T,\n RegisteredSerializableInput<TRegister>\n>\n\nexport type RegisteredSerializableInput<TRegister> =\n | (unknown extends RegisteredSerializationAdapters<TRegister>\n ? never\n : RegisteredSerializationAdapters<TRegister> extends ReadonlyArray<AnySerializationAdapter>\n ? RegisteredSerializationAdapters<TRegister>[number]['~types']['input']\n : never)\n | Serializable\n\nexport type RegisteredSerializationAdapters<TRegister> = RegisteredConfigType<\n TRegister,\n 'serializationAdapters'\n>\n\nexport type ValidateSerializableInputResult<TRegister, T> =\n ValidateSerializableResult<T, RegisteredSerializableInput<TRegister>>\n\nexport type ValidateSerializableResult<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'result'>\n : T extends TSerializable\n ? T\n : unknown extends SerializerExtensions['ReadableStream']\n ? { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n : T extends SerializerExtensions['ReadableStream']\n ? ReadableStream\n : { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n\nexport type RegisteredSSROption<TRegister> =\n unknown extends RegisteredConfigType<TRegister, 'defaultSsr'>\n ? SSROption\n : RegisteredConfigType<TRegister, 'defaultSsr'>\n\nexport type ValidateSerializableLifecycleResult<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n false extends RegisteredSsr<TRegister>\n ? any\n : ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute,\n TSSR,\n TFn\n > extends infer TInput\n ? TInput\n : never\n\nexport type ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n ResolveAllSSR<TParentRoute, TSSR> extends false\n ? any\n : RegisteredSSROption<TRegister> extends false\n ? any\n : ValidateSerializableInput<TRegister, LooseReturnType<TFn>>\n\ntype ResolveArrayShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = number extends T['length']\n ? T extends Array<infer U>\n ? Array<ArrayModeResult<TMode, U, TSerializable>>\n : ReadonlyArray<ArrayModeResult<TMode, T[number], TSerializable>>\n : ResolveTupleShape<T, TSerializable, TMode>\n\ntype ResolveTupleShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = T extends readonly [infer THead, ...infer TTail]\n ? readonly [\n ArrayModeResult<TMode, THead, TSerializable>,\n ...ResolveTupleShape<Readonly<TTail>, TSerializable, TMode>,\n ]\n : T\n\ntype ArrayModeResult<\n TMode extends 'input' | 'result',\n TValue,\n TSerializable,\n> = TMode extends 'input'\n ? ValidateSerializable<TValue, TSerializable>\n : ValidateSerializableResult<TValue, TSerializable>\n"],"names":["createPlugin","GLOBAL_TSR"],"mappings":";;;;AAsCO,SAAS,2BAOd,MACyD;AACzD,SAAO;AAKT;AA6GO,SAAS,qBACd,sBACA,SAC0B;AAC1B,SAAOA,qBAA+B;AAAA,IACpC,KAAK,YAAY,qBAAqB;AAAA,IACtC,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA,IAEF,UAAU,MAAM,KAAK;AACnB,cAAQ,SAAS;AACjB,aACEC,UAAAA,aACA,aACA,qBAAqB,MACrB,QACA,IAAI,UAAU,IAAI,IAClB;AAAA,IAEJ;AAAA;AAAA,IAEA,aAAa;AAAA,EAAA,CACd;AACH;AAGO,SAAS,kBACd,sBAC0B;AAC1B,SAAOD,qBAA+B;AAAA,IACpC,KAAK,YAAY,qBAAqB;AAAA,IACtC,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,KAAK,OAAO,KAAK;AACf,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,MACA,MAAM,MAAM,OAAO,KAAK;AACtB,eAAO,MAAM,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MACnE;AAAA,MACA,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA;AAAA,IAGF,WAAW;AAAA,IACX,YAAY,MAAM,KAAK;AACrB,aAAO,qBAAqB,iBAAiB,IAAI,YAAY,IAAI,CAAC;AAAA,IACpE;AAAA,EAAA,CACD;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"transformer.cjs","sources":["../../../../src/ssr/serializer/transformer.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport { GLOBAL_TSR } from '../constants'\nimport type { Plugin, SerovalNode } from 'seroval'\nimport type {\n RegisteredConfigType,\n RegisteredSsr,\n SSROption,\n} from '../../router'\nimport type { LooseReturnType } from '../../utils'\nimport type { AnyRoute, ResolveAllSSR } from '../../route'\nimport type { RawStream } from './RawStream'\n\ndeclare const TSR_SERIALIZABLE: unique symbol\nexport type TSR_SERIALIZABLE = typeof TSR_SERIALIZABLE\n\nexport type TsrSerializable = { [TSR_SERIALIZABLE]: true }\nexport interface DefaultSerializable {\n number: number\n string: string\n boolean: boolean\n null: null\n undefined: undefined\n bigint: bigint\n Date: Date\n Uint8Array: Uint8Array\n RawStream: RawStream\n TsrSerializable: TsrSerializable\n}\n\nexport interface SerializableExtensions extends DefaultSerializable {}\n\nexport type Serializable = SerializableExtensions[keyof SerializableExtensions]\n\nexport type UnionizeSerializationAdaptersInput<\n TAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> = TAdapters[number]['~types']['input']\n\n/**\n * Create a strongly-typed serialization adapter for SSR hydration.\n * Use to register custom types with the router serializer.\n */\nexport function createSerializationAdapter<\n TInput = unknown,\n TOutput = unknown,\n const TExtendsAdapters extends\n | ReadonlyArray<AnySerializationAdapter>\n | never = never,\n>(\n opts: CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters>,\n): SerializationAdapter<TInput, TOutput, TExtendsAdapters> {\n return opts as unknown as SerializationAdapter<\n TInput,\n TOutput,\n TExtendsAdapters\n >\n}\n\nexport interface CreateSerializationAdapterOptions<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never,\n> {\n key: string\n extends?: TExtendsAdapters\n test: (value: unknown) => value is TInput\n toSerializable: (\n value: TInput,\n ) => ValidateSerializable<\n TOutput,\n Serializable | UnionizeSerializationAdaptersInput<TExtendsAdapters>\n >\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport type ValidateSerializable<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'input'>\n : T extends TSerializable\n ? T\n : T extends (...args: Array<any>) => any\n ? 'Function is not serializable'\n : T extends Promise<any>\n ? ValidateSerializablePromise<T, TSerializable>\n : T extends ReadableStream<any>\n ? ValidateReadableStream<T, TSerializable>\n : T extends Set<any>\n ? ValidateSerializableSet<T, TSerializable>\n : T extends Map<any, any>\n ? ValidateSerializableMap<T, TSerializable>\n : T extends AsyncGenerator<any, any>\n ? ValidateSerializableAsyncGenerator<T, TSerializable>\n : {\n [K in keyof T]: ValidateSerializable<T[K], TSerializable>\n }\n\nexport type ValidateSerializableAsyncGenerator<T, TSerializable> =\n T extends AsyncGenerator<infer T, infer TReturn, infer TNext>\n ? AsyncGenerator<\n ValidateSerializable<T, TSerializable>,\n ValidateSerializable<TReturn, TSerializable>,\n TNext\n >\n : never\n\nexport type ValidateSerializablePromise<T, TSerializable> =\n T extends Promise<infer TAwaited>\n ? Promise<ValidateSerializable<TAwaited, TSerializable>>\n : never\n\nexport type ValidateReadableStream<T, TSerializable> =\n T extends ReadableStream<infer TStreamed>\n ? ReadableStream<ValidateSerializable<TStreamed, TSerializable>>\n : never\n\nexport type ValidateSerializableSet<T, TSerializable> =\n T extends Set<infer TItem>\n ? Set<ValidateSerializable<TItem, TSerializable>>\n : never\n\nexport type ValidateSerializableMap<T, TSerializable> =\n T extends Map<infer TKey, infer TValue>\n ? Map<\n ValidateSerializable<TKey, TSerializable>,\n ValidateSerializable<TValue, TSerializable>\n >\n : never\n\nexport type RegisteredReadableStream =\n unknown extends SerializerExtensions['ReadableStream']\n ? never\n : SerializerExtensions['ReadableStream']\n\nexport interface DefaultSerializerExtensions {\n ReadableStream: unknown\n}\n\nexport interface SerializerExtensions extends DefaultSerializerExtensions {}\n\nexport interface SerializationAdapter<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> {\n '~types': SerializationAdapterTypes<TInput, TOutput, TExtendsAdapters>\n key: string\n extends?: TExtendsAdapters\n test: (value: unknown) => value is TInput\n toSerializable: (value: TInput) => TOutput\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport interface SerializationAdapterTypes<\n TInput,\n TOutput,\n TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter>,\n> {\n input: TInput | UnionizeSerializationAdaptersInput<TExtendsAdapters>\n output: TOutput\n extends: TExtendsAdapters\n}\n\nexport type AnySerializationAdapter = SerializationAdapter<any, any, any>\n\n/** Create a Seroval plugin for server-side serialization only. */\nexport function makeSsrSerovalPlugin(\n serializationAdapter: AnySerializationAdapter,\n options: { didRun: boolean },\n): Plugin<any, SerovalNode> {\n return createPlugin<any, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n test: serializationAdapter.test,\n parse: {\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n serialize(node, ctx) {\n options.didRun = true\n return (\n GLOBAL_TSR +\n '.t.get(\"' +\n serializationAdapter.key +\n '\")(' +\n ctx.serialize(node) +\n ')'\n )\n },\n // we never deserialize on the server during SSR\n deserialize: undefined as never,\n })\n}\n\n/** Create a Seroval plugin for client/server symmetric (de)serialization. */\nexport function makeSerovalPlugin(\n serializationAdapter: AnySerializationAdapter,\n): Plugin<any, SerovalNode> {\n return createPlugin<any, SerovalNode>({\n tag: '$TSR/t/' + serializationAdapter.key,\n test: serializationAdapter.test,\n parse: {\n sync(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n async async(value, ctx) {\n return await ctx.parse(serializationAdapter.toSerializable(value))\n },\n stream(value, ctx) {\n return ctx.parse(serializationAdapter.toSerializable(value))\n },\n },\n // we don't generate JS code outside of SSR (for now)\n serialize: undefined as never,\n deserialize(node, ctx) {\n return serializationAdapter.fromSerializable(ctx.deserialize(node))\n },\n })\n}\n\nexport type ValidateSerializableInput<TRegister, T> = ValidateSerializable<\n T,\n RegisteredSerializableInput<TRegister>\n>\n\nexport type RegisteredSerializableInput<TRegister> =\n | (unknown extends RegisteredSerializationAdapters<TRegister>\n ? never\n : RegisteredSerializationAdapters<TRegister> extends ReadonlyArray<AnySerializationAdapter>\n ? RegisteredSerializationAdapters<TRegister>[number]['~types']['input']\n : never)\n | Serializable\n\nexport type RegisteredSerializationAdapters<TRegister> = RegisteredConfigType<\n TRegister,\n 'serializationAdapters'\n>\n\nexport type ValidateSerializableInputResult<TRegister, T> =\n ValidateSerializableResult<T, RegisteredSerializableInput<TRegister>>\n\nexport type ValidateSerializableResult<T, TSerializable> =\n T extends ReadonlyArray<unknown>\n ? ResolveArrayShape<T, TSerializable, 'result'>\n : T extends TSerializable\n ? T\n : unknown extends SerializerExtensions['ReadableStream']\n ? { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n : T extends SerializerExtensions['ReadableStream']\n ? ReadableStream\n : { [K in keyof T]: ValidateSerializableResult<T[K], TSerializable> }\n\nexport type RegisteredSSROption<TRegister> =\n unknown extends RegisteredConfigType<TRegister, 'defaultSsr'>\n ? SSROption\n : RegisteredConfigType<TRegister, 'defaultSsr'>\n\nexport type ValidateSerializableLifecycleResult<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n false extends RegisteredSsr<TRegister>\n ? any\n : ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute,\n TSSR,\n TFn\n > extends infer TInput\n ? TInput\n : never\n\nexport type ValidateSerializableLifecycleResultSSR<\n TRegister,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> =\n ResolveAllSSR<TParentRoute, TSSR> extends false\n ? any\n : RegisteredSSROption<TRegister> extends false\n ? any\n : ValidateSerializableInput<TRegister, LooseReturnType<TFn>>\n\ntype ResolveArrayShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = number extends T['length']\n ? T extends Array<infer U>\n ? Array<ArrayModeResult<TMode, U, TSerializable>>\n : ReadonlyArray<ArrayModeResult<TMode, T[number], TSerializable>>\n : ResolveTupleShape<T, TSerializable, TMode>\n\ntype ResolveTupleShape<\n T extends ReadonlyArray<unknown>,\n TSerializable,\n TMode extends 'input' | 'result',\n> = T extends readonly [infer THead, ...infer TTail]\n ? readonly [\n ArrayModeResult<TMode, THead, TSerializable>,\n ...ResolveTupleShape<Readonly<TTail>, TSerializable, TMode>,\n ]\n : T\n\ntype ArrayModeResult<\n TMode extends 'input' | 'result',\n TValue,\n TSerializable,\n> = TMode extends 'input'\n ? ValidateSerializable<TValue, TSerializable>\n : ValidateSerializableResult<TValue, TSerializable>\n"],"names":["createPlugin","GLOBAL_TSR"],"mappings":";;;;AAyCO,SAAS,2BAOd,MACyD;AACzD,SAAO;AAKT;AA6GO,SAAS,qBACd,sBACA,SAC0B;AAC1B,SAAOA,qBAA+B;AAAA,IACpC,KAAK,YAAY,qBAAqB;AAAA,IACtC,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA,IAEF,UAAU,MAAM,KAAK;AACnB,cAAQ,SAAS;AACjB,aACEC,UAAAA,aACA,aACA,qBAAqB,MACrB,QACA,IAAI,UAAU,IAAI,IAClB;AAAA,IAEJ;AAAA;AAAA,IAEA,aAAa;AAAA,EAAA,CACd;AACH;AAGO,SAAS,kBACd,sBAC0B;AAC1B,SAAOD,qBAA+B;AAAA,IACpC,KAAK,YAAY,qBAAqB;AAAA,IACtC,MAAM,qBAAqB;AAAA,IAC3B,OAAO;AAAA,MACL,KAAK,OAAO,KAAK;AACf,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,MACA,MAAM,MAAM,OAAO,KAAK;AACtB,eAAO,MAAM,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MACnE;AAAA,MACA,OAAO,OAAO,KAAK;AACjB,eAAO,IAAI,MAAM,qBAAqB,eAAe,KAAK,CAAC;AAAA,MAC7D;AAAA,IAAA;AAAA;AAAA,IAGF,WAAW;AAAA,IACX,YAAY,MAAM,KAAK;AACrB,aAAO,qBAAqB,iBAAiB,IAAI,YAAY,IAAI,CAAC;AAAA,IACpE;AAAA,EAAA,CACD;AACH;;;;"}
|
|
@@ -2,6 +2,7 @@ import { Plugin, SerovalNode } from 'seroval';
|
|
|
2
2
|
import { RegisteredConfigType, RegisteredSsr, SSROption } from '../../router.cjs';
|
|
3
3
|
import { LooseReturnType } from '../../utils.cjs';
|
|
4
4
|
import { AnyRoute, ResolveAllSSR } from '../../route.cjs';
|
|
5
|
+
import { RawStream } from './RawStream.cjs';
|
|
5
6
|
declare const TSR_SERIALIZABLE: unique symbol;
|
|
6
7
|
export type TSR_SERIALIZABLE = typeof TSR_SERIALIZABLE;
|
|
7
8
|
export type TsrSerializable = {
|
|
@@ -15,6 +16,8 @@ export interface DefaultSerializable {
|
|
|
15
16
|
undefined: undefined;
|
|
16
17
|
bigint: bigint;
|
|
17
18
|
Date: Date;
|
|
19
|
+
Uint8Array: Uint8Array;
|
|
20
|
+
RawStream: RawStream;
|
|
18
21
|
TsrSerializable: TsrSerializable;
|
|
19
22
|
}
|
|
20
23
|
export interface SerializableExtensions extends DefaultSerializable {
|