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

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 (145) 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 +15 -3
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/index.d.cts +11 -4
  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/location.d.cts +38 -0
  14. package/dist/cjs/path.cjs +6 -49
  15. package/dist/cjs/path.cjs.map +1 -1
  16. package/dist/cjs/path.d.cts +3 -6
  17. package/dist/cjs/qss.cjs +19 -19
  18. package/dist/cjs/qss.cjs.map +1 -1
  19. package/dist/cjs/qss.d.cts +6 -4
  20. package/dist/cjs/redirect.cjs +3 -3
  21. package/dist/cjs/redirect.cjs.map +1 -1
  22. package/dist/cjs/rewrite.cjs +63 -0
  23. package/dist/cjs/rewrite.cjs.map +1 -0
  24. package/dist/cjs/rewrite.d.cts +22 -0
  25. package/dist/cjs/route.cjs.map +1 -1
  26. package/dist/cjs/route.d.cts +42 -41
  27. package/dist/cjs/router.cjs +134 -681
  28. package/dist/cjs/router.cjs.map +1 -1
  29. package/dist/cjs/router.d.cts +68 -25
  30. package/dist/cjs/scroll-restoration.cjs +32 -29
  31. package/dist/cjs/scroll-restoration.cjs.map +1 -1
  32. package/dist/cjs/scroll-restoration.d.cts +1 -10
  33. package/dist/cjs/searchParams.cjs +7 -15
  34. package/dist/cjs/searchParams.cjs.map +1 -1
  35. package/dist/cjs/ssr/constants.cjs +5 -0
  36. package/dist/cjs/ssr/constants.cjs.map +1 -0
  37. package/dist/cjs/ssr/constants.d.cts +1 -0
  38. package/dist/cjs/ssr/{seroval-plugins.cjs → serializer/ShallowErrorPlugin.cjs} +2 -2
  39. package/dist/cjs/ssr/serializer/ShallowErrorPlugin.cjs.map +1 -0
  40. package/dist/cjs/ssr/{seroval-plugins.d.cts → serializer/ShallowErrorPlugin.d.cts} +1 -2
  41. package/dist/cjs/ssr/serializer/seroval-plugins.cjs +11 -0
  42. package/dist/cjs/ssr/serializer/seroval-plugins.cjs.map +1 -0
  43. package/dist/cjs/ssr/serializer/seroval-plugins.d.cts +2 -0
  44. package/dist/cjs/ssr/serializer/transformer.cjs +52 -0
  45. package/dist/cjs/ssr/serializer/transformer.cjs.map +1 -0
  46. package/dist/cjs/ssr/serializer/transformer.d.cts +56 -0
  47. package/dist/cjs/ssr/server.d.cts +5 -0
  48. package/dist/cjs/ssr/ssr-client.cjs +53 -40
  49. package/dist/cjs/ssr/ssr-client.cjs.map +1 -1
  50. package/dist/cjs/ssr/ssr-client.d.cts +5 -1
  51. package/dist/cjs/ssr/ssr-server.cjs +12 -10
  52. package/dist/cjs/ssr/ssr-server.cjs.map +1 -1
  53. package/dist/cjs/ssr/ssr-server.d.cts +0 -1
  54. package/dist/cjs/ssr/tsrScript.cjs +1 -1
  55. package/dist/cjs/ssr/tsrScript.cjs.map +1 -1
  56. package/dist/cjs/typePrimitives.d.cts +6 -6
  57. package/dist/cjs/utils.cjs +14 -7
  58. package/dist/cjs/utils.cjs.map +1 -1
  59. package/dist/cjs/utils.d.cts +2 -1
  60. package/dist/esm/Matches.d.ts +9 -11
  61. package/dist/esm/Matches.js.map +1 -1
  62. package/dist/esm/config.d.ts +17 -0
  63. package/dist/esm/config.js +10 -0
  64. package/dist/esm/config.js.map +1 -0
  65. package/dist/esm/fileRoute.d.ts +3 -2
  66. package/dist/esm/index.d.ts +11 -4
  67. package/dist/esm/index.js +17 -5
  68. package/dist/esm/index.js.map +1 -1
  69. package/dist/esm/load-matches.d.ts +16 -0
  70. package/dist/esm/load-matches.js +636 -0
  71. package/dist/esm/load-matches.js.map +1 -0
  72. package/dist/esm/location.d.ts +38 -0
  73. package/dist/esm/path.d.ts +3 -6
  74. package/dist/esm/path.js +6 -49
  75. package/dist/esm/path.js.map +1 -1
  76. package/dist/esm/qss.d.ts +6 -4
  77. package/dist/esm/qss.js +19 -19
  78. package/dist/esm/qss.js.map +1 -1
  79. package/dist/esm/redirect.js +3 -3
  80. package/dist/esm/redirect.js.map +1 -1
  81. package/dist/esm/rewrite.d.ts +22 -0
  82. package/dist/esm/rewrite.js +63 -0
  83. package/dist/esm/rewrite.js.map +1 -0
  84. package/dist/esm/route.d.ts +42 -41
  85. package/dist/esm/route.js.map +1 -1
  86. package/dist/esm/router.d.ts +68 -25
  87. package/dist/esm/router.js +136 -683
  88. package/dist/esm/router.js.map +1 -1
  89. package/dist/esm/scroll-restoration.d.ts +1 -10
  90. package/dist/esm/scroll-restoration.js +32 -29
  91. package/dist/esm/scroll-restoration.js.map +1 -1
  92. package/dist/esm/searchParams.js +7 -15
  93. package/dist/esm/searchParams.js.map +1 -1
  94. package/dist/esm/ssr/constants.d.ts +1 -0
  95. package/dist/esm/ssr/constants.js +5 -0
  96. package/dist/esm/ssr/constants.js.map +1 -0
  97. package/dist/esm/ssr/{seroval-plugins.d.ts → serializer/ShallowErrorPlugin.d.ts} +1 -2
  98. package/dist/esm/ssr/{seroval-plugins.js → serializer/ShallowErrorPlugin.js} +2 -2
  99. package/dist/esm/ssr/serializer/ShallowErrorPlugin.js.map +1 -0
  100. package/dist/esm/ssr/serializer/seroval-plugins.d.ts +2 -0
  101. package/dist/esm/ssr/serializer/seroval-plugins.js +11 -0
  102. package/dist/esm/ssr/serializer/seroval-plugins.js.map +1 -0
  103. package/dist/esm/ssr/serializer/transformer.d.ts +56 -0
  104. package/dist/esm/ssr/serializer/transformer.js +52 -0
  105. package/dist/esm/ssr/serializer/transformer.js.map +1 -0
  106. package/dist/esm/ssr/server.d.ts +5 -0
  107. package/dist/esm/ssr/ssr-client.d.ts +5 -1
  108. package/dist/esm/ssr/ssr-client.js +53 -40
  109. package/dist/esm/ssr/ssr-client.js.map +1 -1
  110. package/dist/esm/ssr/ssr-server.d.ts +0 -1
  111. package/dist/esm/ssr/ssr-server.js +12 -10
  112. package/dist/esm/ssr/ssr-server.js.map +1 -1
  113. package/dist/esm/ssr/tsrScript.js +1 -1
  114. package/dist/esm/ssr/tsrScript.js.map +1 -1
  115. package/dist/esm/typePrimitives.d.ts +6 -6
  116. package/dist/esm/utils.d.ts +2 -1
  117. package/dist/esm/utils.js +14 -7
  118. package/dist/esm/utils.js.map +1 -1
  119. package/package.json +1 -1
  120. package/src/Matches.ts +18 -10
  121. package/src/config.ts +42 -0
  122. package/src/fileRoute.ts +15 -3
  123. package/src/index.ts +32 -3
  124. package/src/load-matches.ts +955 -0
  125. package/src/location.ts +38 -0
  126. package/src/path.ts +5 -66
  127. package/src/qss.ts +27 -24
  128. package/src/redirect.ts +3 -3
  129. package/src/rewrite.ts +70 -0
  130. package/src/route.ts +146 -35
  131. package/src/router.ts +263 -972
  132. package/src/scroll-restoration.ts +42 -37
  133. package/src/searchParams.ts +8 -19
  134. package/src/ssr/constants.ts +1 -0
  135. package/src/ssr/{seroval-plugins.ts → serializer/ShallowErrorPlugin.ts} +2 -2
  136. package/src/ssr/serializer/seroval-plugins.ts +9 -0
  137. package/src/ssr/serializer/transformer.ts +215 -0
  138. package/src/ssr/server.ts +6 -0
  139. package/src/ssr/ssr-client.ts +72 -44
  140. package/src/ssr/ssr-server.ts +18 -10
  141. package/src/ssr/tsrScript.ts +5 -1
  142. package/src/typePrimitives.ts +6 -6
  143. package/src/utils.ts +21 -10
  144. package/dist/cjs/ssr/seroval-plugins.cjs.map +0 -1
  145. package/dist/esm/ssr/seroval-plugins.js.map +0 -1
