@tanstack/start-client-core 1.132.0-alpha.0 → 1.132.0-alpha.10

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 (53) hide show
  1. package/dist/esm/constants.d.ts +5 -0
  2. package/dist/esm/constants.js +13 -0
  3. package/dist/esm/constants.js.map +1 -0
  4. package/dist/esm/createClientRpc.d.ts +6 -0
  5. package/dist/esm/createClientRpc.js +26 -0
  6. package/dist/esm/createClientRpc.js.map +1 -0
  7. package/dist/esm/createMiddleware.d.ts +35 -40
  8. package/dist/esm/createMiddleware.js.map +1 -1
  9. package/dist/esm/createServerFn.d.ts +46 -58
  10. package/dist/esm/createServerFn.js +39 -45
  11. package/dist/esm/createServerFn.js.map +1 -1
  12. package/dist/esm/envOnly.d.ts +2 -2
  13. package/dist/esm/envOnly.js +4 -4
  14. package/dist/esm/envOnly.js.map +1 -1
  15. package/dist/esm/getRouterInstance.d.ts +1 -0
  16. package/dist/esm/getRouterInstance.js +7 -0
  17. package/dist/esm/getRouterInstance.js.map +1 -0
  18. package/dist/esm/index.d.ts +6 -5
  19. package/dist/esm/index.js +13 -8
  20. package/dist/esm/index.js.map +1 -1
  21. package/dist/esm/serializer/ServerFunctionSerializationAdapter.d.ts +5 -0
  22. package/dist/esm/serializer/ServerFunctionSerializationAdapter.js +17 -0
  23. package/dist/esm/serializer/ServerFunctionSerializationAdapter.js.map +1 -0
  24. package/dist/esm/serializer/getClientSerovalPlugins.d.ts +3 -0
  25. package/dist/esm/serializer/getClientSerovalPlugins.js +13 -0
  26. package/dist/esm/serializer/getClientSerovalPlugins.js.map +1 -0
  27. package/dist/esm/serializer/getDefaultSerovalPlugins.d.ts +1 -0
  28. package/dist/esm/serializer/getDefaultSerovalPlugins.js +16 -0
  29. package/dist/esm/serializer/getDefaultSerovalPlugins.js.map +1 -0
  30. package/dist/esm/serverFnFetcher.d.ts +1 -0
  31. package/dist/esm/serverFnFetcher.js +217 -0
  32. package/dist/esm/serverFnFetcher.js.map +1 -0
  33. package/package.json +5 -4
  34. package/src/constants.ts +8 -0
  35. package/src/createClientRpc.ts +26 -0
  36. package/src/createMiddleware.ts +93 -91
  37. package/src/createServerFn.ts +158 -206
  38. package/src/envOnly.ts +2 -2
  39. package/src/getRouterInstance.ts +7 -0
  40. package/src/index.tsx +11 -15
  41. package/src/serializer/ServerFunctionSerializationAdapter.ts +16 -0
  42. package/src/serializer/getClientSerovalPlugins.ts +10 -0
  43. package/src/serializer/getDefaultSerovalPlugins.ts +19 -0
  44. package/src/serverFnFetcher.ts +299 -0
  45. package/src/tests/createServerFn.test-d.ts +124 -105
  46. package/src/tests/createServerMiddleware.test-d.ts +11 -9
  47. package/src/tests/envOnly.test-d.ts +9 -9
  48. package/dist/esm/serializer.d.ts +0 -23
  49. package/dist/esm/serializer.js +0 -152
  50. package/dist/esm/serializer.js.map +0 -1
  51. package/dist/esm/tests/serializer.test.d.ts +0 -1
  52. package/src/serializer.ts +0 -206
  53. package/src/tests/serializer.test.tsx +0 -151
@@ -1,7 +1,7 @@
1
1
  import { describe, expectTypeOf, test } from 'vitest'
2
2
  import { createMiddleware } from '../createMiddleware'
3
3
  import { createServerFn } from '../createServerFn'
4
- import type { Constrain, Validator } from '@tanstack/router-core'
4
+ import type { Constrain, Register, Validator } from '@tanstack/router-core'
5
5
  import type { ConstrainValidator } from '../createServerFn'
6
6
 
