@tanstack/start-client-core 1.121.0-alpha.27 → 1.121.0-alpha.28

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 (73) hide show
  1. package/dist/esm/createIsomorphicFn.js +6 -1
  2. package/dist/esm/createIsomorphicFn.js.map +1 -1
  3. package/dist/esm/createMiddleware.d.ts +8 -7
  4. package/dist/esm/createMiddleware.js.map +1 -1
  5. package/dist/esm/createServerFn.d.ts +7 -32
  6. package/dist/esm/createServerFn.js +15 -147
  7. package/dist/esm/createServerFn.js.map +1 -1
  8. package/dist/esm/envOnly.js.map +1 -1
  9. package/dist/esm/index.d.ts +6 -6
  10. package/dist/esm/index.js +2 -5
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/registerGlobalMiddleware.js.map +1 -1
  13. package/dist/esm/serializer.d.ts +22 -1
  14. package/dist/esm/serializer.js.map +1 -1
  15. package/package.json +3 -6
  16. package/src/createIsomorphicFn.ts +6 -1
  17. package/src/createMiddleware.ts +11 -10
  18. package/src/createServerFn.ts +28 -328
  19. package/src/index.tsx +19 -19
  20. package/src/serializer.ts +32 -3
  21. package/src/tests/createServerFn.test-d.ts +0 -6
  22. package/src/tests/{transformer.test.tsx → serializer.test.tsx} +36 -32
  23. package/dist/cjs/createIsomorphicFn.cjs +0 -7
  24. package/dist/cjs/createIsomorphicFn.cjs.map +0 -1
  25. package/dist/cjs/createIsomorphicFn.d.cts +0 -12
  26. package/dist/cjs/createMiddleware.cjs +0 -37
  27. package/dist/cjs/createMiddleware.cjs.map +0 -1
  28. package/dist/cjs/createMiddleware.d.cts +0 -175
  29. package/dist/cjs/createServerFn.cjs +0 -378
  30. package/dist/cjs/createServerFn.cjs.map +0 -1
  31. package/dist/cjs/createServerFn.d.cts +0 -159
  32. package/dist/cjs/envOnly.cjs +0 -7
  33. package/dist/cjs/envOnly.cjs.map +0 -1
  34. package/dist/cjs/envOnly.d.cts +0 -4
  35. package/dist/cjs/headers.cjs +0 -30
  36. package/dist/cjs/headers.cjs.map +0 -1
  37. package/dist/cjs/headers.d.cts +0 -5
  38. package/dist/cjs/index.cjs +0 -33
  39. package/dist/cjs/index.cjs.map +0 -1
  40. package/dist/cjs/index.d.cts +0 -11
  41. package/dist/cjs/json.cjs +0 -14
  42. package/dist/cjs/json.cjs.map +0 -1
  43. package/dist/cjs/json.d.cts +0 -2
  44. package/dist/cjs/registerGlobalMiddleware.cjs +0 -9
  45. package/dist/cjs/registerGlobalMiddleware.cjs.map +0 -1
  46. package/dist/cjs/registerGlobalMiddleware.d.cts +0 -5
  47. package/dist/cjs/serializer.cjs +0 -152
  48. package/dist/cjs/serializer.cjs.map +0 -1
  49. package/dist/cjs/serializer.d.cts +0 -2
  50. package/dist/cjs/ssr-client.cjs +0 -131
  51. package/dist/cjs/ssr-client.cjs.map +0 -1
  52. package/dist/cjs/ssr-client.d.cts +0 -65
  53. package/dist/cjs/tests/createServerFn.test-d.d.cts +0 -1
  54. package/dist/cjs/tests/createServerMiddleware.test-d.d.cts +0 -1
  55. package/dist/cjs/tests/envOnly.test-d.d.cts +0 -1
  56. package/dist/cjs/tests/json.test.d.cts +0 -1
  57. package/dist/cjs/tests/transformer.test.d.cts +0 -1
  58. package/dist/esm/headers.d.ts +0 -5
  59. package/dist/esm/headers.js +0 -30
  60. package/dist/esm/headers.js.map +0 -1
  61. package/dist/esm/json.d.ts +0 -2
  62. package/dist/esm/json.js +0 -14
  63. package/dist/esm/json.js.map +0 -1
  64. package/dist/esm/ssr-client.d.ts +0 -65
  65. package/dist/esm/ssr-client.js +0 -131
  66. package/dist/esm/ssr-client.js.map +0 -1
  67. package/dist/esm/tests/json.test.d.ts +0 -1
  68. package/dist/esm/tests/transformer.test.d.ts +0 -1
  69. package/src/headers.ts +0 -50
  70. package/src/json.ts +0 -15
  71. package/src/ssr-client.tsx +0 -249
  72. package/src/tests/json.test.ts +0 -37
  73. /package/dist/{cjs/tests/createIsomorphicFn.test-d.d.cts → esm/tests/serializer.test.d.ts} +0 -0
