@tanstack/router-core 1.133.20 → 1.133.27
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/defer.cjs.map +1 -1
- package/dist/cjs/defer.d.cts +5 -0
- package/dist/cjs/path.cjs +15 -21
- package/dist/cjs/path.cjs.map +1 -1
- package/dist/cjs/path.d.cts +31 -3
- package/dist/cjs/process-route-tree.cjs +1 -1
- package/dist/cjs/process-route-tree.cjs.map +1 -1
- package/dist/cjs/process-route-tree.d.cts +8 -0
- package/dist/cjs/qss.cjs.map +1 -1
- package/dist/cjs/qss.d.cts +2 -0
- package/dist/cjs/redirect.cjs.map +1 -1
- package/dist/cjs/redirect.d.cts +9 -0
- package/dist/cjs/rewrite.cjs.map +1 -1
- package/dist/cjs/rewrite.d.cts +4 -0
- package/dist/cjs/root.cjs.map +1 -1
- package/dist/cjs/root.d.cts +1 -0
- package/dist/cjs/route.cjs.map +1 -1
- package/dist/cjs/route.d.cts +2 -2
- package/dist/cjs/router.cjs.map +1 -1
- package/dist/cjs/router.d.cts +59 -0
- package/dist/cjs/scroll-restoration.cjs.map +1 -1
- package/dist/cjs/scroll-restoration.d.cts +23 -0
- package/dist/cjs/searchMiddleware.cjs.map +1 -1
- package/dist/cjs/searchMiddleware.d.cts +6 -0
- package/dist/cjs/searchParams.cjs.map +1 -1
- package/dist/cjs/searchParams.d.cts +4 -0
- package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -1
- package/dist/cjs/ssr/serializer/transformer.d.cts +6 -0
- package/dist/esm/defer.d.ts +5 -0
- package/dist/esm/defer.js.map +1 -1
- package/dist/esm/path.d.ts +31 -3
- package/dist/esm/path.js +15 -21
- package/dist/esm/path.js.map +1 -1
- package/dist/esm/process-route-tree.d.ts +8 -0
- package/dist/esm/process-route-tree.js +2 -2
- package/dist/esm/process-route-tree.js.map +1 -1
- package/dist/esm/qss.d.ts +2 -0
- package/dist/esm/qss.js.map +1 -1
- package/dist/esm/redirect.d.ts +9 -0
- package/dist/esm/redirect.js.map +1 -1
- package/dist/esm/rewrite.d.ts +4 -0
- package/dist/esm/rewrite.js.map +1 -1
- package/dist/esm/root.d.ts +1 -0
- package/dist/esm/root.js.map +1 -1
- package/dist/esm/route.d.ts +2 -2
- package/dist/esm/route.js.map +1 -1
- package/dist/esm/router.d.ts +59 -0
- package/dist/esm/router.js.map +1 -1
- package/dist/esm/scroll-restoration.d.ts +23 -0
- package/dist/esm/scroll-restoration.js.map +1 -1
- package/dist/esm/searchMiddleware.d.ts +6 -0
- package/dist/esm/searchMiddleware.js.map +1 -1
- package/dist/esm/searchParams.d.ts +4 -0
- package/dist/esm/searchParams.js.map +1 -1
- package/dist/esm/ssr/serializer/transformer.d.ts +6 -0
- package/dist/esm/ssr/serializer/transformer.js.map +1 -1
- package/package.json +1 -1
- package/src/defer.ts +5 -0
- package/src/path.ts +46 -37
- package/src/process-route-tree.ts +10 -2
- package/src/qss.ts +2 -0
- package/src/redirect.ts +9 -0
- package/src/rewrite.ts +4 -0
- package/src/root.ts +1 -0
- package/src/route.ts +2 -2
- package/src/router.ts +59 -3
- package/src/scroll-restoration.ts +23 -0
- package/src/searchMiddleware.ts +6 -0
- package/src/searchParams.ts +4 -0
- package/src/ssr/serializer/transformer.ts +6 -0
package/dist/cjs/router.d.cts
CHANGED
|
@@ -505,18 +505,27 @@ export interface ViewTransitionOptions {
|
|
|
505
505
|
hashChanged: boolean;
|
|
506
506
|
}) => Array<string> | false);
|
|
507
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* Convert an unknown error into a minimal, serializable object.
|
|
510
|
+
* Includes name and message (and stack in development).
|
|
511
|
+
*/
|
|
508
512
|
export declare function defaultSerializeError(err: unknown): {
|
|
509
513
|
name: string;
|
|
510
514
|
message: string;
|
|
511
515
|
} | {
|
|
512
516
|
data: unknown;
|
|
513
517
|
};
|
|
518
|
+
/** Options for configuring trailing-slash behavior. */
|
|
514
519
|
export declare const trailingSlashOptions: {
|
|
515
520
|
readonly always: "always";
|
|
516
521
|
readonly never: "never";
|
|
517
522
|
readonly preserve: "preserve";
|
|
518
523
|
};
|
|
519
524
|
export type TrailingSlashOption = (typeof trailingSlashOptions)[keyof typeof trailingSlashOptions];
|
|
525
|
+
/**
|
|
526
|
+
* Compute whether path, href or hash changed between previous and current
|
|
527
|
+
* resolved locations in router state.
|
|
528
|
+
*/
|
|
520
529
|
export declare function getLocationChangeInfo(routerState: {
|
|
521
530
|
resolvedLocation?: ParsedLocation;
|
|
522
531
|
location: ParsedLocation;
|
|
@@ -528,6 +537,15 @@ export declare function getLocationChangeInfo(routerState: {
|
|
|
528
537
|
hashChanged: boolean;
|
|
529
538
|
};
|
|
530
539
|
export type CreateRouterFn = <TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption = 'never', TDefaultStructuralSharingOption extends boolean = false, TRouterHistory extends RouterHistory = RouterHistory, TDehydrated extends Record<string, any> = Record<string, any>>(options: undefined extends number ? 'strictNullChecks must be enabled in tsconfig.json' : RouterConstructorOptions<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>) => RouterCore<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>;
|
|
540
|
+
/**
|
|
541
|
+
* Core, framework-agnostic router engine that powers TanStack Router.
|
|
542
|
+
*
|
|
543
|
+
* Provides navigation, matching, loading, preloading, caching and event APIs
|
|
544
|
+
* used by framework adapters (React/Solid). Prefer framework helpers like
|
|
545
|
+
* `createRouter` in app code.
|
|
546
|
+
*
|
|
547
|
+
* @link https://tanstack.com/router/latest/docs/framework/react/api/router/RouterType
|
|
548
|
+
*/
|
|
531
549
|
export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrailingSlashOption extends TrailingSlashOption, in out TDefaultStructuralSharingOption extends boolean, in out TRouterHistory extends RouterHistory = RouterHistory, in out TDehydrated extends Record<string, any> = Record<string, any>> {
|
|
532
550
|
tempLocationKey: string | undefined;
|
|
533
551
|
resetNextScroll: boolean;
|
|
@@ -561,9 +579,20 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
561
579
|
get state(): RouterState<TRouteTree>;
|
|
562
580
|
updateLatestLocation: () => void;
|
|
563
581
|
buildRouteTree: () => void;
|
|
582
|
+
/**
|
|
583
|
+
* Subscribe to router lifecycle events like `onBeforeNavigate`, `onLoad`,
|
|
584
|
+
* `onResolved`, etc. Returns an unsubscribe function.
|
|
585
|
+
*
|
|
586
|
+
* @link https://tanstack.com/router/latest/docs/framework/react/api/router/RouterEventsType
|
|
587
|
+
*/
|
|
564
588
|
subscribe: SubscribeFn;
|
|
565
589
|
emit: EmitFn;
|
|
590
|
+
/**
|
|
591
|
+
* Parse a HistoryLocation into a strongly-typed ParsedLocation using the
|
|
592
|
+
* current router options, rewrite rules and search parser/stringifier.
|
|
593
|
+
*/
|
|
566
594
|
parseLocation: ParseLocationFn<TRouteTree>;
|
|
595
|
+
/** Resolve a path against the router basepath and trailing-slash policy. */
|
|
567
596
|
resolvePathWithBase: (from: string, path: string) => string;
|
|
568
597
|
get looseRoutesById(): Record<string, AnyRoute>;
|
|
569
598
|
matchRoutes: MatchRoutesFn;
|
|
@@ -573,10 +602,29 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
573
602
|
getMatchedRoutes: GetMatchRoutesFn;
|
|
574
603
|
cancelMatch: (id: string) => void;
|
|
575
604
|
cancelMatches: () => void;
|
|
605
|
+
/**
|
|
606
|
+
* Build the next ParsedLocation from navigation options without committing.
|
|
607
|
+
* Resolves `to`/`from`, params/search/hash/state, applies search validation
|
|
608
|
+
* and middlewares, and returns a stable, stringified location object.
|
|
609
|
+
*
|
|
610
|
+
* @link https://tanstack.com/router/latest/docs/framework/react/api/router/RouterType#buildlocation-method
|
|
611
|
+
*/
|
|
576
612
|
buildLocation: BuildLocationFn;
|
|
577
613
|
commitLocationPromise: undefined | ControlledPromise<void>;
|
|
614
|
+
/**
|
|
615
|
+
* Commit a previously built location to history (push/replace), optionally
|
|
616
|
+
* using view transitions and scroll restoration options.
|
|
617
|
+
*/
|
|
578
618
|
commitLocation: CommitLocationFn;
|
|
619
|
+
/** Convenience helper: build a location from options, then commit it. */
|
|
579
620
|
buildAndCommitLocation: ({ replace, resetScroll, hashScrollIntoView, viewTransition, ignoreBlocker, href, ...rest }?: BuildNextOptions & CommitLocationOptions) => Promise<void>;
|
|
621
|
+
/**
|
|
622
|
+
* Imperatively navigate using standard `NavigateOptions`. When `reloadDocument`
|
|
623
|
+
* or an absolute `href` is provided, performs a full document navigation.
|
|
624
|
+
* Otherwise, builds and commits a client-side location.
|
|
625
|
+
*
|
|
626
|
+
* @link https://tanstack.com/router/latest/docs/framework/react/api/router/NavigateOptionsType
|
|
627
|
+
*/
|
|
580
628
|
navigate: NavigateFn;
|
|
581
629
|
latestLoadPromise: undefined | Promise<void>;
|
|
582
630
|
beforeLoad: () => void;
|
|
@@ -597,12 +645,23 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
|
|
|
597
645
|
serverSsr?: ServerSsr;
|
|
598
646
|
hasNotFoundMatch: () => boolean;
|
|
599
647
|
}
|
|
648
|
+
/** Error thrown when search parameter validation fails. */
|
|
600
649
|
export declare class SearchParamError extends Error {
|
|
601
650
|
}
|
|
651
|
+
/** Error thrown when path parameter parsing/validation fails. */
|
|
602
652
|
export declare class PathParamError extends Error {
|
|
603
653
|
}
|
|
654
|
+
/**
|
|
655
|
+
* Lazily import a module function and forward arguments to it, retaining
|
|
656
|
+
* parameter and return types for the selected export key.
|
|
657
|
+
*/
|
|
604
658
|
export declare function lazyFn<T extends Record<string, (...args: Array<any>) => any>, TKey extends keyof T = 'default'>(fn: () => Promise<T>, key?: TKey): (...args: Parameters<T[TKey]>) => Promise<Awaited<ReturnType<T[TKey]>>>;
|
|
659
|
+
/** Create an initial RouterState from a parsed location. */
|
|
605
660
|
export declare function getInitialRouterState(location: ParsedLocation): RouterState<any>;
|
|
661
|
+
/**
|
|
662
|
+
* Build the matched route chain and extract params for a pathname.
|
|
663
|
+
* Falls back to the root route if no specific route is found.
|
|
664
|
+
*/
|
|
606
665
|
export declare function getMatchedRoutes<TRouteLike extends RouteLike>({ pathname, routePathname, caseSensitive, routesByPath, routesById, flatRoutes, parseCache, }: {
|
|
607
666
|
pathname: string;
|
|
608
667
|
routePathname?: string;
|
|
@@ -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\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\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\nexport const defaultGetScrollRestorationKey = (location: ParsedLocation) => {\n return location.state.__TSR_key! || location.href\n}\n\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\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 */\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. */\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. */\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 */\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\n/**\n * Restore scroll positions for window/elements based on cached entries.\n */\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. */\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 <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 */\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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"}
|
|
@@ -16,7 +16,11 @@ export type ScrollRestorationOptions = {
|
|
|
16
16
|
getKey?: (location: ParsedLocation) => string;
|
|
17
17
|
scrollBehavior?: ScrollToOptions['behavior'];
|
|
18
18
|
};
|
|
19
|
+
/** SessionStorage key used to persist scroll restoration state. */
|
|
20
|
+
/** SessionStorage key used to store scroll positions across navigations. */
|
|
19
21
|
export declare const storageKey = "tsr-scroll-restoration-v1_3";
|
|
22
|
+
/** In-memory handle to the persisted scroll restoration cache. */
|
|
23
|
+
/** In-memory handle to the persisted scroll restoration cache. */
|
|
20
24
|
export declare const scrollRestorationCache: ScrollRestorationCache | null;
|
|
21
25
|
/**
|
|
22
26
|
* The default `getKey` function for `useScrollRestoration`.
|
|
@@ -24,8 +28,18 @@ export declare const scrollRestorationCache: ScrollRestorationCache | null;
|
|
|
24
28
|
*
|
|
25
29
|
* The `location.href` is used as a fallback to support the use case where the location state is not available like the initial render.
|
|
26
30
|
*/
|
|
31
|
+
/**
|
|
32
|
+
* Default scroll restoration cache key: location state key or full href.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Default scroll restoration cache key: location state key or full href.
|
|
36
|
+
*/
|
|
27
37
|
export declare const defaultGetScrollRestorationKey: (location: ParsedLocation) => string;
|
|
38
|
+
/** Best-effort nth-child CSS selector for a given element. */
|
|
28
39
|
export declare function getCssSelector(el: any): string;
|
|
40
|
+
/**
|
|
41
|
+
* Restore scroll positions for window/elements based on cached entries.
|
|
42
|
+
*/
|
|
29
43
|
export declare function restoreScroll({ storageKey, key, behavior, shouldScrollRestoration, scrollToTopSelectors, location, }: {
|
|
30
44
|
storageKey: string;
|
|
31
45
|
key?: string;
|
|
@@ -34,7 +48,16 @@ export declare function restoreScroll({ storageKey, key, behavior, shouldScrollR
|
|
|
34
48
|
scrollToTopSelectors?: Array<string | (() => Element | null | undefined)>;
|
|
35
49
|
location?: HistoryLocation;
|
|
36
50
|
}): void;
|
|
51
|
+
/** Setup global listeners and hooks to support scroll restoration. */
|
|
37
52
|
export declare function setupScrollRestoration(router: AnyRouter, force?: boolean): void;
|
|
53
|
+
/**
|
|
54
|
+
* @private
|
|
55
|
+
* Handles hash-based scrolling after navigation completes.
|
|
56
|
+
* To be used in framework-specific <Transitioner> components during the onResolved event.
|
|
57
|
+
*
|
|
58
|
+
* Provides hash scrolling for programmatic navigation when default browser handling is prevented.
|
|
59
|
+
* @param router The router instance containing current location and state
|
|
60
|
+
*/
|
|
38
61
|
/**
|
|
39
62
|
* @private
|
|
40
63
|
* Handles hash-based scrolling after navigation completes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchMiddleware.cjs","sources":["../../src/searchMiddleware.ts"],"sourcesContent":["import { deepEqual } from './utils'\nimport type { NoInfer, PickOptional } from './utils'\nimport type { SearchMiddleware } from './route'\nimport type { IsRequiredParams } from './link'\n\n/**\n * Retain specified search params across navigations.\n *\n * If `keys` is `true`, retain all current params. Otherwise, copy only the\n * listed keys from the current search into the next search.\n *\n * @param keys `true` to retain all, or a list of keys to retain.\n * @returns A search middleware suitable for route `search.middlewares`.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/retainSearchParamsFunction\n */\nexport function retainSearchParams<TSearchSchema extends object>(\n keys: Array<keyof TSearchSchema> | true,\n): SearchMiddleware<TSearchSchema> {\n return ({ search, next }) => {\n const result = next(search)\n if (keys === true) {\n return { ...search, ...result }\n }\n // add missing keys from search to result\n keys.forEach((key) => {\n if (!(key in result)) {\n result[key] = search[key]\n }\n })\n return result\n }\n}\n\n/**\n * Remove optional or default-valued search params from navigations.\n *\n * - Pass `true` (only if there are no required search params) to strip all.\n * - Pass an array to always remove those optional keys.\n * - Pass an object of default values; keys equal (deeply) to the defaults are removed.\n *\n * @returns A search middleware suitable for route `search.middlewares`.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/stripSearchParamsFunction\n */\nexport function stripSearchParams<\n TSearchSchema,\n TOptionalProps = PickOptional<NoInfer<TSearchSchema>>,\n const TValues =\n | Partial<NoInfer<TOptionalProps>>\n | Array<keyof TOptionalProps>,\n const TInput = IsRequiredParams<TSearchSchema> extends never\n ? TValues | true\n : TValues,\n>(input: NoInfer<TInput>): SearchMiddleware<TSearchSchema> {\n return ({ search, next }) => {\n if (input === true) {\n return {}\n }\n const result = next(search) as Record<string, unknown>\n if (Array.isArray(input)) {\n input.forEach((key) => {\n delete result[key]\n })\n } else {\n Object.entries(input as Record<string, unknown>).forEach(\n ([key, value]) => {\n if (deepEqual(result[key], value)) {\n delete result[key]\n }\n },\n )\n }\n return result as any\n }\n}\n"],"names":["deepEqual"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"searchMiddleware.cjs","sources":["../../src/searchMiddleware.ts"],"sourcesContent":["import { deepEqual } from './utils'\nimport type { NoInfer, PickOptional } from './utils'\nimport type { SearchMiddleware } from './route'\nimport type { IsRequiredParams } from './link'\n\n/**\n * Retain specified search params across navigations.\n *\n * If `keys` is `true`, retain all current params. Otherwise, copy only the\n * listed keys from the current search into the next search.\n *\n * @param keys `true` to retain all, or a list of keys to retain.\n * @returns A search middleware suitable for route `search.middlewares`.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/retainSearchParamsFunction\n */\n/**\n * Retain specified search params across navigations by merging prior values.\n */\nexport function retainSearchParams<TSearchSchema extends object>(\n keys: Array<keyof TSearchSchema> | true,\n): SearchMiddleware<TSearchSchema> {\n return ({ search, next }) => {\n const result = next(search)\n if (keys === true) {\n return { ...search, ...result }\n }\n // add missing keys from search to result\n keys.forEach((key) => {\n if (!(key in result)) {\n result[key] = search[key]\n }\n })\n return result\n }\n}\n\n/**\n * Remove optional or default-valued search params from navigations.\n *\n * - Pass `true` (only if there are no required search params) to strip all.\n * - Pass an array to always remove those optional keys.\n * - Pass an object of default values; keys equal (deeply) to the defaults are removed.\n *\n * @returns A search middleware suitable for route `search.middlewares`.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/stripSearchParamsFunction\n */\n/**\n * Remove optional/default-valued search params from navigations.\n */\nexport function stripSearchParams<\n TSearchSchema,\n TOptionalProps = PickOptional<NoInfer<TSearchSchema>>,\n const TValues =\n | Partial<NoInfer<TOptionalProps>>\n | Array<keyof TOptionalProps>,\n const TInput = IsRequiredParams<TSearchSchema> extends never\n ? TValues | true\n : TValues,\n>(input: NoInfer<TInput>): SearchMiddleware<TSearchSchema> {\n return ({ search, next }) => {\n if (input === true) {\n return {}\n }\n const result = next(search) as Record<string, unknown>\n if (Array.isArray(input)) {\n input.forEach((key) => {\n delete result[key]\n })\n } else {\n Object.entries(input as Record<string, unknown>).forEach(\n ([key, value]) => {\n if (deepEqual(result[key], value)) {\n delete result[key]\n }\n },\n )\n }\n return result as any\n }\n}\n"],"names":["deepEqual"],"mappings":";;;AAkBO,SAAS,mBACd,MACiC;AACjC,SAAO,CAAC,EAAE,QAAQ,WAAW;AAC3B,UAAM,SAAS,KAAK,MAAM;AAC1B,QAAI,SAAS,MAAM;AACjB,aAAO,EAAE,GAAG,QAAQ,GAAG,OAAA;AAAA,IACzB;AAEA,SAAK,QAAQ,CAAC,QAAQ;AACpB,UAAI,EAAE,OAAO,SAAS;AACpB,eAAO,GAAG,IAAI,OAAO,GAAG;AAAA,MAC1B;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AACF;AAeO,SAAS,kBASd,OAAyD;AACzD,SAAO,CAAC,EAAE,QAAQ,WAAW;AAC3B,QAAI,UAAU,MAAM;AAClB,aAAO,CAAA;AAAA,IACT;AACA,UAAM,SAAS,KAAK,MAAM;AAC1B,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAM,QAAQ,CAAC,QAAQ;AACrB,eAAO,OAAO,GAAG;AAAA,MACnB,CAAC;AAAA,IACH,OAAO;AACL,aAAO,QAAQ,KAAgC,EAAE;AAAA,QAC/C,CAAC,CAAC,KAAK,KAAK,MAAM;AAChB,cAAIA,MAAAA,UAAU,OAAO,GAAG,GAAG,KAAK,GAAG;AACjC,mBAAO,OAAO,GAAG;AAAA,UACnB;AAAA,QACF;AAAA,MAAA;AAAA,IAEJ;AACA,WAAO;AAAA,EACT;AACF;;;"}
|
|
@@ -11,6 +11,9 @@ import { IsRequiredParams } from './link.cjs';
|
|
|
11
11
|
* @returns A search middleware suitable for route `search.middlewares`.
|
|
12
12
|
* @link https://tanstack.com/router/latest/docs/framework/react/api/router/retainSearchParamsFunction
|
|
13
13
|
*/
|
|
14
|
+
/**
|
|
15
|
+
* Retain specified search params across navigations by merging prior values.
|
|
16
|
+
*/
|
|
14
17
|
export declare function retainSearchParams<TSearchSchema extends object>(keys: Array<keyof TSearchSchema> | true): SearchMiddleware<TSearchSchema>;
|
|
15
18
|
/**
|
|
16
19
|
* Remove optional or default-valued search params from navigations.
|
|
@@ -22,4 +25,7 @@ export declare function retainSearchParams<TSearchSchema extends object>(keys: A
|
|
|
22
25
|
* @returns A search middleware suitable for route `search.middlewares`.
|
|
23
26
|
* @link https://tanstack.com/router/latest/docs/framework/react/api/router/stripSearchParamsFunction
|
|
24
27
|
*/
|
|
28
|
+
/**
|
|
29
|
+
* Remove optional/default-valued search params from navigations.
|
|
30
|
+
*/
|
|
25
31
|
export declare function stripSearchParams<TSearchSchema, TOptionalProps = PickOptional<NoInfer<TSearchSchema>>, const TValues = Partial<NoInfer<TOptionalProps>> | Array<keyof TOptionalProps>, const TInput = IsRequiredParams<TSearchSchema> extends never ? TValues | true : TValues>(input: NoInfer<TInput>): SearchMiddleware<TSearchSchema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"searchParams.cjs","sources":["../../src/searchParams.ts"],"sourcesContent":["import { decode, encode } from './qss'\nimport type { AnySchema } from './validators'\n\nexport const defaultParseSearch = parseSearchWith(JSON.parse)\nexport const defaultStringifySearch = stringifySearchWith(\n JSON.stringify,\n JSON.parse,\n)\n\n/**\n * Build a `parseSearch` function using a provided JSON-like parser.\n *\n * The returned function strips a leading `?`, decodes values, and attempts to\n * JSON-parse string values using the given `parser`.\n *\n * @param parser Function to parse a string value (e.g. `JSON.parse`).\n * @returns A `parseSearch` function compatible with `Router` options.\n * @link https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization\n */\nexport function parseSearchWith(parser: (str: string) => any) {\n return (searchStr: string): AnySchema => {\n if (searchStr[0] === '?') {\n searchStr = searchStr.substring(1)\n }\n\n const query: Record<string, unknown> = decode(searchStr)\n\n // Try to parse any query params that might be json\n for (const key in query) {\n const value = query[key]\n if (typeof value === 'string') {\n try {\n query[key] = parser(value)\n } catch (_err) {\n // silent\n }\n }\n }\n\n return query\n }\n}\n\n/**\n * Build a `stringifySearch` function using a provided serializer.\n *\n * Non-primitive values are serialized with `stringify`. If a `parser` is\n * supplied, string values that are parseable are re-serialized to ensure\n * symmetry with `parseSearch`.\n *\n * @param stringify Function to serialize a value (e.g. `JSON.stringify`).\n * @param parser Optional parser to detect parseable strings.\n * @returns A `stringifySearch` function compatible with `Router` options.\n * @link https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization\n */\nexport function stringifySearchWith(\n stringify: (search: any) => string,\n parser?: (str: string) => any,\n) {\n const hasParser = typeof parser === 'function'\n function stringifyValue(val: any) {\n if (typeof val === 'object' && val !== null) {\n try {\n return stringify(val)\n } catch (_err) {\n // silent\n }\n } else if (hasParser && typeof val === 'string') {\n try {\n // Check if it's a valid parseable string.\n // If it is, then stringify it again.\n parser(val)\n return stringify(val)\n } catch (_err) {\n // silent\n }\n }\n return val\n }\n\n return (search: Record<string, any>) => {\n const searchStr = encode(search, stringifyValue)\n return searchStr ? `?${searchStr}` : ''\n }\n}\n\nexport type SearchSerializer = (searchObj: Record<string, any>) => string\nexport type SearchParser = (searchStr: string) => Record<string, any>\n"],"names":["decode","encode"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"searchParams.cjs","sources":["../../src/searchParams.ts"],"sourcesContent":["import { decode, encode } from './qss'\nimport type { AnySchema } from './validators'\n\n/** Default `parseSearch` that strips leading '?' and JSON-parses values. */\n/** Default `parseSearch` that strips leading '?' and JSON-parses values. */\nexport const defaultParseSearch = parseSearchWith(JSON.parse)\nexport const defaultStringifySearch = stringifySearchWith(\n JSON.stringify,\n JSON.parse,\n)\n\n/**\n * Build a `parseSearch` function using a provided JSON-like parser.\n *\n * The returned function strips a leading `?`, decodes values, and attempts to\n * JSON-parse string values using the given `parser`.\n *\n * @param parser Function to parse a string value (e.g. `JSON.parse`).\n * @returns A `parseSearch` function compatible with `Router` options.\n * @link https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization\n */\n/** Build a parseSearch function using a provided JSON-like parser. */\nexport function parseSearchWith(parser: (str: string) => any) {\n return (searchStr: string): AnySchema => {\n if (searchStr[0] === '?') {\n searchStr = searchStr.substring(1)\n }\n\n const query: Record<string, unknown> = decode(searchStr)\n\n // Try to parse any query params that might be json\n for (const key in query) {\n const value = query[key]\n if (typeof value === 'string') {\n try {\n query[key] = parser(value)\n } catch (_err) {\n // silent\n }\n }\n }\n\n return query\n }\n}\n\n/**\n * Build a `stringifySearch` function using a provided serializer.\n *\n * Non-primitive values are serialized with `stringify`. If a `parser` is\n * supplied, string values that are parseable are re-serialized to ensure\n * symmetry with `parseSearch`.\n *\n * @param stringify Function to serialize a value (e.g. `JSON.stringify`).\n * @param parser Optional parser to detect parseable strings.\n * @returns A `stringifySearch` function compatible with `Router` options.\n * @link https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization\n */\n/** Build a stringifySearch function using a provided serializer/parser. */\nexport function stringifySearchWith(\n stringify: (search: any) => string,\n parser?: (str: string) => any,\n) {\n const hasParser = typeof parser === 'function'\n function stringifyValue(val: any) {\n if (typeof val === 'object' && val !== null) {\n try {\n return stringify(val)\n } catch (_err) {\n // silent\n }\n } else if (hasParser && typeof val === 'string') {\n try {\n // Check if it's a valid parseable string.\n // If it is, then stringify it again.\n parser(val)\n return stringify(val)\n } catch (_err) {\n // silent\n }\n }\n return val\n }\n\n return (search: Record<string, any>) => {\n const searchStr = encode(search, stringifyValue)\n return searchStr ? `?${searchStr}` : ''\n }\n}\n\nexport type SearchSerializer = (searchObj: Record<string, any>) => string\nexport type SearchParser = (searchStr: string) => Record<string, any>\n"],"names":["decode","encode"],"mappings":";;;AAKO,MAAM,qBAAqB,gBAAgB,KAAK,KAAK;AACrD,MAAM,yBAAyB;AAAA,EACpC,KAAK;AAAA,EACL,KAAK;AACP;AAaO,SAAS,gBAAgB,QAA8B;AAC5D,SAAO,CAAC,cAAiC;AACvC,QAAI,UAAU,CAAC,MAAM,KAAK;AACxB,kBAAY,UAAU,UAAU,CAAC;AAAA,IACnC;AAEA,UAAM,QAAiCA,IAAAA,OAAO,SAAS;AAGvD,eAAW,OAAO,OAAO;AACvB,YAAM,QAAQ,MAAM,GAAG;AACvB,UAAI,OAAO,UAAU,UAAU;AAC7B,YAAI;AACF,gBAAM,GAAG,IAAI,OAAO,KAAK;AAAA,QAC3B,SAAS,MAAM;AAAA,QAEf;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAeO,SAAS,oBACd,WACA,QACA;AACA,QAAM,YAAY,OAAO,WAAW;AACpC,WAAS,eAAe,KAAU;AAChC,QAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,UAAI;AACF,eAAO,UAAU,GAAG;AAAA,MACtB,SAAS,MAAM;AAAA,MAEf;AAAA,IACF,WAAW,aAAa,OAAO,QAAQ,UAAU;AAC/C,UAAI;AAGF,eAAO,GAAG;AACV,eAAO,UAAU,GAAG;AAAA,MACtB,SAAS,MAAM;AAAA,MAEf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,WAAgC;AACtC,UAAM,YAAYC,IAAAA,OAAO,QAAQ,cAAc;AAC/C,WAAO,YAAY,IAAI,SAAS,KAAK;AAAA,EACvC;AACF;;;;;"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { AnySchema } from './validators.cjs';
|
|
2
|
+
/** Default `parseSearch` that strips leading '?' and JSON-parses values. */
|
|
3
|
+
/** Default `parseSearch` that strips leading '?' and JSON-parses values. */
|
|
2
4
|
export declare const defaultParseSearch: (searchStr: string) => AnySchema;
|
|
3
5
|
export declare const defaultStringifySearch: (search: Record<string, any>) => string;
|
|
4
6
|
/**
|
|
@@ -11,6 +13,7 @@ export declare const defaultStringifySearch: (search: Record<string, any>) => st
|
|
|
11
13
|
* @returns A `parseSearch` function compatible with `Router` options.
|
|
12
14
|
* @link https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization
|
|
13
15
|
*/
|
|
16
|
+
/** Build a parseSearch function using a provided JSON-like parser. */
|
|
14
17
|
export declare function parseSearchWith(parser: (str: string) => any): (searchStr: string) => AnySchema;
|
|
15
18
|
/**
|
|
16
19
|
* Build a `stringifySearch` function using a provided serializer.
|
|
@@ -24,6 +27,7 @@ export declare function parseSearchWith(parser: (str: string) => any): (searchSt
|
|
|
24
27
|
* @returns A `stringifySearch` function compatible with `Router` options.
|
|
25
28
|
* @link https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization
|
|
26
29
|
*/
|
|
30
|
+
/** Build a stringifySearch function using a provided serializer/parser. */
|
|
27
31
|
export declare function stringifySearchWith(stringify: (search: any) => string, parser?: (str: string) => any): (search: Record<string, any>) => string;
|
|
28
32
|
export type SearchSerializer = (searchObj: Record<string, any>) => string;
|
|
29
33
|
export type SearchParser = (searchStr: string) => Record<string, 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\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\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\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":";;;;AAkCO,SAAS,2BAOd,MACyD;AACzD,SAAO;AAKT;AA4GO,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;AAEO,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'\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;;;;"}
|
|
@@ -21,6 +21,10 @@ export interface SerializableExtensions extends DefaultSerializable {
|
|
|
21
21
|
}
|
|
22
22
|
export type Serializable = SerializableExtensions[keyof SerializableExtensions];
|
|
23
23
|
export type UnionizeSerializationAdaptersInput<TAdapters extends ReadonlyArray<AnySerializationAdapter>> = TAdapters[number]['~types']['input'];
|
|
24
|
+
/**
|
|
25
|
+
* Create a strongly-typed serialization adapter for SSR hydration.
|
|
26
|
+
* Use to register custom types with the router serializer.
|
|
27
|
+
*/
|
|
24
28
|
export declare function createSerializationAdapter<TInput = unknown, TOutput = unknown, const TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never = never>(opts: CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters>): SerializationAdapter<TInput, TOutput, TExtendsAdapters>;
|
|
25
29
|
export interface CreateSerializationAdapterOptions<TInput, TOutput, TExtendsAdapters extends ReadonlyArray<AnySerializationAdapter> | never> {
|
|
26
30
|
key: string;
|
|
@@ -57,9 +61,11 @@ export interface SerializationAdapterTypes<TInput, TOutput, TExtendsAdapters ext
|
|
|
57
61
|
extends: TExtendsAdapters;
|
|
58
62
|
}
|
|
59
63
|
export type AnySerializationAdapter = SerializationAdapter<any, any, any>;
|
|
64
|
+
/** Create a Seroval plugin for server-side serialization only. */
|
|
60
65
|
export declare function makeSsrSerovalPlugin(serializationAdapter: AnySerializationAdapter, options: {
|
|
61
66
|
didRun: boolean;
|
|
62
67
|
}): Plugin<any, SerovalNode>;
|
|
68
|
+
/** Create a Seroval plugin for client/server symmetric (de)serialization. */
|
|
63
69
|
export declare function makeSerovalPlugin(serializationAdapter: AnySerializationAdapter): Plugin<any, SerovalNode>;
|
|
64
70
|
export type ValidateSerializableInput<TRegister, T> = ValidateSerializable<T, RegisteredSerializableInput<TRegister>>;
|
|
65
71
|
export type RegisteredSerializableInput<TRegister> = (unknown extends RegisteredSerializationAdapters<TRegister> ? never : RegisteredSerializationAdapters<TRegister> extends ReadonlyArray<AnySerializationAdapter> ? RegisteredSerializationAdapters<TRegister>[number]['~types']['input'] : never) | Serializable;
|
package/dist/esm/defer.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { defaultSerializeError } from './router.js';
|
|
2
|
+
/**
|
|
3
|
+
* Well-known symbol used by {@link defer} to tag a promise with
|
|
4
|
+
* its deferred state. Consumers can read `promise[TSR_DEFERRED_PROMISE]`
|
|
5
|
+
* to access `status`, `data`, or `error`.
|
|
6
|
+
*/
|
|
2
7
|
export declare const TSR_DEFERRED_PROMISE: unique symbol;
|
|
3
8
|
export type DeferredPromiseState<T> = {
|
|
4
9
|
status: 'pending';
|
package/dist/esm/defer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defer.js","sources":["../../src/defer.ts"],"sourcesContent":["import { defaultSerializeError } from './router'\n\nexport const TSR_DEFERRED_PROMISE = Symbol.for('TSR_DEFERRED_PROMISE')\n\nexport type DeferredPromiseState<T> =\n | {\n status: 'pending'\n data?: T\n error?: unknown\n }\n | {\n status: 'success'\n data: T\n }\n | {\n status: 'error'\n data?: T\n error: unknown\n }\n\nexport type DeferredPromise<T> = Promise<T> & {\n [TSR_DEFERRED_PROMISE]: DeferredPromiseState<T>\n}\n\n/**\n * Wrap a promise with a deferred state for use with `<Await>` and `useAwaited`.\n *\n * The returned promise is augmented with internal state (status/data/error)\n * so UI can read progress or suspend until it settles.\n *\n * @param _promise The promise to wrap.\n * @param options Optional config. Provide `serializeError` to customize how\n * errors are serialized for transfer.\n * @returns The same promise with attached deferred metadata.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/deferFunction\n */\nexport function defer<T>(\n _promise: Promise<T>,\n options?: {\n serializeError?: typeof defaultSerializeError\n },\n) {\n const promise = _promise as DeferredPromise<T>\n // this is already deferred promise\n if ((promise as any)[TSR_DEFERRED_PROMISE]) {\n return promise\n }\n promise[TSR_DEFERRED_PROMISE] = { status: 'pending' }\n\n promise\n .then((data) => {\n promise[TSR_DEFERRED_PROMISE].status = 'success'\n promise[TSR_DEFERRED_PROMISE].data = data\n })\n .catch((error) => {\n promise[TSR_DEFERRED_PROMISE].status = 'error'\n ;(promise[TSR_DEFERRED_PROMISE] as any).error = {\n data: (options?.serializeError ?? defaultSerializeError)(error),\n __isServerError: true,\n }\n })\n\n return promise\n}\n"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"defer.js","sources":["../../src/defer.ts"],"sourcesContent":["import { defaultSerializeError } from './router'\n\n/**\n * Well-known symbol used by {@link defer} to tag a promise with\n * its deferred state. Consumers can read `promise[TSR_DEFERRED_PROMISE]`\n * to access `status`, `data`, or `error`.\n */\nexport const TSR_DEFERRED_PROMISE = Symbol.for('TSR_DEFERRED_PROMISE')\n\nexport type DeferredPromiseState<T> =\n | {\n status: 'pending'\n data?: T\n error?: unknown\n }\n | {\n status: 'success'\n data: T\n }\n | {\n status: 'error'\n data?: T\n error: unknown\n }\n\nexport type DeferredPromise<T> = Promise<T> & {\n [TSR_DEFERRED_PROMISE]: DeferredPromiseState<T>\n}\n\n/**\n * Wrap a promise with a deferred state for use with `<Await>` and `useAwaited`.\n *\n * The returned promise is augmented with internal state (status/data/error)\n * so UI can read progress or suspend until it settles.\n *\n * @param _promise The promise to wrap.\n * @param options Optional config. Provide `serializeError` to customize how\n * errors are serialized for transfer.\n * @returns The same promise with attached deferred metadata.\n * @link https://tanstack.com/router/latest/docs/framework/react/api/router/deferFunction\n */\nexport function defer<T>(\n _promise: Promise<T>,\n options?: {\n serializeError?: typeof defaultSerializeError\n },\n) {\n const promise = _promise as DeferredPromise<T>\n // this is already deferred promise\n if ((promise as any)[TSR_DEFERRED_PROMISE]) {\n return promise\n }\n promise[TSR_DEFERRED_PROMISE] = { status: 'pending' }\n\n promise\n .then((data) => {\n promise[TSR_DEFERRED_PROMISE].status = 'success'\n promise[TSR_DEFERRED_PROMISE].data = data\n })\n .catch((error) => {\n promise[TSR_DEFERRED_PROMISE].status = 'error'\n ;(promise[TSR_DEFERRED_PROMISE] as any).error = {\n data: (options?.serializeError ?? defaultSerializeError)(error),\n __isServerError: true,\n }\n })\n\n return promise\n}\n"],"names":[],"mappings":";AAOO,MAAM,uBAAuB,OAAO,IAAI,sBAAsB;AAkC9D,SAAS,MACd,UACA,SAGA;AACA,QAAM,UAAU;AAEhB,MAAK,QAAgB,oBAAoB,GAAG;AAC1C,WAAO;AAAA,EACT;AACA,UAAQ,oBAAoB,IAAI,EAAE,QAAQ,UAAA;AAE1C,UACG,KAAK,CAAC,SAAS;AACd,YAAQ,oBAAoB,EAAE,SAAS;AACvC,YAAQ,oBAAoB,EAAE,OAAO;AAAA,EACvC,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,YAAQ,oBAAoB,EAAE,SAAS;AACrC,YAAQ,oBAAoB,EAAU,QAAQ;AAAA,MAC9C,OAAO,SAAS,kBAAkB,uBAAuB,KAAK;AAAA,MAC9D,iBAAiB;AAAA,IAAA;AAAA,EAErB,CAAC;AAEH,SAAO;AACT;"}
|
package/dist/esm/path.d.ts
CHANGED
|
@@ -12,12 +12,22 @@ export interface Segment {
|
|
|
12
12
|
readonly suffixSegment?: string;
|
|
13
13
|
readonly hasStaticAfter?: boolean;
|
|
14
14
|
}
|
|
15
|
+
/** Join path segments, cleaning duplicate slashes between parts. */
|
|
15
16
|
export declare function joinPaths(paths: Array<string | undefined>): string;
|
|
17
|
+
/** Remove repeated slashes from a path string. */
|
|
16
18
|
export declare function cleanPath(path: string): string;
|
|
19
|
+
/** Trim leading slashes (except preserving root '/'). */
|
|
17
20
|
export declare function trimPathLeft(path: string): string;
|
|
21
|
+
/** Trim trailing slashes (except preserving root '/'). */
|
|
18
22
|
export declare function trimPathRight(path: string): string;
|
|
23
|
+
/** Trim both leading and trailing slashes. */
|
|
19
24
|
export declare function trimPath(path: string): string;
|
|
25
|
+
/** Remove a trailing slash from value when appropriate for comparisons. */
|
|
20
26
|
export declare function removeTrailingSlash(value: string, basepath: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Compare two pathnames for exact equality after normalizing trailing slashes
|
|
29
|
+
* relative to the provided `basepath`.
|
|
30
|
+
*/
|
|
21
31
|
export declare function exactPathTest(pathName1: string, pathName2: string, basepath: string): boolean;
|
|
22
32
|
interface ResolvePathOptions {
|
|
23
33
|
base: string;
|
|
@@ -25,11 +35,17 @@ interface ResolvePathOptions {
|
|
|
25
35
|
trailingSlash?: 'always' | 'never' | 'preserve';
|
|
26
36
|
parseCache?: ParsePathnameCache;
|
|
27
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a destination path against a base, honoring trailing-slash policy
|
|
40
|
+
* and supporting relative segments (`.`/`..`) and absolute `to` values.
|
|
41
|
+
*/
|
|
28
42
|
export declare function resolvePath({ base, to, trailingSlash, parseCache, }: ResolvePathOptions): string;
|
|
29
43
|
export type ParsePathnameCache = LRUCache<string, ReadonlyArray<Segment>>;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Parse a pathname into an array of typed segments used by the router's
|
|
46
|
+
* matcher. Results are optionally cached via an LRU cache.
|
|
47
|
+
*/
|
|
48
|
+
export declare const parsePathname: (pathname?: string, cache?: ParsePathnameCache) => ReadonlyArray<Segment>;
|
|
33
49
|
interface InterpolatePathOptions {
|
|
34
50
|
path?: string;
|
|
35
51
|
params: Record<string, unknown>;
|
|
@@ -43,7 +59,19 @@ type InterPolatePathResult = {
|
|
|
43
59
|
usedParams: Record<string, unknown>;
|
|
44
60
|
isMissingParams: boolean;
|
|
45
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Interpolate params and wildcards into a route path template.
|
|
64
|
+
*
|
|
65
|
+
* - Encodes params safely (configurable allowed characters)
|
|
66
|
+
* - Supports `{-$optional}` segments, `{prefix{$id}suffix}` and `{$}` wildcards
|
|
67
|
+
* - Optionally leaves placeholders or wildcards in place
|
|
68
|
+
*/
|
|
46
69
|
export declare function interpolatePath({ path, params, leaveWildcards, leaveParams, decodeCharMap, parseCache, }: InterpolatePathOptions): InterPolatePathResult;
|
|
70
|
+
/**
|
|
71
|
+
* Match a pathname against a route destination and return extracted params
|
|
72
|
+
* or `undefined`. Uses the same parsing as the router for consistency.
|
|
73
|
+
*/
|
|
47
74
|
export declare function matchPathname(currentPathname: string, matchLocation: Pick<MatchLocation, 'to' | 'fuzzy' | 'caseSensitive'>, parseCache?: ParsePathnameCache): AnyPathParams | undefined;
|
|
75
|
+
/** Low-level matcher that compares two path strings and extracts params. */
|
|
48
76
|
export declare function matchByPath(from: string, { to, fuzzy, caseSensitive, }: Pick<MatchLocation, 'to' | 'caseSensitive' | 'fuzzy'>, parseCache?: ParsePathnameCache): Record<string, string> | undefined;
|
|
49
77
|
export {};
|