7
7
  test('createServerFn method with autocomplete', () => {
@@ -21,7 +21,6 @@ test('createServerFn without middleware', () => {
21
21
  context: undefined
22
22
  data: undefined
23
23
  signal: AbortSignal
24
- response: 'data'
25
24
  }>()
26
25
  })
27
26
  })
@@ -45,7 +44,6 @@ test('createServerFn with validator', () => {
45
44
  a: string
46
45
  }
47
46
  signal: AbortSignal
48
- response: 'data'
49
47
  }>()
50
48
  })
51
49
 
@@ -97,7 +95,6 @@ test('createServerFn with middleware and context', () => {
97
95
 
98
96
  expectTypeOf(fnWithMiddleware).toHaveProperty('handler')
99
97
  expectTypeOf(fnWithMiddleware).toHaveProperty('validator')
100
- expectTypeOf(fnWithMiddleware).not.toHaveProperty('middleware')
101
98
 
102
99
  fnWithMiddleware.handler((options) => {
103
100
  expectTypeOf(options).toEqualTypeOf<{
@@ -110,7 +107,6 @@ test('createServerFn with middleware and context', () => {
110
107
  }
111
108
  data: undefined
112
109
  signal: AbortSignal
113
- response: 'data'
114
110
  }>()
115
111
  })
116
112
  })
@@ -135,8 +131,8 @@ describe('createServerFn with middleware and validator', () => {
135
131
  middleware2,
136
132
  ])
137
133
 
138
- test(`response: 'data'`, () => {
139
- const fn = createServerFn({ method: 'GET', response: 'data' })
134
+ test(`response`, () => {
135
+ const fn = createServerFn({ method: 'GET' })
140
136
  .middleware([middleware3])
141
137
  .validator(
142
138
  (input: { readonly inputC: 'inputC' }) =>
@@ -154,7 +150,6 @@ describe('createServerFn with middleware and validator', () => {
154
150
  readonly outputC: 'outputC'
155
151
  }
156
152
  signal: AbortSignal
157
- response: 'data'
158
153
  }>()
159
154
 
160
155
  return 'some-data' as const
@@ -177,52 +172,6 @@ describe('createServerFn with middleware and validator', () => {
177
172
  }),
178
173
  ).returns.resolves.toEqualTypeOf<'some-data'>()
179
174
  })
180
-
181
- test(`response: 'full'`, () => {
182
- const fn = createServerFn({ method: 'GET', response: 'full' })
183
- .middleware([middleware3])
184
- .validator(
185
- (input: { readonly inputC: 'inputC' }) =>
186
- ({
187
- outputC: 'outputC',
188
- }) as const,
189
- )
190
- .handler((options) => {
191
- expectTypeOf(options).toEqualTypeOf<{
192
- method: 'GET'
193
- context: undefined
194
- data: {
195
- readonly outputA: 'outputA'
196
- readonly outputB: 'outputB'
197
- readonly outputC: 'outputC'
198
- }
199
- signal: AbortSignal
200
- response: 'full'
201
- }>()
202
-
203
- return 'some-data' as const
204
- })
205
-
206
- expectTypeOf(fn).parameter(0).toEqualTypeOf<{
207
- data: {
208
- readonly inputA: 'inputA'
209
- readonly inputB: 'inputB'
210
- readonly inputC: 'inputC'
211
- }
212
- headers?: HeadersInit
213
- signal?: AbortSignal
214
- }>()
215
-
216
- expectTypeOf(() =>
217
- fn({
218
- data: { inputA: 'inputA', inputB: 'inputB', inputC: 'inputC' },
219
- }),
220
- ).returns.resolves.toEqualTypeOf<{
221
- result: 'some-data'
222
- context: undefined
223
- error: unknown
224
- }>()
225
- })
226
175
  })
227
176
 
228
177
  test('createServerFn overrides properties', () => {
@@ -298,7 +247,6 @@ test('createServerFn where validator is a primitive', () => {
298
247
  context: undefined
299
248
  data: 'c'
300
249
  signal: AbortSignal
301
- response: 'data'
302
250
  }>()
303
251
  })
304
252
  })