@@ -1,19 +1,25 @@
1
- import { default as invariant } from 'tiny-invariant'
2
- import { default as warning } from 'tiny-warning'
3
1
  import { isNotFound, isRedirect } from '@tanstack/router-core'
4
- import { startSerializer } from './serializer'
5
- import { mergeHeaders } from './headers'
2
+ import { mergeHeaders } from '@tanstack/router-core/ssr/client'
3
+ import { getStartContext } from '@tanstack/start-storage-context'
6
4
  import { globalMiddleware } from './registerGlobalMiddleware'
5
+
6
+ import { startSerializer } from './serializer'
7
+
8
+ import { createIsomorphicFn } from './createIsomorphicFn'
9
+ import type {
10
+ SerializerParse,
11
+ SerializerStringify,
12
+ SerializerStringifyBy,
13
+ } from './serializer'
7
14
  import type {
15
+ AnyRouter,
8
16
  AnyValidator,
9
17
  Constrain,
10
18
  Expand,
11
19
  ResolveValidatorInput,
12
- SerializerParse,
13
- SerializerStringify,
14
- SerializerStringifyBy,
15
20
  Validator,
16
21
  } from '@tanstack/router-core'
22
+ import type { JsonResponse } from '@tanstack/router-core/ssr/client'
17
23
  import type { Readable } from 'node:stream'
18
24
  import type {
19
25
  AnyFunctionMiddleware,
@@ -27,6 +33,10 @@ import type {
27
33
 
28
34
  type TODO = any
29
35
 
36
+ const getRouterInstance = createIsomorphicFn()
37
+ .client(() => window.__TSR_ROUTER__!)
38
+ .server(() => getStartContext({ throwIfNotFound: false })?.router)
39
+
30
40
  export function createServerFn<
31
41
  TMethod extends Method,
32
42
  TServerFnResponseType extends ServerFnResponseType = 'data',
@@ -37,7 +47,6 @@ export function createServerFn<
37
47
  options?: {
38
48
  method?: TMethod
39
49
  response?: TServerFnResponseType
40
- type?: ServerFnType
41
50
  },
42
51
  __opts?: ServerFnBaseOptions<
43
52
  TMethod,
@@ -79,15 +88,6 @@ export function createServerFn<
79
88
  TValidator
80
89
  >(undefined, Object.assign(resolvedOptions, { validator })) as any
81
90
  },
82
- type: (type) => {
83
- return createServerFn<
84
- TMethod,
85
- ServerFnResponseType,
86
- TResponse,
87
- TMiddlewares,
88
- TValidator
89
- >(undefined, Object.assign(resolvedOptions, { type })) as any
90
- },
91
91
  handler: (...args) => {
92
92
  // This function signature changes due to AST transformations
93
93
  // in the babel plugin. We need to cast it to the correct
@@ -129,6 +129,7 @@ export function createServerFn<
129
129
  headers: opts?.headers,
130
130
  signal: opts?.signal,
131
131
  context: {},
132
+ router: getRouterInstance(),
132
133
  }).then((d) => {
133
134
  if (resolvedOptions.response === 'full') {
134
135
  return d
@@ -146,70 +147,20 @@ export function createServerFn<
146
147
  const opts =
147
148
  opts_ instanceof FormData ? extractFormDataContext(opts_) : opts_
148
149
 
149
- opts.type =
150
- typeof resolvedOptions.type === 'function'
151
- ? resolvedOptions.type(opts)
152
- : resolvedOptions.type
153
-
154
150
  const ctx = {
155
151
  ...extractedFn,
156
152
  ...opts,
157
153
  signal,
158
154
  }
159
155
 
160
- const run = () =>
161
- executeMiddleware(resolvedMiddleware, 'server', ctx).then(
162
- (d) => ({
163
- // Only send the result and sendContext back to the client
164
- result: d.result,
165
- error: d.error,
166
- context: d.sendContext,
167
- }),
168
- )
169
-
170
- if (ctx.type === 'static') {
171
- let response: StaticCachedResult | undefined
172
-
173
- // If we can get the cached item, try to get it
174
- if (serverFnStaticCache?.getItem) {
175
- // If this throws, it's okay to let it bubble up
176
- response = await serverFnStaticCache.getItem(ctx)
177
- }
178
-
179
- if (!response) {
180
- // If there's no cached item, execute the server function
181
- response = await run()
182
- .then((d) => {
183
- return {
184
- ctx: d,
185
- error: null,
186
- }
187
- })
188
- .catch((e) => {
189
- return {
190
- ctx: undefined,
191
- error: e,
192
- }
193
- })
194
-
195
- if (serverFnStaticCache?.setItem) {
196
- await serverFnStaticCache.setItem(ctx, response)
197
- }
198
- }
199
-
200
- invariant(
201
- response,
202
- 'No response from both server and static cache!',
203
- )
204
-
205
- if (response.error) {
206
- throw response.error
207
- }
208
-
209
- return response.ctx
210
- }
211
-
212
- return run()
156
+ return executeMiddleware(resolvedMiddleware, 'server', ctx).then(
157
+ (d) => ({
158
+ // Only send the result and sendContext back to the client
159
+ result: d.result,
160
+ error: d.error,
161
+ context: d.sendContext,
162
+ }),
163
+ )
213
164
  },
214
165
  },
215
166
  ) as any
