@tanstack/router-core 1.132.0-alpha.1 → 1.132.0-alpha.12

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.
Files changed (128) hide show
  1. package/dist/cjs/Matches.cjs.map +1 -1
  2. package/dist/cjs/Matches.d.cts +9 -11
  3. package/dist/cjs/config.cjs +10 -0
  4. package/dist/cjs/config.cjs.map +1 -0
  5. package/dist/cjs/config.d.cts +17 -0
  6. package/dist/cjs/fileRoute.d.cts +3 -2
  7. package/dist/cjs/index.cjs +10 -2
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/index.d.cts +8 -3
  10. package/dist/cjs/load-matches.cjs +636 -0
  11. package/dist/cjs/load-matches.cjs.map +1 -0
  12. package/dist/cjs/load-matches.d.cts +16 -0
  13. package/dist/cjs/qss.cjs +19 -19
  14. package/dist/cjs/qss.cjs.map +1 -1
  15. package/dist/cjs/qss.d.cts +6 -4
  16. package/dist/cjs/redirect.cjs +3 -3
  17. package/dist/cjs/redirect.cjs.map +1 -1
  18. package/dist/cjs/route.cjs.map +1 -1
  19. package/dist/cjs/route.d.cts +42 -41
  20. package/dist/cjs/router.cjs +85 -654
  21. package/dist/cjs/router.cjs.map +1 -1
  22. package/dist/cjs/router.d.cts +19 -23
  23. package/dist/cjs/scroll-restoration.cjs +32 -29
  24. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  25. package/dist/cjs/scroll-restoration.d.cts +1 -10
  26. package/dist/cjs/searchParams.cjs +7 -15
  27. package/dist/cjs/searchParams.cjs.map +1 -1
  28. package/dist/cjs/ssr/constants.cjs +5 -0
  29. package/dist/cjs/ssr/constants.cjs.map +1 -0
  30. package/dist/cjs/ssr/constants.d.cts +1 -0
  31. package/dist/cjs/ssr/{seroval-plugins.cjs → serializer/ShallowErrorPlugin.cjs} +2 -2
  32. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -0
  33. package/dist/cjs/ssr/{seroval-plugins.d.cts → serializer/ShallowErrorPlugin.d.cts} +1 -2
  34. package/dist/cjs/ssr/serializer/seroval-plugins.cjs +11 -0
  35. package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -0
  36. package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -0
  37. package/dist/cjs/ssr/serializer/transformer.cjs +52 -0
  38. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -0
  39. package/dist/cjs/ssr/serializer/transformer.d.cts +56 -0
  40. package/dist/cjs/ssr/server.d.cts +5 -0
  41. package/dist/cjs/ssr/ssr-client.cjs +53 -40
  42. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  43. package/dist/cjs/ssr/ssr-client.d.cts +5 -1
  44. package/dist/cjs/ssr/ssr-server.cjs +12 -10
  45. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  46. package/dist/cjs/ssr/ssr-server.d.cts +0 -1
  47. package/dist/cjs/ssr/tsrScript.cjs +1 -1
  48. package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
  49. package/dist/cjs/typePrimitives.d.cts +6 -6
  50. package/dist/cjs/utils.cjs +14 -7
  51. package/dist/cjs/utils.cjs.map +1 -1
  52. package/dist/cjs/utils.d.cts +2 -1
  53. package/dist/esm/Matches.d.ts +9 -11
  54. package/dist/esm/Matches.js.map +1 -1
  55. package/dist/esm/config.d.ts +17 -0
  56. package/dist/esm/config.js +10 -0
  57. package/dist/esm/config.js.map +1 -0
  58. package/dist/esm/fileRoute.d.ts +3 -2
  59. package/dist/esm/index.d.ts +8 -3
  60. package/dist/esm/index.js +11 -3
  61. package/dist/esm/index.js.map +1 -1
  62. package/dist/esm/load-matches.d.ts +16 -0
  63. package/dist/esm/load-matches.js +636 -0
  64. package/dist/esm/load-matches.js.map +1 -0
  65. package/dist/esm/qss.d.ts +6 -4
  66. package/dist/esm/qss.js +19 -19
  67. package/dist/esm/qss.js.map +1 -1
  68. package/dist/esm/redirect.js +3 -3
  69. package/dist/esm/redirect.js.map +1 -1
  70. package/dist/esm/route.d.ts +42 -41
  71. package/dist/esm/route.js.map +1 -1
  72. package/dist/esm/router.d.ts +19 -23
  73. package/dist/esm/router.js +85 -654
  74. package/dist/esm/router.js.map +1 -1
  75. package/dist/esm/scroll-restoration.d.ts +1 -10
  76. package/dist/esm/scroll-restoration.js +32 -29
  77. package/dist/esm/scroll-restoration.js.map +1 -1
  78. package/dist/esm/searchParams.js +7 -15
  79. package/dist/esm/searchParams.js.map +1 -1
  80. package/dist/esm/ssr/constants.d.ts +1 -0
  81. package/dist/esm/ssr/constants.js +5 -0
  82. package/dist/esm/ssr/constants.js.map +1 -0
  83. package/dist/esm/ssr/{seroval-plugins.d.ts → serializer/ShallowErrorPlugin.d.ts} +1 -2
  84. package/dist/esm/ssr/{seroval-plugins.js → serializer/ShallowErrorPlugin.js} +2 -2
  85. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -0
  86. package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -0
  87. package/dist/esm/ssr/serializer/seroval-plugins.js +11 -0
  88. package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -0
  89. package/dist/esm/ssr/serializer/transformer.d.ts +56 -0
  90. package/dist/esm/ssr/serializer/transformer.js +52 -0
  91. package/dist/esm/ssr/serializer/transformer.js.map +1 -0
  92. package/dist/esm/ssr/server.d.ts +5 -0
  93. package/dist/esm/ssr/ssr-client.d.ts +5 -1
  94. package/dist/esm/ssr/ssr-client.js +53 -40
  95. package/dist/esm/ssr/ssr-client.js.map +1 -1
  96. package/dist/esm/ssr/ssr-server.d.ts +0 -1
  97. package/dist/esm/ssr/ssr-server.js +12 -10
  98. package/dist/esm/ssr/ssr-server.js.map +1 -1
  99. package/dist/esm/ssr/tsrScript.js +1 -1
  100. package/dist/esm/ssr/tsrScript.js.map +1 -1
  101. package/dist/esm/typePrimitives.d.ts +6 -6
  102. package/dist/esm/utils.d.ts +2 -1
  103. package/dist/esm/utils.js +14 -7
  104. package/dist/esm/utils.js.map +1 -1
  105. package/package.json +1 -1
  106. package/src/Matches.ts +18 -10
  107. package/src/config.ts +42 -0
  108. package/src/fileRoute.ts +15 -3
  109. package/src/index.ts +24 -2
  110. package/src/load-matches.ts +955 -0
  111. package/src/qss.ts +27 -24
  112. package/src/redirect.ts +3 -3
  113. package/src/route.ts +146 -35
  114. package/src/router.ts +135 -925
  115. package/src/scroll-restoration.ts +42 -37
  116. package/src/searchParams.ts +8 -19
  117. package/src/ssr/constants.ts +1 -0
  118. package/src/ssr/{seroval-plugins.ts → serializer/ShallowErrorPlugin.ts} +2 -2
  119. package/src/ssr/serializer/seroval-plugins.ts +9 -0
  120. package/src/ssr/serializer/transformer.ts +215 -0
  121. package/src/ssr/server.ts +6 -0
  122. package/src/ssr/ssr-client.ts +72 -44
  123. package/src/ssr/ssr-server.ts +18 -10
  124. package/src/ssr/tsrScript.ts +5 -1
  125. package/src/typePrimitives.ts +6 -6
  126. package/src/utils.ts +21 -10
  127. package/dist/cjs/ssr/seroval-plugins.cjs.map +0 -1
  128. package/dist/esm/ssr/seroval-plugins.js.map +0 -1