@@ -312,7 +260,6 @@ test('createServerFn where validator is optional if object is optional', () => {
312
260
  context: undefined
313
261
  data: 'c' | undefined
314
262
  signal: AbortSignal
315
- response: 'data'
316
263
  }>()
317
264
  })
318
265
 
@@ -335,7 +282,6 @@ test('createServerFn where data is optional if there is no validator', () => {
335
282
  context: undefined
336
283
  data: undefined
337
284
  signal: AbortSignal
338
- response: 'data'
339
285
  }>()
340
286
  })
341
287
 
@@ -371,6 +317,7 @@ test('createServerFn cannot return function', () => {
371
317
  expectTypeOf(createServerFn().handler<{ func: () => 'func' }>)
372
318
  .parameter(0)
373
319
  .returns.toEqualTypeOf<
320
+ | Response
374
321
  | { func: 'Function is not serializable' }
375
322
  | Promise<{ func: 'Function is not serializable' }>
376
323
  >()
@@ -398,7 +345,9 @@ test('createServerFn can validate Date', () => {
398
345
 
399
346
  expectTypeOf(validator)
400
347
  .parameter(0)
401
- .toEqualTypeOf<ConstrainValidator<(input: Date) => { output: 'string' }>>()
348
+ .toEqualTypeOf<
349
+ ConstrainValidator<Register, (input: Date) => { output: 'string' }>
350
+ >()
402
351
  })
403
352
 
404
353
  test('createServerFn can validate FormData', () => {
@@ -409,63 +358,18 @@ test('createServerFn can validate FormData', () => {
409
358
  expectTypeOf(validator)
410
359
  .parameter(0)
411
360
  .toEqualTypeOf<
412
- ConstrainValidator<(input: FormData) => { output: 'string' }>
361
+ ConstrainValidator<Register, (input: FormData) => { output: 'string' }>
413
362
  >()
414
363
  })
415
364
 
416
365
  describe('response', () => {
417
- describe('data', () => {
418
- test(`response: 'data' is passed into handler without response being set`, () => {
419
- createServerFn().handler((options) => {
420
- expectTypeOf(options.response).toEqualTypeOf<'data'>()
421
- })
422
- })
423
-
424
- test(`response: 'data' is passed into handler with explicit response: 'data'`, () => {
425
- createServerFn({ response: 'data' }).handler((options) => {
426
- expectTypeOf(options.response).toEqualTypeOf<'data'>()
427
- })
428
- })
429
- })
430
- describe('full', () => {
431
- test(`response: 'full' is passed into handler`, () => {
432
- createServerFn({ response: 'full' }).handler((options) => {
433
- expectTypeOf(options.response).toEqualTypeOf<'full'>()
434
- })
435
- })
436
- })
437
-
438
- describe('raw', () => {
439
- test(`response: 'raw' is passed into handler`, () => {
440
- createServerFn({ response: 'raw' }).handler((options) => {
441
- expectTypeOf(options.response).toEqualTypeOf<'raw'>()
442
- return null
443
- })
444
- })
445
- })
446
366
  test(`client receives Response when Response is returned`, () => {
447
- const fn = createServerFn({ response: 'raw' }).handler(() => {
367
+ const fn = createServerFn().handler(() => {
448
368
  return new Response('Hello World')
449
369
  })
450
370
 
451
371
  expectTypeOf(fn()).toEqualTypeOf<Promise<Response>>()
452
372
  })
453
-
454
- test(`client receives Response when ReadableStream is returned`, () => {
455
- const fn = createServerFn({ response: 'raw' }).handler(() => {
456
- return new ReadableStream()
457
- })
458
-
459
- expectTypeOf(fn()).toEqualTypeOf<Promise<Response>>()
460
- })
461
-
462
- test(`client receives Response when string is returned`, () => {
463
- const fn = createServerFn({ response: 'raw' }).handler(() => {
464
- return 'hello'
465
- })
466
-
467
- expectTypeOf(fn()).toEqualTypeOf<Promise<Response>>()
468
- })
469
373
  })
470
374
 
471
375
  test('createServerFn can be used as a mutation function', () => {
@@ -511,3 +415,118 @@ test('createServerFn validator infers unknown for default input type', () => {
511
415
 
512
416
  expectTypeOf(fn()).toEqualTypeOf<Promise<'failed' | 'success'>>()
513
417
  })
418
+
419
+ test('incrementally building createServerFn with multiple middleware calls', () => {
420
+ const middleware1 = createMiddleware({ type: 'function' }).server(
421
+ ({ next }) => {
422
+ return next({ context: { a: 'a' } as const })
423
+ },
424
+ )
425
+
426
+ const middleware2 = createMiddleware({ type: 'function' }).server(
427
+ ({ next }) => {
428
+ return next({ context: { b: 'b' } as const })
429
+ },
430
+ )
431
+
432
+ const middleware3 = createMiddleware({ type: 'function' }).server(
433
+ ({ next }) => {
434
+ return next({ context: { c: 'c' } as const })
435
+ },
436
+ )
437
+
438
+ const builderWithMw1 = createServerFn({ method: 'GET' }).middleware([
439
+ middleware1,
440
+ ])
441
+
442
+ expectTypeOf(builderWithMw1).toHaveProperty('handler')
443
+ expectTypeOf(builderWithMw1).toHaveProperty('validator')
444
+ expectTypeOf(builderWithMw1).toHaveProperty('middleware')
445
+
446
+ builderWithMw1.handler((options) => {
447
+ expectTypeOf(options).toEqualTypeOf<{
448
+ method: 'GET'
449
+ context: {
450
+ readonly a: 'a'
451
+ }
452
+ data: undefined
453
+ signal: AbortSignal
454
+ }>()
455
+ })
456
+
457
+ // overrides method
458
+ const builderWithMw2 = builderWithMw1({ method: 'POST' }).middleware([
459
+ middleware2,
460
+ ])
461
+
462
+ expectTypeOf(builderWithMw2).toHaveProperty('handler')
463
+ expectTypeOf(builderWithMw2).toHaveProperty('validator')
464
+ expectTypeOf(builderWithMw2).toHaveProperty('middleware')
465
+
466
+ builderWithMw2.handler((options) => {
467
+ expectTypeOf(options).toEqualTypeOf<{
468
+ method: 'POST'
469
+ context: {
470
+ readonly a: 'a'
471
+ readonly b: 'b'
472
+ }
473
+ data: undefined
474
+ signal: AbortSignal
475
+ }>()
476
+ })
477
+
478
+ // overrides method again
479
+ const builderWithMw3 = builderWithMw2({ method: 'GET' }).middleware([
480
+ middleware3,
481
+ ])
482
+
483
+ expectTypeOf(builderWithMw3).toHaveProperty('handler')
484
+ expectTypeOf(builderWithMw3).toHaveProperty('validator')
485
+ expectTypeOf(builderWithMw3).toHaveProperty('middleware')
486
+
487
+ builderWithMw3.handler((options) => {
488
+ expectTypeOf(options).toEqualTypeOf<{
489
+ method: 'GET'
490
+ context: {
491
+ readonly a: 'a'
492
+ readonly b: 'b'
493
+ readonly c: 'c'
494
+ }
495
+ data: undefined
496
+ signal: AbortSignal
497
+ }>()
498
+ })
499
+ })
500
+
501
+ test('compose middlewares and server function factories', () => {
502
+ const middleware1 = createMiddleware({ type: 'function' }).server(
503
+ ({ next }) => {
504
+ return next({ context: { a: 'a' } as const })
505
+ },
506
+ )
507
+
508
+ const middleware2 = createMiddleware({ type: 'function' }).server(
509
+ ({ next }) => {
510
+ return next({ context: { b: 'b' } as const })
511
+ },
512
+ )
513
+
514
+ const builderWithMw1 = createServerFn().middleware([middleware1])
515
+
516
+ const composedBuilder = createServerFn({ method: 'GET' }).middleware([
517
+ middleware2,
518
+ builderWithMw1,
519
+ ])
520
+
521
+ composedBuilder.handler((options) => {
522
+ expectTypeOf(options).toEqualTypeOf<{
523
+ method: 'GET'
524
+ context: {
525
+ readonly a: 'a'
526
+ readonly b: 'b'
527
+ }
528
+ data: undefined
529
+ signal: AbortSignal
530
+ }>()
531
+ })
532
+ })
@@ -1,8 +1,8 @@
1
1
  import { expectTypeOf, test } from 'vitest'
2
2
  import { createMiddleware } from '../createMiddleware'
3
3
  import type { RequestServerNextFn } from '../createMiddleware'
4
- import type { Constrain, Validator } from '@tanstack/router-core'
5
4
  import type { ConstrainValidator } from '../createServerFn'
5
+ import type { Register } from '@tanstack/router-core'
6
6
 
7
7
  test('createServeMiddleware removes middleware after middleware,', () => {
8
8
  const middleware = createMiddleware({ type: 'function' })
@@ -211,7 +211,7 @@ test('createMiddleware merges client context and sends to the server', () => {
211
211
  expectTypeOf(result).toEqualTypeOf<{
212
212
  'use functions must return the result of next()': true
213
213
  context: { a: boolean; b: string; c: number }
214
- sendContext: { a: boolean; b: string; c: number; d: number }
214
+ sendContext: { a: boolean; b: string; c: number; d: 5 }
215
215
  headers: HeadersInit
216
216
  }>()
217
217
 
@@ -225,7 +225,7 @@ test('createMiddleware merges client context and sends to the server', () => {
225
225
  a: boolean
226
226
  b: string
227
227
  c: number
228
- d: number
228
+ d: 5
229
229
  }>()
230
230
 
231
231
  const result = await options.next({
@@ -242,7 +242,7 @@ test('createMiddleware merges client context and sends to the server', () => {
242
242
  }
243
243
  sendContext: undefined
244
244
  }
245
- context: { a: boolean; b: string; c: number; d: number; e: string }
245
+ context: { a: boolean; b: string; c: number; d: 5; e: string }
246
246
  sendContext: undefined
247
247
  }>()
248
248
 
@@ -586,9 +586,9 @@ test('createMiddleware cannot validate function', () => {
586
586
  expectTypeOf(validator)
587
587
  .parameter(0)
588
588
  .toEqualTypeOf<
589
- Constrain<
590
- (input: { func: () => 'string' }) => { output: 'string' },
591
- Validator<{ func: 'Function is not serializable' }, any>
589
+ ConstrainValidator<
590
+ Register,
591
+ (input: { func: () => 'string' }) => { output: 'string' }
592
592
  >
593
593
  >()
594
594
  })
@@ -600,7 +600,9 @@ test('createMiddleware can validate Date', () => {
600
600
 
601
601
  expectTypeOf(validator)
602
602
  .parameter(0)
603
- .toEqualTypeOf<ConstrainValidator<(input: Date) => { output: 'string' }>>()
603
+ .toEqualTypeOf<
604
+ ConstrainValidator<Register, (input: Date) => { output: 'string' }>
605
+ >()
604
606
  })
605
607
 
606
608
  test('createMiddleware can validate FormData', () => {
@@ -611,7 +613,7 @@ test('createMiddleware can validate FormData', () => {
611
613
  expectTypeOf(validator)
612
614
  .parameter(0)
613
615
  .toEqualTypeOf<
614
- ConstrainValidator<(input: FormData) => { output: 'string' }>
616
+ ConstrainValidator<Register, (input: FormData) => { output: 'string' }>
615
617
  >()
616
618
  })
617
619
 
@@ -1,5 +1,5 @@
1
1
  import { expectTypeOf, test } from 'vitest'
2
- import { clientOnly, serverOnly } from '../envOnly'
2
+ import { createClientOnlyFn, createServerOnlyFn } from '../envOnly'
3
3
 
4
4
  const inputFn = () => 'output'
5
5
 
@@ -11,24 +11,24 @@ function overloadedFn(input: any) {
11
11
  return input
12
12
  }
13
13
 
14
- test("clientOnly returns the function it's given", () => {
15
- const outputFn = clientOnly(inputFn)
14
+ test("createClientOnlyFn returns the function it's given", () => {
15
+ const outputFn = createClientOnlyFn(inputFn)
16
16
  expectTypeOf(outputFn).toEqualTypeOf<typeof inputFn>()
17
17
 
18
- const genericOutputFn = clientOnly(genericInputFn)
18
+ const genericOutputFn = createClientOnlyFn(genericInputFn)
19
19
  expectTypeOf(genericOutputFn).toEqualTypeOf<typeof genericInputFn>()
20
20
 
21
- const overloadedOutputFn = clientOnly(overloadedFn)
21
+ const overloadedOutputFn = createClientOnlyFn(overloadedFn)
22
22
  expectTypeOf(overloadedOutputFn).toEqualTypeOf<typeof overloadedFn>()
23
23
  })
24
24
 
25
- test("serverOnly returns the function it's given", () => {
26
- const outputFn = serverOnly(inputFn)
25
+ test("createServerOnlyFn returns the function it's given", () => {
26
+ const outputFn = createServerOnlyFn(inputFn)
27
27
  expectTypeOf(outputFn).toEqualTypeOf<typeof inputFn>()
28
28
 
29
- const genericOutputFn = serverOnly(genericInputFn)
29
+ const genericOutputFn = createServerOnlyFn(genericInputFn)
30
30
  expectTypeOf(genericOutputFn).toEqualTypeOf<typeof genericInputFn>()
31
31
 
32
- const overloadedOutputFn = serverOnly(overloadedFn)
32
+ const overloadedOutputFn = createServerOnlyFn(overloadedFn)
33
33
  expectTypeOf(overloadedOutputFn).toEqualTypeOf<typeof overloadedFn>()
34
34
  })
@@ -1,23 +0,0 @@
1
- export interface StartSerializer {
2
- stringify: (obj: unknown) => string;
3
- parse: (str: string) => unknown;
4
- encode: <T>(value: T) => T;
5
- decode: <T>(value: T) => T;
6
- }
7
- export type SerializerStringifyBy<T, TSerializable> = T extends TSerializable ? T : T extends (...args: Array<any>) => any ? 'Function is not serializable' : {
8
- [K in keyof T]: SerializerStringifyBy<T[K], TSerializable>;
9
- };
10
- export type SerializerParseBy<T, TSerializable> = T extends TSerializable ? T : unknown extends SerializerExtensions['ReadableStream'] ? {
11
- [K in keyof T]: SerializerParseBy<T[K], TSerializable>;
12
- } : T extends SerializerExtensions['ReadableStream'] ? ReadableStream : {
13
- [K in keyof T]: SerializerParseBy<T[K], TSerializable>;
14
- };
15
- export interface DefaultSerializerExtensions {
16
- ReadableStream: unknown;
17
- }
18
- export interface SerializerExtensions extends DefaultSerializerExtensions {
19
- }
20
- export type Serializable = Date | undefined | Error | FormData | bigint;
21
- export type SerializerStringify<T> = SerializerStringifyBy<T, Serializable>;
22
- export type SerializerParse<T> = SerializerParseBy<T, Serializable>;
23
- export declare const startSerializer: StartSerializer;
@@ -1,152 +0,0 @@
1
- import { isPlainObject } from "@tanstack/router-core";
2
- const startSerializer = {
3
- stringify: (value) => JSON.stringify(value, function replacer(key, val) {
4
- const ogVal = this[key];
5
- const serializer = serializers.find((t) => t.stringifyCondition(ogVal));
6
- if (serializer) {
7
- return serializer.stringify(ogVal);
8
- }
9
- return val;
10
- }),
11
- parse: (value) => JSON.parse(value, function parser(key, val) {
12
- const ogVal = this[key];
13
- if (isPlainObject(ogVal)) {
14
- const serializer = serializers.find((t) => t.parseCondition(ogVal));
15
- if (serializer) {
16
- return serializer.parse(ogVal);
17
- }
18
- }
19
- return val;
20
- }),
21
- encode: (value) => {
22
- if (Array.isArray(value)) {
23
- return value.map((v) => startSerializer.encode(v));
24
- }
25
- if (isPlainObject(value)) {
26
- return Object.fromEntries(
27
- Object.entries(value).map(([key, v]) => [
28
- key,
29
- startSerializer.encode(v)
30
- ])
31
- );
32
- }
33
- const serializer = serializers.find((t) => t.stringifyCondition(value));
34
- if (serializer) {
35
- return serializer.stringify(value);
36
- }
37
- return value;
38
- },
39
- decode: (value) => {
40
- if (isPlainObject(value)) {
41
- const serializer = serializers.find((t) => t.parseCondition(value));
42
- if (serializer) {
43
- return serializer.parse(value);
44
- }
45
- }
46
- if (Array.isArray(value)) {
47
- return value.map((v) => startSerializer.decode(v));
48
- }
49
- if (isPlainObject(value)) {
50
- return Object.fromEntries(
51
- Object.entries(value).map(([key, v]) => [
52
- key,
53
- startSerializer.decode(v)
54
- ])
55
- );
56
- }
57
- return value;
58
- }
59
- };
60
- const createSerializer = (key, check, toValue, fromValue) => ({
61
- key,
62
- stringifyCondition: check,
63
- stringify: (value) => ({ [`$${key}`]: toValue(value) }),
64
- parseCondition: (value) => Object.hasOwn(value, `$${key}`),
65
- parse: (value) => fromValue(value[`$${key}`])
66
- });
67
- const serializers = [
68
- createSerializer(
69
- // Key
70
- "undefined",
71
- // Check
72
- (v) => v === void 0,
73
- // To
74
- () => 0,
75
- // From
76
- () => void 0
77
- ),
78
- createSerializer(
79
- // Key
80
- "date",
81
- // Check
82
- (v) => v instanceof Date,
83
- // To
84
- (v) => v.toISOString(),
85
- // From
86
- (v) => new Date(v)
87
- ),
88
- createSerializer(
89
- // Key
90
- "error",
91
- // Check
92
- (v) => v instanceof Error,
93
- // To
94
- (v) => ({
95
- ...v,
96
- message: v.message,
97
- stack: process.env.NODE_ENV === "development" ? v.stack : void 0,
98
- cause: v.cause
99
- }),
100
- // From
101
- (v) => Object.assign(new Error(v.message), v)
102
- ),
103
- createSerializer(
104
- // Key
105
- "formData",
106
- // Check
107
- (v) => v instanceof FormData,
108
- // To
109
- (v) => {
110
- const entries = {};
111
- v.forEach((value, key) => {
112
- const entry = entries[key];
113
- if (entry !== void 0) {
114
- if (Array.isArray(entry)) {
115
- entry.push(value);
116
- } else {
117
- entries[key] = [entry, value];
118
- }
119
- } else {
120
- entries[key] = value;
121
- }
122
- });
123
- return entries;
124
- },
125
- // From
126
- (v) => {
127
- const formData = new FormData();
128
- Object.entries(v).forEach(([key, value]) => {
129
- if (Array.isArray(value)) {
130
- value.forEach((val) => formData.append(key, val));
131
- } else {
132
- formData.append(key, value);
133
- }
134
- });
135
- return formData;
136
- }
137
- ),
138
- createSerializer(
139
- // Key
140
- "bigint",
141
- // Check
142
- (v) => typeof v === "bigint",
143
- // To
144
- (v) => v.toString(),
145
- // From
146
- (v) => BigInt(v)
147
- )
148
- ];
149
- export {
150
- startSerializer
151
- };
152
- //# sourceMappingURL=serializer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"serializer.js","sources":["../../src/serializer.ts"],"sourcesContent":["import { isPlainObject } from '@tanstack/router-core'\n\nexport interface StartSerializer {\n stringify: (obj: unknown) => string\n parse: (str: string) => unknown\n encode: <T>(value: T) => T\n decode: <T>(value: T) => T\n}\n\nexport type SerializerStringifyBy<T, TSerializable> = T extends TSerializable\n ? T\n : T extends (...args: Array<any>) => any\n ? 'Function is not serializable'\n : { [K in keyof T]: SerializerStringifyBy<T[K], TSerializable> }\n\nexport type SerializerParseBy<T, TSerializable> = T extends TSerializable\n ? T\n : unknown extends SerializerExtensions['ReadableStream']\n ? { [K in keyof T]: SerializerParseBy<T[K], TSerializable> }\n : T extends SerializerExtensions['ReadableStream']\n ? ReadableStream\n : { [K in keyof T]: SerializerParseBy<T[K], TSerializable> }\n\nexport interface DefaultSerializerExtensions {\n ReadableStream: unknown\n}\n\nexport interface SerializerExtensions extends DefaultSerializerExtensions {}\n\nexport type Serializable = Date | undefined | Error | FormData | bigint\n\nexport type SerializerStringify<T> = SerializerStringifyBy<T, Serializable>\n\nexport type SerializerParse<T> = SerializerParseBy<T, Serializable>\nexport const startSerializer: StartSerializer = {\n stringify: (value: any) =>\n JSON.stringify(value, function replacer(key, val) {\n const ogVal = this[key]\n const serializer = serializers.find((t) => t.stringifyCondition(ogVal))\n\n if (serializer) {\n return serializer.stringify(ogVal)\n }\n\n return val\n }),\n parse: (value: string) =>\n JSON.parse(value, function parser(key, val) {\n const ogVal = this[key]\n if (isPlainObject(ogVal)) {\n const serializer = serializers.find((t) => t.parseCondition(ogVal))\n\n if (serializer) {\n return serializer.parse(ogVal)\n }\n }\n\n return val\n }),\n encode: (value: any) => {\n // When encoding, dive first\n if (Array.isArray(value)) {\n return value.map((v) => startSerializer.encode(v))\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, v]) => [\n key,\n startSerializer.encode(v),\n ]),\n )\n }\n\n const serializer = serializers.find((t) => t.stringifyCondition(value))\n if (serializer) {\n return serializer.stringify(value)\n }\n\n return value\n },\n decode: (value: any) => {\n // Attempt transform first\n if (isPlainObject(value)) {\n const serializer = serializers.find((t) => t.parseCondition(value))\n if (serializer) {\n return serializer.parse(value)\n }\n }\n\n if (Array.isArray(value)) {\n return value.map((v) => startSerializer.decode(v))\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, v]) => [\n key,\n startSerializer.decode(v),\n ]),\n )\n }\n\n return value\n },\n}\nconst createSerializer = <TKey extends string, TInput, TSerialized>(\n key: TKey,\n check: (value: any) => value is TInput,\n toValue: (value: TInput) => TSerialized,\n fromValue: (value: TSerialized) => TInput,\n) => ({\n key,\n stringifyCondition: check,\n stringify: (value: any) => ({ [`$${key}`]: toValue(value) }),\n parseCondition: (value: any) => Object.hasOwn(value, `$${key}`),\n parse: (value: any) => fromValue(value[`$${key}`]),\n})\n// Keep these ordered by predicted frequency\n// Make sure to keep DefaultSerializable in sync with these serializers\n// Also, make sure that they are unit tested in serializer.test.tsx\nconst serializers = [\n createSerializer(\n // Key\n 'undefined',\n // Check\n (v): v is undefined => v === undefined,\n // To\n () => 0,\n // From\n () => undefined,\n ),\n createSerializer(\n // Key\n 'date',\n // Check\n (v): v is Date => v instanceof Date,\n // To\n (v) => v.toISOString(),\n // From\n (v) => new Date(v),\n ),\n createSerializer(\n // Key\n 'error',\n // Check\n (v): v is Error => v instanceof Error,\n // To\n (v) => ({\n ...v,\n message: v.message,\n stack: process.env.NODE_ENV === 'development' ? v.stack : undefined,\n cause: v.cause,\n }),\n // From\n (v) => Object.assign(new Error(v.message), v),\n ),\n createSerializer(\n // Key\n 'formData',\n // Check\n (v): v is FormData => v instanceof FormData,\n // To\n (v) => {\n const entries: Record<\n string,\n Array<FormDataEntryValue> | FormDataEntryValue\n > = {}\n v.forEach((value, key) => {\n const entry = entries[key]\n if (entry !== undefined) {\n if (Array.isArray(entry)) {\n entry.push(value)\n } else {\n entries[key] = [entry, value]\n }\n } else {\n entries[key] = value\n }\n })\n return entries\n },\n // From\n (v) => {\n const formData = new FormData()\n Object.entries(v).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n value.forEach((val) => formData.append(key, val))\n } else {\n formData.append(key, value)\n }\n })\n return formData\n },\n ),\n createSerializer(\n // Key\n 'bigint',\n // Check\n (v): v is bigint => typeof v === 'bigint',\n // To\n (v) => v.toString(),\n // From\n (v) => BigInt(v),\n ),\n] as const\n"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};