@@ -5,7 +5,8 @@ import type { AnyRouteMatch, MakeRouteMatch } from '../Matches'
5
5
  import type { AnyRouter } from '../router'
6
6
  import type { Manifest } from '../manifest'
7
7
  import type { RouteContextOptions } from '../route'
8
- import type { GLOBAL_TSR } from './ssr-server'
8
+ import type { AnySerializationAdapter } from './serializer/transformer'
9
+ import type { GLOBAL_TSR } from './constants'
9
10
 
10
11
  declare global {
11
12
  interface Window {
@@ -15,22 +16,28 @@ declare global {
15
16
 
16
17
  export interface TsrSsrGlobal {
17
18
  router?: DehydratedRouter
18
- // clean scripts, shortened since this is sent for each streamed script
19
+ // clean scripts; shortened since this is sent for each streamed script
19
20
  c: () => void
21
+ // push script into buffer; shortened since this is sent for each streamed script as soon as the first custom transformer was invoked
22
+ p: (script: () => void) => void
23
+ buffer: Array<() => void>
24
+ // custom transformers, shortened since this is sent for each streamed value that needs a custom transformer
25
+ t?: Map<string, (value: any) => any>
26
+ // this flag indicates whether the transformers were initialized
27
+ initialized?: boolean
20
28
  }
21
29
 
22
30
  function hydrateMatch(
31
+ match: AnyRouteMatch,
23
32
  deyhydratedMatch: DehydratedMatch,
24
- ): Partial<MakeRouteMatch> {
25
- return {
26
- id: deyhydratedMatch.i,
27
- __beforeLoadContext: deyhydratedMatch.b,
28
- loaderData: deyhydratedMatch.l,
29
- status: deyhydratedMatch.s,
30
- ssr: deyhydratedMatch.ssr,
31
- updatedAt: deyhydratedMatch.u,
32
- error: deyhydratedMatch.e,
33
- }
33
+ ): void {
34
+ match.id = deyhydratedMatch.i
35
+ match.__beforeLoadContext = deyhydratedMatch.b
36
+ match.loaderData = deyhydratedMatch.l
37
+ match.status = deyhydratedMatch.s
38
+ match.ssr = deyhydratedMatch.ssr
39
+ match.updatedAt = deyhydratedMatch.u
40
+ match.error = deyhydratedMatch.e
34
41
  }
35
42
  export interface DehydratedMatch {
36
43
  i: MakeRouteMatch['id']
@@ -51,7 +58,26 @@ export interface DehydratedRouter {
51
58
 
52
59
  export async function hydrate(router: AnyRouter): Promise<any> {
53
60
  invariant(
54
- window.$_TSR?.router,
61
+ window.$_TSR,
62
+ 'Expected to find bootstrap data on window.$_TSR, but we did not. Please file an issue!',
63
+ )
64
+
65
+ const serializationAdapters = router.options.serializationAdapters as
66
+ | Array<AnySerializationAdapter>
67
+ | undefined
68
+
69
+ if (serializationAdapters?.length) {
70
+ const fromSerializableMap = new Map()
71
+ serializationAdapters.forEach((adapter) => {
72
+ fromSerializableMap.set(adapter.key, adapter.fromSerializable)
73
+ })
74
+ window.$_TSR.t = fromSerializableMap
75
+ window.$_TSR.buffer.forEach((script) => script())
76
+ }
77
+ window.$_TSR.initialized = true
78
+
79
+ invariant(
80
+ window.$_TSR.router,
55
81
  'Expected to find a dehydrated data on window.$_TSR.router, but we did not. Please file an issue!',
56
82
  )
57
83
 
@@ -80,17 +106,19 @@ export async function hydrate(router: AnyRouter): Promise<any> {
80
106
  route.options.pendingMinMs ?? router.options.defaultPendingMinMs
81
107
  if (pendingMinMs) {
82
108
  const minPendingPromise = createControlledPromise<void>()
83
- match.minPendingPromise = minPendingPromise
109
+ match._nonReactive.minPendingPromise = minPendingPromise
84
110
  match._forcePending = true
85
111
 
86
112
  setTimeout(() => {
87
113
  minPendingPromise.resolve()
88
114
  // We've handled the minPendingPromise, so we can delete it
89
- router.updateMatch(match.id, (prev) => ({
90
- ...prev,
91
- minPendingPromise: undefined,
92
- _forcePending: undefined,
93
- }))
115
+ router.updateMatch(match.id, (prev) => {
116
+ prev._nonReactive.minPendingPromise = undefined
117
+ return {
118
+ ...prev,
119
+ _forcePending: undefined,
120
+ }
121
+ })
94
122
  }, pendingMinMs)
95
123
  }
96
124
  }
@@ -103,17 +131,14 @@ export async function hydrate(router: AnyRouter): Promise<any> {
103
131
  (d) => d.i === match.id,
104
132
  )
105
133
  if (!dehydratedMatch) {
106
- Object.assign(match, { dehydrated: false, ssr: false })
134
+ match._nonReactive.dehydrated = false
135
+ match.ssr = false
107
136
  return
108
137
  }
109
138
 
110
- Object.assign(match, hydrateMatch(dehydratedMatch))
139
+ hydrateMatch(match, dehydratedMatch)
111
140
 
112
- if (match.ssr === false) {
113
- match._dehydrated = false
114
- } else {
115
- match._dehydrated = true
116
- }
141
+ match._nonReactive.dehydrated = match.ssr !== false
117
142
 
118
143
  if (match.ssr === 'data-only' || match.ssr === false) {
119
144
  if (firstNonSsrMatchIndex === undefined) {
@@ -141,24 +166,27 @@ export async function hydrate(router: AnyRouter): Promise<any> {
141
166
  const route = router.looseRoutesById[match.routeId]!
142
167
 
143
168
  const parentMatch = router.state.matches[match.index - 1]
144
- const parentContext = parentMatch?.context ?? router.options.context ?? {}
169
+ const parentContext = parentMatch?.context ?? router.options.context
145
170
 
146
171
  // `context()` was already executed by `matchRoutes`, however route context was not yet fully reconstructed
147
172
  // so run it again and merge route context
148
- const contextFnContext: RouteContextOptions<any, any, any, any> = {
149
- deps: match.loaderDeps,
150
- params: match.params,
151
- context: parentContext,
152
- location: router.state.location,
153
- navigate: (opts: any) =>
154
- router.navigate({ ...opts, _fromLocation: router.state.location }),
155
- buildLocation: router.buildLocation,
156
- cause: match.cause,
157
- abortController: match.abortController,
158
- preload: false,
159
- matches,
173
+ if (route.options.context) {
174
+ const contextFnContext: RouteContextOptions<any, any, any, any> = {
175
+ deps: match.loaderDeps,
176
+ params: match.params,
177
+ context: parentContext ?? {},
178
+ location: router.state.location,
179
+ navigate: (opts: any) =>
180
+ router.navigate({ ...opts, _fromLocation: router.state.location }),
181
+ buildLocation: router.buildLocation,
182
+ cause: match.cause,
183
+ abortController: match.abortController,
184
+ preload: false,
185
+ matches,
186
+ }
187
+ match.__routeContext =
188
+ route.options.context(contextFnContext) ?? undefined
160
189
  }
161
- match.__routeContext = route.options.context?.(contextFnContext) ?? {}
162
190
 
163
191
  match.context = {
164
192
  ...parentContext,
@@ -186,11 +214,11 @@ export async function hydrate(router: AnyRouter): Promise<any> {
186
214
 
187
215
  const isSpaMode = matches[matches.length - 1]!.id !== lastMatchId
188
216
  const hasSsrFalseMatches = matches.some((m) => m.ssr === false)
189
- // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()
217
+ // all matches have data from the server and we are not in SPA mode so we don't need to kick of router.load()
190
218
  if (!hasSsrFalseMatches && !isSpaMode) {
191
219
  matches.forEach((match) => {
192
- // remove the _dehydrate flag since we won't run router.load() which would remove it
193
- match._dehydrated = undefined
220
+ // remove the dehydrated flag since we won't run router.load() which would remove it
221
+ match._nonReactive.dehydrated = undefined
194
222
  })
195
223
  return routeChunkPromise
196
224
  }
@@ -213,7 +241,7 @@ export async function hydrate(router: AnyRouter): Promise<any> {
213
241
  setMatchForcePending(match)
214
242
 
215
243
  match._displayPending = true
216
- match.displayPendingPromise = loadPromise
244
+ match._nonReactive.displayPendingPromise = loadPromise
217
245
 
218
246
  loadPromise.then(() => {
219
247
  batch(() => {
@@ -1,14 +1,16 @@
1
1
  import { crossSerializeStream, getCrossReferenceHeader } from 'seroval'
2
- import { ReadableStreamPlugin } from 'seroval-plugins/web'
3
2
  import invariant from 'tiny-invariant'
4
3
  import { createControlledPromise } from '../utils'
5
4
  import minifiedTsrBootStrapScript from './tsrScript?script-string'
6
- import { ShallowErrorPlugin } from './seroval-plugins'
5
+ import { GLOBAL_TSR } from './constants'
6
+ import { defaultSerovalPlugins } from './serializer/seroval-plugins'
7
+ import { makeSsrSerovalPlugin } from './serializer/transformer'
7
8
  import type { AnyRouter } from '../router'
8
9
  import type { DehydratedMatch } from './ssr-client'
9
10
  import type { DehydratedRouter } from './client'
10
11
  import type { AnyRouteMatch } from '../Matches'
11
12
  import type { Manifest } from '../manifest'
13
+ import type { AnySerializationAdapter } from './serializer/transformer'
12
14
 
13
15
  declare module '../router' {
14
16
  interface ServerSsr {
@@ -22,7 +24,6 @@ declare module '../router' {
22
24
  }
23
25
  }
24
26
 
25
- export const GLOBAL_TSR = '$_TSR'
26
27
  const SCOPE_ID = 'tsr'
27
28
 
28
29
  export function dehydrateMatch(match: AnyRouteMatch): DehydratedMatch {
@@ -54,8 +55,6 @@ export function attachRouterServerSsrUtils(
54
55
  router.ssr = {
55
56
  manifest,
56
57
  }
57
- const serializationRefs = new Map<unknown, number>()
58
-
59
58
  let initialScriptSent = false
60
59
  const getInitialScript = () => {
61
60
  if (initialScriptSent) {
@@ -82,7 +81,7 @@ export function attachRouterServerSsrUtils(
82
81
  injectScript: (getScript) => {
83
82
  return router.serverSsr!.injectHtml(async () => {
84
83
  const script = await getScript()
85
- return `<script class='$tsr'>${getInitialScript()}${script};if (typeof $_TSR !== 'undefined') $_TSR.c()</script>`
84
+ return `<script class='$tsr'>${getInitialScript()}${script};$_TSR.c()</script>`
86
85
  })
87
86
  },
88
87
  dehydrate: async () => {
@@ -106,12 +105,21 @@ export function attachRouterServerSsrUtils(
106
105
  _dehydrated = true
107
106
 
108
107
  const p = createControlledPromise<string>()
108
+ const trackPlugins = { didRun: false }
109
+ const plugins =
110
+ (
111
+ router.options.serializationAdapters as
112
+ | Array<AnySerializationAdapter>
113
+ | undefined
114
+ )?.map((t) => makeSsrSerovalPlugin(t, trackPlugins)) ?? []
109
115
  crossSerializeStream(dehydratedRouter, {
110
- refs: serializationRefs,
111
- // TODO make plugins configurable
112
- plugins: [ReadableStreamPlugin, ShallowErrorPlugin],
116
+ refs: new Map(),
117
+ plugins: [...plugins, ...defaultSerovalPlugins],
113
118
  onSerialize: (data, initial) => {
114
- const serialized = initial ? `${GLOBAL_TSR}["router"]=` + data : data
119
+ let serialized = initial ? GLOBAL_TSR + '.router=' + data : data
120
+ if (trackPlugins.didRun) {
121
+ serialized = GLOBAL_TSR + '.p(()=>' + serialized + ')'
122
+ }
115
123
  router.serverSsr!.injectScript(() => serialized)
116
124
  },
117
125
  scopeId: SCOPE_ID,
@@ -1,7 +1,11 @@
1
1
  self.$_TSR = {
2
- c: () => {
2
+ c() {
3
3
  document.querySelectorAll('.\\$tsr').forEach((o) => {
4
4
  o.remove()
5
5
  })
6
6
  },
7
+ p(script) {
8
+ !this.initialized ? this.buffer.push(script) : script()
9
+ },
10
+ buffer: [],
7
11
  }
@@ -36,7 +36,7 @@ export type ValidateParams<
36
36
  > = PathParamOptions<TRouter, TFrom, TTo>
37
37
 
38
38
  /**
39
- * @internal
39
+ * @private
40
40
  */
41
41
  export type InferFrom<
42
42
  TOptions,
@@ -48,7 +48,7 @@ export type InferFrom<
48
48
  : TDefaultFrom
49
49
 
50
50
  /**
51
- * @internal
51
+ * @private
52
52
  */
53
53
  export type InferTo<TOptions> = TOptions extends {
54
54
  to: infer TTo extends string
@@ -57,7 +57,7 @@ export type InferTo<TOptions> = TOptions extends {
57
57
  : undefined
58
58
 
59
59
  /**
60
- * @internal
60
+ * @private
61
61
  */
62
62
  export type InferMaskTo<TOptions> = TOptions extends {
63
63
  mask: { to: infer TTo extends string }
@@ -131,7 +131,7 @@ export type ValidateId<
131
131
  > = ConstrainLiteral<TId, RouteIds<TRouter['routeTree']>>
132
132
 
133
133
  /**
134
- * @internal
134
+ * @private
135
135
  */
136
136
  export type InferStrict<TOptions> = TOptions extends {
137
137
  strict: infer TStrict extends boolean
@@ -140,7 +140,7 @@ export type InferStrict<TOptions> = TOptions extends {
140
140
  : true
141
141
 
142
142
  /**
143
- * @internal
143
+ * @private
144
144
  */
145
145
  export type InferShouldThrow<TOptions> = TOptions extends {
146
146
  shouldThrow: infer TShouldThrow extends boolean
@@ -149,7 +149,7 @@ export type InferShouldThrow<TOptions> = TOptions extends {
149
149
  : true
150
150
 
151
151
  /**
152
- * @internal
152
+ * @private
153
153
  */
154
154
  export type InferSelected<TOptions> = TOptions extends {
155
155
  select: (...args: Array<any>) => infer TSelected
package/src/utils.ts CHANGED
@@ -203,16 +203,6 @@ export function functionalUpdate<TPrevious, TResult = TPrevious>(
203
203
  return updater
204
204
  }
205
205
 
206
- export function pick<TValue, TKey extends keyof TValue>(
207
- parent: TValue,
208
- keys: Array<TKey>,
209
- ): Pick<TValue, TKey> {
210
- return keys.reduce((obj: any, key: TKey) => {
211
- obj[key] = parent[key]
212
- return obj
213
- }, {} as any)
214
- }
215
-
216
206
  /**
217
207
  * This function returns `prev` if `_next` is deeply equal.
218
208
  * If not, it will replace any deeply equal children of `b` with those of `a`.
@@ -432,3 +422,24 @@ export function isModuleNotFoundError(error: any): boolean {
432
422
  error.message.startsWith('Importing a module script failed')
433
423
  )
434
424
  }
425
+
426
+ export function isPromise<T>(
427
+ value: Promise<Awaited<T>> | T,
428
+ ): value is Promise<Awaited<T>> {
429
+ return Boolean(
430
+ value &&
431
+ typeof value === 'object' &&
432
+ typeof (value as Promise<T>).then === 'function',
433
+ )
434
+ }
435
+
436
+ export function findLast<T>(
437
+ array: ReadonlyArray<T>,
438
+ predicate: (item: T) => boolean,
439
+ ): T | undefined {
440
+ for (let i = array.length - 1; i >= 0; i--) {
441
+ const item = array[i]!
442
+ if (predicate(item)) return item
443
+ }
444
+ return undefined
445
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"seroval-plugins.cjs","sources":["../../../src/ssr/seroval-plugins.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport type { SerovalNode } from 'seroval'\n\ninterface 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: 'tanstack-start:seroval-plugins/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 +0,0 @@
1
- {"version":3,"file":"seroval-plugins.js","sources":["../../../src/ssr/seroval-plugins.ts"],"sourcesContent":["import { createPlugin } from 'seroval'\nimport type { SerovalNode } from 'seroval'\n\ninterface 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: 'tanstack-start:seroval-plugins/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":[],"mappings":";AAWO,MAAM,qBAAqC,6BAGhD;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;"}