@@ -1,18 +1,20 @@
1
1
  import { Store } from '@tanstack/store';
2
+ import { loadRouteChunk } from './load-matches.cjs';
2
3
  import { ParsePathnameCache } from './path.cjs';
3
4
  import { SearchParser, SearchSerializer } from './searchParams.cjs';
4
5
  import { AnyRedirect, ResolvedRedirect } from './redirect.cjs';
5
6
  import { HistoryLocation, HistoryState, ParsedHistoryState, RouterHistory } from '@tanstack/history';
6
- import { Awaitable, ControlledPromise, NoInfer, NonNullableUpdater, PickAsRequired, Updater } from './utils.cjs';
7
+ import { Awaitable, Constrain, ControlledPromise, NoInfer, NonNullableUpdater, PickAsRequired, Updater } from './utils.cjs';
7
8
  import { ParsedLocation } from './location.cjs';
8
9
  import { AnyContext, AnyRoute, AnyRouteWithContext, MakeRemountDepsOptionsUnion, RouteMask } from './route.cjs';
9
10
  import { FullSearchSchema, RouteById, RoutePaths, RoutesById, RoutesByPath } from './routeInfo.cjs';
10
- import { AnyRouteMatch, MakeRouteMatch, MakeRouteMatchUnion, MatchRouteOptions } from './Matches.cjs';
11
+ import { AnyRouteMatch, MakeRouteMatchUnion, MatchRouteOptions } from './Matches.cjs';
11
12
  import { BuildLocationFn, CommitLocationOptions, NavigateFn } from './RouterProvider.cjs';
12
13
  import { Manifest } from './manifest.cjs';
13
14
  import { AnySchema } from './validators.cjs';
14
15
  import { NavigateOptions, ResolveRelativePath, ToOptions } from './link.cjs';