@@ -278,10 +229,6 @@ export async function executeMiddleware(
278
229
  })
279
230
  }
280
231
 
281
- export interface JsonResponse<TData> extends Response {
282
- json: () => Promise<TData>
283
- }
284
-
285
232
  export type CompiledFetcherFnOptions = {
286
233
  method: Method
287
234
  data: unknown
@@ -289,6 +236,7 @@ export type CompiledFetcherFnOptions = {
289
236
  headers?: HeadersInit
290
237
  signal?: AbortSignal
291
238
  context?: any
239
+ // router?: AnyRouter
292
240
  }
293
241
 
294
242
  export type Fetcher<
@@ -357,12 +305,9 @@ export interface RequiredFetcher<
357
305
 
358
306
  export type FetcherBaseOptions = {
359
307
  headers?: HeadersInit
360
- type?: ServerFnType
361
308
  signal?: AbortSignal
362
309
  }
363
310
 
364
- export type ServerFnType = 'static' | 'dynamic'
365
-
366
311
  export interface OptionalFetcherDataOptions<TMiddlewares, TValidator>
367
312
  extends FetcherBaseOptions {
368
313
  data?: Expand<IntersectAllValidatorInputs<TMiddlewares, TValidator>>
@@ -456,12 +401,6 @@ export type ServerFnBaseOptions<
456
401
  TResponse
457
402
  >
458
403
  functionId: string
459
- type: ServerFnTypeOrTypeFn<
460
- TMethod,
461
- TServerFnResponseType,
462
- TMiddlewares,
463
- AnyValidator
464
- >
465
404
  }
466
405
 
467
406
  export type ValidatorInputStringify<TValidator> = SerializerStringifyBy<
@@ -506,7 +445,6 @@ export interface ServerFnAfterMiddleware<
506
445
  TMiddlewares,
507
446
  TValidator,
508
447
  > extends ServerFnValidator<TMethod, TServerFnResponseType, TMiddlewares>,
509
- ServerFnTyper<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,
510
448
  ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}
511
449
 
512
450
  export type ValidatorFn<
@@ -536,47 +474,8 @@ export interface ServerFnAfterValidator<
536
474
  TMiddlewares,
537
475
  TValidator,
538
476
  > extends ServerFnMiddleware<TMethod, TServerFnResponseType, TValidator>,
539
- ServerFnTyper<TMethod, TServerFnResponseType, TMiddlewares, TValidator>,
540
477
  ServerFnHandler<TMethod, TServerFnResponseType, TMiddlewares, TValidator> {}
541
478
 
542
- // Typer
543
- export interface ServerFnTyper<
544
- TMethod extends Method,
545
- TServerFnResponseType extends ServerFnResponseType,
546
- TMiddlewares,
547
- TValidator,
548
- > {
549
- type: (
550
- typer: ServerFnTypeOrTypeFn<
551
- TMethod,
552
- TServerFnResponseType,
553
- TMiddlewares,
554
- TValidator
555
- >,
556
- ) => ServerFnAfterTyper<
557
- TMethod,
558
- TServerFnResponseType,
559
- TMiddlewares,
560
- TValidator
561
- >
562
- }
563
-
564
- export type ServerFnTypeOrTypeFn<
565
- TMethod extends Method,
566
- TServerFnResponseType extends ServerFnResponseType,
567
- TMiddlewares,
568
- TValidator,
569
- > =
570
- | ServerFnType
571
- | ((
572
- ctx: ServerFnCtx<
573
- TMethod,
574
- TServerFnResponseType,
575
- TMiddlewares,
576
- TValidator
577
- >,
578
- ) => ServerFnType)
579
-
580
479
  export interface ServerFnAfterTyper<
581
480
  TMethod extends Method,
582
481
  TServerFnResponseType extends ServerFnResponseType,
@@ -612,7 +511,6 @@ export interface ServerFnBuilder<
612
511
  TServerFnResponseType extends ServerFnResponseType = 'data',
613
512
  > extends ServerFnMiddleware<TMethod, TServerFnResponseType, undefined>,
614
513
  ServerFnValidator<TMethod, TServerFnResponseType, undefined>,
615
- ServerFnTyper<TMethod, TServerFnResponseType, undefined, undefined>,
616
514
  ServerFnHandler<TMethod, TServerFnResponseType, undefined, undefined> {
617
515
  options: ServerFnBaseOptions<
618
516
  TMethod,
@@ -623,176 +521,6 @@ export interface ServerFnBuilder<
623
521
  >
624
522
  }
625
523
 