15
- import { NotFoundError } from './not-found.cjs';
16
+ import { AnySerializationAdapter, ValidateSerializableInput } from './ssr/serializer/transformer.cjs';
17
+ import { AnyRouterConfig } from './config.cjs';
16
18
  export type ControllablePromise<T = any> = Promise<T> & {
17
19
  resolve: (value: T) => void;
18
20
  reject: (value?: any) => void;
@@ -20,6 +22,8 @@ export type ControllablePromise<T = any> = Promise<T> & {
20
22
  export type InjectedHtmlEntry = Promise<string>;
21
23
  export interface DefaultRegister {
22
24
  router: AnyRouter;
25
+ config: AnyRouterConfig;
26
+ ssr: SSROption;
23
27
  }
24
28
  export interface Register extends DefaultRegister {
25
29
  }
@@ -29,7 +33,8 @@ export interface DefaultRouterOptionsExtensions {
29
33
  }
30
34
  export interface RouterOptionsExtensions extends DefaultRouterOptionsExtensions {
31
35
  }
32
- export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean = false, TRouterHistory extends RouterHistory = RouterHistory, TDehydrated extends Record<string, any> = Record<string, any>> extends RouterOptionsExtensions {
36
+ export type SSROption = boolean | 'data-only';
37
+ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption extends TrailingSlashOption, TDefaultStructuralSharingOption extends boolean = false, TRouterHistory extends RouterHistory = RouterHistory, TDehydrated = undefined> extends RouterOptionsExtensions {
33
38
  /**
34
39
  * The history object that will be used to manage the browser history.
35
40
  *
@@ -196,7 +201,7 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
196
201
  * @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RouterOptionsType#dehydrate-method)
197
202
  * @link [Guide](https://tanstack.com/router/latest/docs/framework/react/guide/external-data-loading#critical-dehydrationhydration)
198
203
  */
199
- dehydrate?: () => Awaitable<TDehydrated>;
204
+ dehydrate?: () => Constrain<TDehydrated, ValidateSerializableInput<Register, TDehydrated>>;
200
205
  /**
201
206
  * A function that will be called when the router is hydrated.
202
207
  *
@@ -262,7 +267,7 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
262
267
  *
263
268
  * @default true
264
269
  */
265
- defaultSsr?: boolean | 'data-only';
270
+ defaultSsr?: SSROption;
266
271
  search?: {
267
272
  /**
268
273
  * Configures how unknown search params (= not returned by any `validateSearch`) are treated.
@@ -291,7 +296,9 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
291
296
  *
292
297
  * @default false
293
298
  */
294
- scrollRestoration?: boolean;
299
+ scrollRestoration?: boolean | ((opts: {
300
+ location: ParsedLocation;
301
+ }) => boolean);
295
302
  /**
296
303
  * A function that will be called to get the key for the scroll restoration cache.
297
304
  *
@@ -320,6 +327,7 @@ export interface RouterOptions<TRouteTree extends AnyRoute, TTrailingSlashOption
320
327
  * @default false
321
328
  */
322
329
  disableGlobalCatchBoundary?: boolean;
330
+ serializationAdapters?: ReadonlyArray<AnySerializationAdapter>;
323
331
  }
324
332
  export interface RouterState<in out TRouteTree extends AnyRoute = AnyRoute, in out TRouteMatch = MakeRouteMatchUnion> {
325
333
  status: 'pending' | 'idle';
@@ -409,7 +417,7 @@ export type InvalidateFn<TRouter extends AnyRouter> = (opts?: {
409
417
  sync?: boolean;
410
418
  forcePending?: boolean;
411
419
  }) => Promise<void>;
412
- export type ParseLocationFn<TRouteTree extends AnyRoute> = (previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>, locationToParse?: HistoryLocation) => ParsedLocation<FullSearchSchema<TRouteTree>>;
420
+ export type ParseLocationFn<TRouteTree extends AnyRoute> = (locationToParse: HistoryLocation, previousLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>) => ParsedLocation<FullSearchSchema<TRouteTree>>;
413
421
  export type GetMatchRoutesFn = (pathname: string, routePathname: string | undefined) => {
414
422
  matchedRoutes: Array<AnyRoute>;
415
423
  routeParams: Record<string, string>;
@@ -503,7 +511,8 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
503
511
  isShell(): boolean;
504
512
  isPrerendering(): boolean;
505
513
  update: UpdateFn<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>;
506
- get state(): RouterState<TRouteTree, import('./Matches.cjs').RouteMatch<any, any, any, any, any, any, any>>;
514
+ get state(): RouterState<TRouteTree>;
515
+ updateLatestLocation: () => void;
507
516
  buildRouteTree: () => void;
508
517
  subscribe: SubscribeFn;
509
518
  emit: EmitFn;
@@ -528,29 +537,17 @@ export declare class RouterCore<in out TRouteTree extends AnyRoute, in out TTrai
528
537
  startViewTransition: (fn: () => Promise<void>) => void;
529
538
  updateMatch: UpdateMatchFn;
530
539
  getMatch: GetMatchFn;
531
- loadMatches: ({ location, matches, preload: allPreload, onReady, updateMatch, sync, }: {
532
- location: ParsedLocation;
533
- matches: Array<AnyRouteMatch>;
534
- preload?: boolean;
535
- onReady?: () => Promise<void>;
536
- updateMatch?: (id: string, updater: (match: AnyRouteMatch) => AnyRouteMatch) => void;
537
- getMatch?: (matchId: string) => AnyRouteMatch | undefined;
538
- sync?: boolean;
539
- }) => Promise<Array<MakeRouteMatch>>;
540
540
  invalidate: InvalidateFn<RouterCore<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory, TDehydrated>>;
541
541
  resolveRedirect: (redirect: AnyRedirect) => AnyRedirect;
542
542
  clearCache: ClearCacheFn<this>;
543
543
  clearExpiredCache: () => void;
544
- loadRouteChunk: (route: AnyRoute) => Promise<void[]>;
544
+ loadRouteChunk: typeof loadRouteChunk;
545
545
  preloadRoute: PreloadRouteFn<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory>;
546
546
  matchRoute: MatchRouteFn<TRouteTree, TTrailingSlashOption, TDefaultStructuralSharingOption, TRouterHistory>;
547
547
  ssr?: {
548
548
  manifest: Manifest | undefined;
549
549
  };
550
550
  serverSsr?: ServerSsr;
551
- _handleNotFound: (matches: Array<AnyRouteMatch>, err: NotFoundError, { updateMatch, }?: {
552
- updateMatch?: (id: string, updater: (match: AnyRouteMatch) => AnyRouteMatch) => void;
553
- }) => void;
554
551
  hasNotFoundMatch: () => boolean;
555
552
  }
556
553
  export declare class SearchParamError extends Error {
@@ -559,7 +556,6 @@ export declare class PathParamError extends Error {
559
556
  }
560
557
  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]>>>;
561
558
  export declare function getInitialRouterState(location: ParsedLocation): RouterState<any>;
562
- export declare const componentTypes: readonly ["component", "errorComponent", "pendingComponent", "notFoundComponent"];
563
559
  interface RouteLike {
564
560
  id: string;
565
561
  isRoot?: boolean;
@@ -7,7 +7,6 @@ function getSafeSessionStorage() {
7
7
  return window.sessionStorage;
8
8
  }
9
9
  } catch {
10
- return void 0;
11
10
  }
12
11
  return void 0;
13
12
  }
@@ -26,7 +25,7 @@ const throttle = (fn, wait) => {
26
25
  function createScrollRestorationCache() {
27
26
  const safeSessionStorage = getSafeSessionStorage();
28
27
  if (!safeSessionStorage) {
29
- return void 0;
28
+ return null;
30
29
  }
31
30
  const persistedState = safeSessionStorage.getItem(storageKey);
32
31
  let state = persistedState ? JSON.parse(persistedState) : {};
@@ -46,12 +45,12 @@ function getCssSelector(el) {
46
45
  const path = [];
47
46
  let parent;
48
47
  while (parent = el.parentNode) {
49
- path.unshift(
50
- `${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`
48
+ path.push(
49
+ `${el.tagName}:nth-child(${Array.prototype.indexOf.call(parent.children, el) + 1})`
51
50
  );
52
51
  el = parent;
53
52
  }
54
- return `${path.join(" > ")}`.toLowerCase();
53
+ return `${path.reverse().join(" > ")}`.toLowerCase();
55
54
  }
56
55
  let ignoreScroll = false;
57
56
  function restoreScroll({
@@ -69,10 +68,10 @@ function restoreScroll({
69
68
  console.error(error);
70
69
  return;
71
70
  }
72
- const resolvedKey = key || window.history.state?.key;
71
+ const resolvedKey = key || window.history.state?.__TSR_key;
73
72
  const elementEntries = byKey[resolvedKey];
74
73
  ignoreScroll = true;
75
- (() => {
74
+ scroll: {
76
75
  if (shouldScrollRestoration && elementEntries && Object.keys(elementEntries).length > 0) {
77
76
  for (const elementSelector in elementEntries) {
78
77
  const entry = elementEntries[elementSelector];
@@ -90,44 +89,40 @@ function restoreScroll({
90
89
  }
91
90
  }
92
91
  }
93
- return;
92
+ break scroll;
94
93
  }
95
- const hash = (location ?? window.location).hash.split("#")[1];
94
+ const hash = (location ?? window.location).hash.split("#", 2)[1];
96
95
  if (hash) {
97
- const hashScrollIntoViewOptions = (window.history.state || {}).__hashScrollIntoViewOptions ?? true;
96
+ const hashScrollIntoViewOptions = window.history.state?.__hashScrollIntoViewOptions ?? true;
98
97
  if (hashScrollIntoViewOptions) {
99
98
  const el = document.getElementById(hash);
100
99
  if (el) {
101
100
  el.scrollIntoView(hashScrollIntoViewOptions);
102
101
  }
103
102
  }
104
- return;
103
+ break scroll;
105
104
  }
106
- [
107
- "window",
108
- ...scrollToTopSelectors?.filter((d) => d !== "window") ?? []
109
- ].forEach((selector) => {
110
- const element = selector === "window" ? window : typeof selector === "function" ? selector() : document.querySelector(selector);
111
- if (element) {
112
- element.scrollTo({
113
- top: 0,
114
- left: 0,
115
- behavior
116
- });
105
+ const scrollOptions = { top: 0, left: 0, behavior };
106
+ window.scrollTo(scrollOptions);
107
+ if (scrollToTopSelectors) {
108
+ for (const selector of scrollToTopSelectors) {
109
+ if (selector === "window") continue;
110
+ const element = typeof selector === "function" ? selector() : document.querySelector(selector);
111
+ if (element) element.scrollTo(scrollOptions);
117
112
  }
118
- });
119
- })();
113
+ }
114
+ }
120
115
  ignoreScroll = false;
121
116
  }
122
117
  function setupScrollRestoration(router, force) {
123
- if (scrollRestorationCache === void 0) {
118
+ if (!scrollRestorationCache && !router.isServer) {
124
119
  return;
125
120
  }
126
121
  const shouldScrollRestoration = force ?? router.options.scrollRestoration ?? false;
127
122
  if (shouldScrollRestoration) {
128
123
  router.isScrollRestoring = true;
129
124
  }
130
- if (typeof document === "undefined" || router.isScrollRestorationSetup) {
125
+ if (router.isServer || router.isScrollRestorationSetup || !scrollRestorationCache) {
131
126
  return;
132
127
  }
133
128
  router.isScrollRestorationSetup = true;
@@ -153,8 +148,8 @@ function setupScrollRestoration(router, force) {
153
148
  }
154
149
  const restoreKey = getKey(router.state.location);
155
150
  scrollRestorationCache.set((state) => {
156
- const keyEntry = state[restoreKey] = state[restoreKey] || {};
157
- const elementEntry = keyEntry[elementSelector] = keyEntry[elementSelector] || {};
151
+ const keyEntry = state[restoreKey] ||= {};
152
+ const elementEntry = keyEntry[elementSelector] ||= {};
158
153
  if (elementSelector === "window") {
159
154
  elementEntry.scrollX = window.scrollX || 0;
160
155
  elementEntry.scrollY = window.scrollY || 0;
@@ -177,6 +172,14 @@ function setupScrollRestoration(router, force) {
177
172
  router.resetNextScroll = true;
178
173
  return;
179
174
  }
175
+ if (typeof router.options.scrollRestoration === "function") {
176
+ const shouldRestore = router.options.scrollRestoration({
177
+ location: router.latestLocation
178
+ });
179
+ if (!shouldRestore) {
180
+ return;
181
+ }
182
+ }
180
183
  restoreScroll({
181
184
  storageKey,
182
185
  key: cacheKey,
@@ -187,7 +190,7 @@ function setupScrollRestoration(router, force) {
187
190
  });
188
191
  if (router.isScrollRestoring) {
189
192
  scrollRestorationCache.set((state) => {
190
- state[cacheKey] = state[cacheKey] || {};
193
+ state[cacheKey] ||= {};
191
194
  return state;
192
195
  });
193
196
  }
@@ -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 return undefined\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 | undefined {\n const safeSessionStorage = getSafeSessionStorage()\n if (!safeSessionStorage) {\n return undefined\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\n while ((parent = el.parentNode)) {\n path.unshift(\n `${el.tagName}:nth-child(${([].indexOf as any).call(parent.children, el) + 1})`,\n )\n el = parent\n }\n return `${path.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: any) {\n console.error(error)\n return\n }\n\n const resolvedKey = key || window.history.state?.key\n const elementEntries = byKey[resolvedKey]\n\n //\n ignoreScroll = true\n\n //\n ;(() => {\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 return\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('#')[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 return\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 ;[\n 'window',\n ...(scrollToTopSelectors?.filter((d) => d !== 'window') ?? []),\n ].forEach((selector) => {\n const element =\n selector === 'window'\n ? window\n : typeof selector === 'function'\n ? selector()\n : document.querySelector(selector)\n if (element) {\n element.scrollTo({\n top: 0,\n left: 0,\n behavior,\n })\n }\n })\n })()\n\n //\n ignoreScroll = false\n}\n\nexport function setupScrollRestoration(router: AnyRouter, force?: boolean) {\n if (scrollRestorationCache === undefined) {\n return\n }\n const shouldScrollRestoration =\n force ?? router.options.scrollRestoration ?? false\n\n if (shouldScrollRestoration) {\n router.isScrollRestoring = true\n }\n\n if (typeof document === 'undefined' || router.isScrollRestorationSetup) {\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] =\n state[restoreKey] || ({} as ScrollRestorationByElement))\n\n const elementEntry = (keyEntry[elementSelector] =\n keyEntry[elementSelector] || ({} 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\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] = state[cacheKey] || ({} as ScrollRestorationByElement)\n\n return state\n })\n }\n })\n}\n\n/**\n * @internal\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\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 * @internal\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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"}
@@ -17,7 +17,7 @@ export type ScrollRestorationOptions = {
17
17
  scrollBehavior?: ScrollToOptions['behavior'];
18
18
  };
19
19
  export declare const storageKey = "tsr-scroll-restoration-v1_3";
20
- export declare const scrollRestorationCache: ScrollRestorationCache | undefined;
20
+ export declare const scrollRestorationCache: ScrollRestorationCache | null;
21
21
  /**
22
22
  * The default `getKey` function for `useScrollRestoration`.
23
23
  * It returns the `key` from the location state or the `href` of the location.
@@ -35,12 +35,3 @@ export declare function restoreScroll({ storageKey, key, behavior, shouldScrollR
35
35
  location?: HistoryLocation;
36
36
  }): void;
37
37
  export declare function setupScrollRestoration(router: AnyRouter, force?: boolean): void;
38
- /**
39
- * @internal
40
- * Handles hash-based scrolling after navigation completes.
41
- * To be used in framework-specific <Transitioner> components during the onResolved event.
42
- *
43
- * Provides hash scrolling for programmatic navigation when default browser handling is prevented.
44
- * @param router The router instance containing current location and state
45
- */
46
- export declare function handleHashScroll(router: AnyRouter): void;
@@ -8,7 +8,7 @@ const defaultStringifySearch = stringifySearchWith(
8
8
  );
9
9
  function parseSearchWith(parser) {
10
10
  return (searchStr) => {
11
- if (searchStr.substring(0, 1) === "?") {
11
+ if (searchStr[0] === "?") {
12
12
  searchStr = searchStr.substring(1);
13
13
  }
14
14
  const query = qss.decode(searchStr);
@@ -17,7 +17,7 @@ function parseSearchWith(parser) {
17
17
  if (typeof value === "string") {
18
18
  try {
19
19
  query[key] = parser(value);
20
- } catch (err) {
20
+ } catch (_err) {
21
21
  }
22
22
  }
23
23
  }
@@ -25,32 +25,24 @@ function parseSearchWith(parser) {
25
25
  };
26
26
  }
27
27
  function stringifySearchWith(stringify, parser) {
28
+ const hasParser = typeof parser === "function";
28
29
  function stringifyValue(val) {
29
30
  if (typeof val === "object" && val !== null) {
30
31
  try {
31
32
  return stringify(val);
32
- } catch (err) {
33
+ } catch (_err) {
33
34
  }
34
- } else if (typeof val === "string" && typeof parser === "function") {
35
+ } else if (hasParser && typeof val === "string") {
35
36
  try {
36
37
  parser(val);
37
38
  return stringify(val);
38
- } catch (err) {
39
+ } catch (_err) {
39
40
  }
40
41
  }
41
42
  return val;
42
43
  }
43
44
  return (search) => {
44
- search = { ...search };
45
- Object.keys(search).forEach((key) => {
46
- const val = search[key];
47
- if (typeof val === "undefined" || val === void 0) {
48
- delete search[key];
49
- } else {
50
- search[key] = stringifyValue(val);
51
- }
52
- });
53
- const searchStr = qss.encode(search).toString();
45
+ const searchStr = qss.encode(search, stringifyValue);
54
46
  return searchStr ? `?${searchStr}` : "";
55
47
  };
56
48
  }
@@ -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\nexport function parseSearchWith(parser: (str: string) => any) {\n return (searchStr: string): AnySchema => {\n if (searchStr.substring(0, 1) === '?') {\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 //\n }\n }\n }\n\n return query\n }\n}\n\nexport function stringifySearchWith(\n stringify: (search: any) => string,\n parser?: (str: string) => any,\n) {\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 (typeof val === 'string' && typeof parser === 'function') {\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 search = { ...search }\n\n Object.keys(search).forEach((key) => {\n const val = search[key]\n if (typeof val === 'undefined' || val === undefined) {\n delete search[key]\n } else {\n search[key] = stringifyValue(val)\n }\n })\n\n const searchStr = encode(search as Record<string, string>).toString()\n\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":";;;AAGO,MAAM,qBAAqB,gBAAgB,KAAK,KAAK;AACrD,MAAM,yBAAyB;AAAA,EACpC,KAAK;AAAA,EACL,KAAK;AACP;AAEO,SAAS,gBAAgB,QAA8B;AAC5D,SAAO,CAAC,cAAiC;AACvC,QAAI,UAAU,UAAU,GAAG,CAAC,MAAM,KAAK;AACrC,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,KAAK;AAAA,QAEd;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,oBACd,WACA,QACA;AACA,WAAS,eAAe,KAAU;AAChC,QAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,UAAI;AACF,eAAO,UAAU,GAAG;AAAA,MACtB,SAAS,KAAK;AAAA,MAEd;AAAA,IACF,WAAW,OAAO,QAAQ,YAAY,OAAO,WAAW,YAAY;AAClE,UAAI;AAGF,eAAO,GAAG;AACV,eAAO,UAAU,GAAG;AAAA,MACtB,SAAS,KAAK;AAAA,MAEd;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO,CAAC,WAAgC;AACtC,aAAS,EAAE,GAAG,OAAA;AAEd,WAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,QAAQ;AACnC,YAAM,MAAM,OAAO,GAAG;AACtB,UAAI,OAAO,QAAQ,eAAe,QAAQ,QAAW;AACnD,eAAO,OAAO,GAAG;AAAA,MACnB,OAAO;AACL,eAAO,GAAG,IAAI,eAAe,GAAG;AAAA,MAClC;AAAA,IACF,CAAC;AAED,UAAM,YAAYC,IAAAA,OAAO,MAAgC,EAAE,SAAA;AAE3D,WAAO,YAAY,IAAI,SAAS,KAAK;AAAA,EACvC;AACF;;;;;"}
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\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\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":";;;AAGO,MAAM,qBAAqB,gBAAgB,KAAK,KAAK;AACrD,MAAM,yBAAyB;AAAA,EACpC,KAAK;AAAA,EACL,KAAK;AACP;AAEO,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;;;;;"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const GLOBAL_TSR = "$_TSR";
4
+ exports.GLOBAL_TSR = GLOBAL_TSR;
5
+ //# sourceMappingURL=constants.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.cjs","sources":["../../../src/ssr/constants.ts"],"sourcesContent":["export const GLOBAL_TSR = '$_TSR'\n"],"names":[],"mappings":";;AAAO,MAAM,aAAa;;"}
@@ -0,0 +1 @@
1
+ export declare const GLOBAL_TSR = "$_TSR";
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const seroval = require("seroval");
4
4
  const ShallowErrorPlugin = /* @__PURE__ */ seroval.createPlugin({
5
- tag: "tanstack-start:seroval-plugins/Error",
5
+ tag: "$TSR/Error",
6
6
  test(value) {
7
7
  return value instanceof Error;
8
8
  },
@@ -31,4 +31,4 @@ const ShallowErrorPlugin = /* @__PURE__ */ seroval.createPlugin({
31
31
  }
32
32
  });
33
33
  exports.ShallowErrorPlugin = ShallowErrorPlugin;
34
- //# sourceMappingURL=seroval-plugins.cjs.map
34
+ //# sourceMappingURL=ShallowErrorPlugin.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShallowErrorPlugin.cjs","sources":["../../../../src/ssr/serializer/ShallowErrorPlugin.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport type { SerovalNode } from 'seroval'\n\nexport interface ErrorNode {\n message: SerovalNode\n}\n\n/**\n * this plugin serializes only the `message` part of an Error\n * this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized\n */\nexport const ShallowErrorPlugin = /* @__PURE__ */ createPlugin<\n Error,\n ErrorNode\n>({\n tag: '$TSR/Error',\n test(value) {\n return value instanceof Error\n },\n parse: {\n sync(value, ctx) {\n return {\n message: ctx.parse(value.message),\n }\n },\n async async(value, ctx) {\n return {\n message: await ctx.parse(value.message),\n }\n },\n stream(value, ctx) {\n return {\n message: ctx.parse(value.message),\n }\n },\n },\n serialize(node, ctx) {\n return 'new Error(' + ctx.serialize(node.message) + ')'\n },\n deserialize(node, ctx) {\n return new Error(ctx.deserialize(node.message) as string)\n },\n})\n"],"names":["createPlugin"],"mappings":";;;AAWO,MAAM,qBAAqCA,wBAAAA,aAGhD;AAAA,EACA,KAAK;AAAA,EACL,KAAK,OAAO;AACV,WAAO,iBAAiB;AAAA,EAC1B;AAAA,EACA,OAAO;AAAA,IACL,KAAK,OAAO,KAAK;AACf,aAAO;AAAA,QACL,SAAS,IAAI,MAAM,MAAM,OAAO;AAAA,MAAA;AAAA,IAEpC;AAAA,IACA,MAAM,MAAM,OAAO,KAAK;AACtB,aAAO;AAAA,QACL,SAAS,MAAM,IAAI,MAAM,MAAM,OAAO;AAAA,MAAA;AAAA,IAE1C;AAAA,IACA,OAAO,OAAO,KAAK;AACjB,aAAO;AAAA,QACL,SAAS,IAAI,MAAM,MAAM,OAAO;AAAA,MAAA;AAAA,IAEpC;AAAA,EAAA;AAAA,EAEF,UAAU,MAAM,KAAK;AACnB,WAAO,eAAe,IAAI,UAAU,KAAK,OAAO,IAAI;AAAA,EACtD;AAAA,EACA,YAAY,MAAM,KAAK;AACrB,WAAO,IAAI,MAAM,IAAI,YAAY,KAAK,OAAO,CAAW;AAAA,EAC1D;AACF,CAAC;;"}
@@ -1,5 +1,5 @@
1
1
  import { SerovalNode } from 'seroval';
2
- interface ErrorNode {
2
+ export interface ErrorNode {
3
3
  message: SerovalNode;
4
4
  }
5
5
  /**
@@ -7,4 +7,3 @@ interface ErrorNode {
7
7
  * this helps with serializing e.g. a ZodError which has functions attached that cannot be serialized
8
8
  */
9
9
  export declare const ShallowErrorPlugin: import('seroval').Plugin<Error, ErrorNode>;
10
- export {};
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const web = require("seroval-plugins/web");
4
+ const ShallowErrorPlugin = require("./ShallowErrorPlugin.cjs");
5
+ const defaultSerovalPlugins = [
6
+ ShallowErrorPlugin.ShallowErrorPlugin,
7
+ // ReadableStreamNode is not exported by seroval
8
+ web.ReadableStreamPlugin
9
+ ];
10
+ exports.defaultSerovalPlugins = defaultSerovalPlugins;
11
+ //# sourceMappingURL=seroval-plugins.cjs.map
@@ -0,0 +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":";;;;AAIO,MAAM,wBAAwB;AAAA,EACnCA,mBAAAA;AAAAA;AAAAA,EAEAC,IAAAA;AACF;;"}
@@ -0,0 +1,2 @@
1
+ import { Plugin } from 'seroval';
2
+ export declare const defaultSerovalPlugins: (Plugin<Error, any> | Plugin<ReadableStream<any>, any>)[];
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const seroval = require("seroval");
4
+ const constants = require("../constants.cjs");
5
+ function createSerializationAdapter(opts) {
6
+ return opts;
7
+ }
8
+ function makeSsrSerovalPlugin(serializationAdapter, options) {
9
+ return seroval.createPlugin({
10
+ tag: "$TSR/t/" + serializationAdapter.key,
11
+ test: serializationAdapter.test,
12
+ parse: {
13
+ stream(value, ctx) {
14
+ return ctx.parse(serializationAdapter.toSerializable(value));
15
+ }
16
+ },
17
+ serialize(node, ctx) {
18
+ options.didRun = true;
19
+ return constants.GLOBAL_TSR + '.t.get("' + serializationAdapter.key + '")(' + ctx.serialize(node) + ")";
20
+ },
21
+ // we never deserialize on the server during SSR
22
+ deserialize: void 0
23
+ });
24
+ }
25
+ function makeSerovalPlugin(serializationAdapter) {
26
+ return seroval.createPlugin({
27
+ tag: "$TSR/t/" + serializationAdapter.key,
28
+ test: serializationAdapter.test,
29
+ parse: {
30
+ sync(value, ctx) {
31
+ return ctx.parse(serializationAdapter.toSerializable(value));
32
+ },
33
+ async async(value, ctx) {
34
+ return await ctx.parse(serializationAdapter.toSerializable(value));
35
+ },
36
+ stream(value, ctx) {
37
+ return ctx.parse(serializationAdapter.toSerializable(value));
38
+ }
39
+ },
40
+ // we don't generate JS code outside of SSR (for now)
41
+ serialize: void 0,
42
+ deserialize(node, ctx) {
43
+ return serializationAdapter.fromSerializable(
44
+ ctx.deserialize(node)
45
+ );
46
+ }
47
+ });
48
+ }
49
+ exports.createSerializationAdapter = createSerializationAdapter;
50
+ exports.makeSerovalPlugin = makeSerovalPlugin;
51
+ exports.makeSsrSerovalPlugin = makeSsrSerovalPlugin;
52
+ //# sourceMappingURL=transformer.cjs.map
@@ -0,0 +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 { Register, SSROption } from '../../router'\nimport type { LooseReturnType } from '../../utils'\nimport type { AnyRoute, ResolveAllSSR } from '../../route'\n\nexport type Serializable =\n | number\n | string\n | boolean\n | null\n | undefined\n | bigint\n | Date\n\nexport function createSerializationAdapter<\n TInput = unknown,\n TOutput = unknown /* we need to check that this type is actually serializable taking into account all seroval native types and any custom plugin WE=router/start add!!! */,\n>(\n opts: CreateSerializationAdapterOptions<TInput, TOutput>,\n): SerializationAdapter<TInput, TOutput> {\n return opts as unknown as SerializationAdapter<TInput, TOutput>\n}\n\nexport interface CreateSerializationAdapterOptions<TInput, TOutput> {\n key: string\n test: (value: unknown) => value is TInput\n toSerializable: (value: TInput) => ValidateSerializable<TOutput, Serializable>\n fromSerializable: (value: TOutput) => TInput\n}\n\nexport type ValidateSerializable<T, TSerializable> = 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 : {\n [K in keyof T]: ValidateSerializable<T[K], TSerializable>\n }\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<TInput, TOutput> {\n '~types': SerializationAdapterTypes<TInput, TOutput>\n key: string\n test: (value: unknown) => value is TInput\n toSerializable: (value: TInput) => TOutput\n fromSerializable: (value: TOutput) => TInput\n makePlugin: (options: { didRun: boolean }) => Plugin<TInput, SerovalNode>\n}\n\nexport interface SerializationAdapterTypes<TInput, TOutput> {\n input: TInput\n output: TOutput\n}\n\nexport type AnySerializationAdapter = SerializationAdapter<any, any>\n\nexport function makeSsrSerovalPlugin<TInput, TOutput>(\n serializationAdapter: SerializationAdapter<TInput, TOutput>,\n options: { didRun: boolean },\n) {\n return createPlugin<TInput, 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<TInput, TOutput>(\n serializationAdapter: SerializationAdapter<TInput, TOutput>,\n) {\n return createPlugin<TInput, 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(\n ctx.deserialize(node) as TOutput,\n )\n },\n })\n}\n\nexport type ValidateSerializableInput<\n TRegister extends Register,\n T,\n> = ValidateSerializable<T, RegisteredSerializableInput<TRegister>>\n\nexport type RegisteredSerializableInput<TRegister extends Register> =\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 extends Register> =\n TRegister['config']['~types']['serializationAdapters']\n\nexport type ValidateSerializableInputResult<\n TRegister extends Register,\n T,\n> = ValidateSerializableResult<T, RegisteredSerializableInput<TRegister>>\n\nexport type ValidateSerializableResult<T, TSerializable> =\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 extends Register> =\n unknown extends TRegister['config']['~types']['defaultSsr']\n ? SSROption\n : TRegister['config']['~types']['defaultSsr']\n\nexport type ValidateSerializableLifecycleResult<\n TRegister extends Register,\n TParentRoute extends AnyRoute,\n TSSR,\n TFn,\n> = false extends TRegister['ssr']\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 extends Register,\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"],"names":["createPlugin","GLOBAL_TSR"],"mappings":";;;;AAgBO,SAAS,2BAId,MACuC;AACvC,SAAO;AACT;AA2EO,SAAS,qBACd,sBACA,SACA;AACA,SAAOA,qBAAkC;AAAA,IACvC,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,sBACA;AACA,SAAOD,qBAAkC;AAAA,IACvC,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;AAAA,QAC1B,IAAI,YAAY,IAAI;AAAA,MAAA;AAAA,IAExB;AAAA,EAAA,CACD;AACH;;;;"}