626
- export type StaticCachedResult = {
627
- ctx?: {
628
- result: any
629
- context: any
630
- }
631
- error?: any
632
- }
633
-
634
- export type ServerFnStaticCache = {
635
- getItem: (
636
- ctx: ServerFnMiddlewareResult,
637
- ) => StaticCachedResult | Promise<StaticCachedResult | undefined>
638
- setItem: (
639
- ctx: ServerFnMiddlewareResult,
640
- response: StaticCachedResult,
641
- ) => Promise<void>
642
- fetchItem: (
643
- ctx: ServerFnMiddlewareResult,
644
- ) => StaticCachedResult | Promise<StaticCachedResult | undefined>
645
- }
646
-
647
- export let serverFnStaticCache: ServerFnStaticCache | undefined
648
-
649
- export function setServerFnStaticCache(
650
- cache?: ServerFnStaticCache | (() => ServerFnStaticCache | undefined),
651
- ) {
652
- const previousCache = serverFnStaticCache
653
- serverFnStaticCache = typeof cache === 'function' ? cache() : cache
654
-
655
- return () => {
656
- serverFnStaticCache = previousCache
657
- }
658
- }
659
-
660
- export function createServerFnStaticCache(
661
- serverFnStaticCache: ServerFnStaticCache,
662
- ) {
663
- return serverFnStaticCache
664
- }
665
-
666
- /**
667
- * This is a simple hash function for generating a hash from a string to make the filenames shorter.
668
- *
669
- * It is not cryptographically secure (as its using SHA-1) and should not be used for any security purposes.
670
- *
671
- * It is only used to generate a hash for the static cache filenames.
672
- *
673
- * @param message - The input string to hash.
674
- * @returns A promise that resolves to the SHA-1 hash of the input string in hexadecimal format.
675
- *
676
- * @example
677
- * ```typescript
678
- * const hash = await sha1Hash("hello");
679
- * console.log(hash); // Outputs the SHA-1 hash of "hello" -> "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
680
- * ```
681
- */
682
- async function sha1Hash(message: string): Promise<string> {
683
- // Encode the string as UTF-8
684
- const msgBuffer = new TextEncoder().encode(message)
685
-
686
- // Hash the message
687
- const hashBuffer = await crypto.subtle.digest('SHA-1', msgBuffer)
688
-
689
- // Convert the ArrayBuffer to a string
690
- const hashArray = Array.from(new Uint8Array(hashBuffer))
691
- const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('')
692
- return hashHex
693
- }
694
-
695
- setServerFnStaticCache(() => {
696
- const getStaticCacheUrl = async (
697
- options: ServerFnMiddlewareResult,
698
- hash: string,
699
- ) => {
700
- const filename = await sha1Hash(`${options.functionId}__${hash}`)
701
- return `/__tsr/staticServerFnCache/${filename}.json`
702
- }
703
-
704
- const jsonToFilenameSafeString = (json: any) => {
705
- // Custom replacer to sort keys
706
- const sortedKeysReplacer = (key: string, value: any) =>
707
- value && typeof value === 'object' && !Array.isArray(value)
708
- ? Object.keys(value)
709
- .sort()
710
- .reduce((acc: any, curr: string) => {
711
- acc[curr] = value[curr]
712
- return acc
713
- }, {})
714
- : value
715
-
716
- // Convert JSON to string with sorted keys
717
- const jsonString = JSON.stringify(json ?? '', sortedKeysReplacer)
718
-
719
- // Replace characters invalid in filenames
720
- return jsonString
721
- .replace(/[/\\?%*:|"<>]/g, '-') // Replace invalid characters with a dash
722
- .replace(/\s+/g, '_') // Optionally replace whitespace with underscores
723
- }
724
-
725
- const staticClientCache =
726
- typeof document !== 'undefined' ? new Map<string, any>() : null
727
-
728
- return createServerFnStaticCache({
729
- getItem: async (ctx) => {
730
- if (typeof document === 'undefined') {
731
- const hash = jsonToFilenameSafeString(ctx.data)
732
- const url = await getStaticCacheUrl(ctx, hash)
733
- const publicUrl = process.env.TSS_OUTPUT_PUBLIC_DIR!
734
-
735
- // Use fs instead of fetch to read from filesystem
736
- const { promises: fs } = await import('node:fs')
737
- const path = await import('node:path')
738
- const filePath = path.join(publicUrl, url)
739
-
740
- const [cachedResult, readError] = await fs
741
- .readFile(filePath, 'utf-8')
742
- .then((c) => [
743
- startSerializer.parse(c) as {
744
- ctx: unknown
745
- error: any
746
- },
747
- null,
748
- ])
749
- .catch((e) => [null, e])
750
-
751
- if (readError && readError.code !== 'ENOENT') {
752
- throw readError
753
- }
754
-
755
- return cachedResult as StaticCachedResult
756
- }
757
-
758
- return undefined
759
- },
760
- setItem: async (ctx, response) => {
761
- const { promises: fs } = await import('node:fs')
762
- const path = await import('node:path')
763
-
764
- const hash = jsonToFilenameSafeString(ctx.data)
765
- const url = await getStaticCacheUrl(ctx, hash)
766
- const publicUrl = process.env.TSS_OUTPUT_PUBLIC_DIR!
767
- const filePath = path.join(publicUrl, url)
768
-
769
- // Ensure the directory exists
770
- await fs.mkdir(path.dirname(filePath), { recursive: true })
771
-
772
- // Store the result with fs
773
- await fs.writeFile(filePath, startSerializer.stringify(response))
774
- },
775
- fetchItem: async (ctx) => {
776
- const hash = jsonToFilenameSafeString(ctx.data)
777
- const url = await getStaticCacheUrl(ctx, hash)
778
-
779
- let result: any = staticClientCache?.get(url)
780
-
781
- if (!result) {
782
- result = await fetch(url, {
783
- method: 'GET',
784
- })
785
- .then((r) => r.text())
786
- .then((d) => startSerializer.parse(d))
787
-
788
- staticClientCache?.set(url, result)
789
- }
790
-
791
- return result
792
- },
793
- })
794
- })
795
-
796
524
  export function extractFormDataContext(formData: FormData) {
797
525
  const serializedContext = formData.get('__TSR_CONTEXT')
798
526
  formData.delete('__TSR_CONTEXT')
@@ -849,14 +577,13 @@ export type ServerFnMiddlewareOptions = {
849
577
  signal?: AbortSignal
850
578
  sendContext?: any
851
579
  context?: any
852
- type: ServerFnTypeOrTypeFn<any, any, any, any>
853
580
  functionId: string
581
+ router?: AnyRouter
854
582
  }
855
583
 
856
584
  export type ServerFnMiddlewareResult = ServerFnMiddlewareOptions & {
857
585
  result?: unknown
858
586
  error?: unknown
859
- type: ServerFnTypeOrTypeFn<any, any, any, any>
860
587
  }
861
588
 
862
589
  export type NextFn = (
@@ -946,35 +673,8 @@ export function serverFnBaseToMiddleware(
946
673
  ...ctx,
947
674
  // switch the sendContext over to context
948
675
  context: sendContext,
949
- type: typeof ctx.type === 'function' ? ctx.type(ctx) : ctx.type,
950
676
  } as any
951
677
 
952
- if (
953
- ctx.type === 'static' &&
954
- process.env.NODE_ENV === 'production' &&
955
- typeof document !== 'undefined'
956
- ) {
957
- invariant(
958
- serverFnStaticCache,
959
- 'serverFnStaticCache.fetchItem is not available!',
960
- )
961
-
962
- const result = await serverFnStaticCache.fetchItem(payload)
963
-
964
- if (result) {
965
- if (result.error) {
966
- throw result.error
967
- }
968
-
969
- return next(result.ctx)
970
- }
971
-
972
- warning(
973
- result,
974
- `No static cache item found for ${payload.functionId}__${JSON.stringify(payload.data)}, falling back to server function...`,
975
- )
976
- }
977
-
978
678
  // Execute the extracted function
979
679
  // but not before serializing the context
980
680
  const res = await options.extractedFn?.(payload)
package/src/index.tsx CHANGED
@@ -1,16 +1,22 @@
1
- export { mergeHeaders } from './headers'
1
+ export type {
2
+ DehydratedRouter,
3
+ JsonResponse,
4
+ } from '@tanstack/router-core/ssr/client'
5
+
6
+ export { hydrate, json, mergeHeaders } from '@tanstack/router-core/ssr/client'
7
+
2
8
  export { startSerializer } from './serializer'
3
- export {
4
- type DehydratedRouter,
5
- type ClientExtractedBaseEntry,
6
- type StartSsrGlobal,
7
- type ClientExtractedEntry,
8
- type SsrMatch,
9
- type ClientExtractedPromise,
10
- type ClientExtractedStream,
11
- type ResolvePromiseState,
12
- hydrate,
13
- } from './ssr-client'
9
+
10
+ export type {
11
+ StartSerializer,
12
+ Serializable,
13
+ SerializerParse,
14
+ SerializerParseBy,
15
+ SerializerStringify,
16
+ SerializerStringifyBy,
17
+ SerializerExtensions,
18
+ } from './serializer'
19
+
14
20
  export {
15
21
  createIsomorphicFn,
16
22
  type IsomorphicFn,
@@ -19,8 +25,7 @@ export {
19
25
  type IsomorphicFnBase,
20
26
  } from './createIsomorphicFn'
21
27
  export { serverOnly, clientOnly } from './envOnly'
22
- export { type JsonResponse, createServerFn } from './createServerFn'
23
- export { json } from './json'
28
+ export { createServerFn } from './createServerFn'
24
29
  export {
25
30
  createMiddleware,
26
31
  type IntersectAllValidatorInputs,
@@ -55,8 +60,6 @@ export {
55
60
  globalMiddleware,
56
61
  } from './registerGlobalMiddleware'
57
62
  export type {
58
- ServerFn as FetchFn,
59
- ServerFnCtx as FetchFnCtx,
60
63
  CompiledFetcherFnOptions,
61
64
  CompiledFetcherFn,
62
65
  Fetcher,
@@ -70,11 +73,9 @@ export type {
70
73
  ServerFnMiddlewareOptions,
71
74
  ServerFnMiddlewareResult,
72
75
  ServerFnBuilder,
73
- ServerFnType,
74
76
  ServerFnBaseOptions,
75
77
  NextFn,
76
78
  Method,
77
- StaticCachedResult,
78
79
  OptionalFetcher,
79
80
  RequiredFetcher,
80
81
  } from './createServerFn'
@@ -84,6 +85,5 @@ export {
84
85
  serverFnBaseToMiddleware,
85
86
  extractFormDataContext,
86
87
  flattenMiddlewares,
87
- serverFnStaticCache,
88
88
  executeMiddleware,
89
89
  } from './createServerFn'
package/src/serializer.ts CHANGED
@@ -1,6 +1,37 @@
1
1
  import { isPlainObject } from '@tanstack/router-core'
2
- import type { StartSerializer } from '@tanstack/router-core'
3
2
 
3
+ export interface StartSerializer {
4
+ stringify: (obj: unknown) => string
5
+ parse: (str: string) => unknown
6
+ encode: <T>(value: T) => T
7
+ decode: <T>(value: T) => T
8
+ }
9
+
10
+ export type SerializerStringifyBy<T, TSerializable> = T extends TSerializable
11
+ ? T
12
+ : T extends (...args: Array<any>) => any
13
+ ? 'Function is not serializable'
14
+ : { [K in keyof T]: SerializerStringifyBy<T[K], TSerializable> }
15
+
16
+ export type SerializerParseBy<T, TSerializable> = T extends TSerializable
17
+ ? T
18
+ : unknown extends SerializerExtensions['ReadableStream']
19
+ ? { [K in keyof T]: SerializerParseBy<T[K], TSerializable> }
20
+ : T extends SerializerExtensions['ReadableStream']
21
+ ? ReadableStream
22
+ : { [K in keyof T]: SerializerParseBy<T[K], TSerializable> }
23
+
24
+ export interface DefaultSerializerExtensions {
25
+ ReadableStream: unknown
26
+ }
27
+
28
+ export interface SerializerExtensions extends DefaultSerializerExtensions {}
29
+
30
+ export type Serializable = Date | undefined | Error | FormData | bigint
31
+
32
+ export type SerializerStringify<T> = SerializerStringifyBy<T, Serializable>
33
+
34
+ export type SerializerParse<T> = SerializerParseBy<T, Serializable>
4
35
  export const startSerializer: StartSerializer = {
5
36
  stringify: (value: any) =>
6
37
  JSON.stringify(value, function replacer(key, val) {
@@ -73,7 +104,6 @@ export const startSerializer: StartSerializer = {
73
104
  return value
74
105
  },
75
106
  }
76
-
77
107
  const createSerializer = <TKey extends string, TInput, TSerialized>(
78
108
  key: TKey,
79
109
  check: (value: any) => value is TInput,
@@ -86,7 +116,6 @@ const createSerializer = <TKey extends string, TInput, TSerialized>(
86
116
  parseCondition: (value: any) => Object.hasOwn(value, `$${key}`),
87
117
  parse: (value: any) => fromValue(value[`$${key}`]),
88
118
  })
89
-
90
119
  // Keep these ordered by predicted frequency
91
120
  // Make sure to keep DefaultSerializable in sync with these serializers
92
121
  // Also, make sure that they are unit tested in serializer.test.tsx
@@ -52,7 +52,6 @@ test('createServerFn with validator', () => {
52
52
  expectTypeOf(fn).parameter(0).toEqualTypeOf<{
53
53
  data: { input: string }
54
54
  headers?: HeadersInit
55
- type?: 'static' | 'dynamic'
56
55
  signal?: AbortSignal
57
56
  }>()
58
57
 
@@ -168,7 +167,6 @@ describe('createServerFn with middleware and validator', () => {
168
167
  readonly inputC: 'inputC'
169
168
  }
170
169
  headers?: HeadersInit
171
- type?: 'static' | 'dynamic'
172
170
  signal?: AbortSignal
173
171
  }>()
174
172
 
@@ -212,7 +210,6 @@ describe('createServerFn with middleware and validator', () => {
212
210
  readonly inputC: 'inputC'
213
211
  }
214
212
  headers?: HeadersInit
215
- type?: 'static' | 'dynamic'
216
213
  signal?: AbortSignal
217
214
  }>()
218
215
 
@@ -323,7 +320,6 @@ test('createServerFn where validator is optional if object is optional', () => {
323
320
  | {
324
321
  data?: 'c' | undefined
325
322
  headers?: HeadersInit
326
- type?: 'static' | 'dynamic'
327
323
  signal?: AbortSignal
328
324
  }
329
325
  | undefined
@@ -347,7 +343,6 @@ test('createServerFn where data is optional if there is no validator', () => {
347
343
  | {
348
344
  data?: undefined
349
345
  headers?: HeadersInit
350
- type?: 'static' | 'dynamic'
351
346
  signal?: AbortSignal
352
347
  }
353
348
  | undefined
@@ -509,7 +504,6 @@ test('createServerFn validator infers unknown for default input type', () => {
509
504
  | {
510
505
  data?: unknown | undefined
511
506
  headers?: HeadersInit
512
- type?: 'static' | 'dynamic'
513
507
  signal?: AbortSignal
514
508
  }
515
509
  | undefined