@benjavicente/start-client-core 1.167.9

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 (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +12 -0
  3. package/bin/intent.js +25 -0
  4. package/dist/esm/client/ServerFunctionSerializationAdapter.d.ts +7 -0
  5. package/dist/esm/client/ServerFunctionSerializationAdapter.js +18 -0
  6. package/dist/esm/client/ServerFunctionSerializationAdapter.js.map +1 -0
  7. package/dist/esm/client/hydrateStart.d.ts +2 -0
  8. package/dist/esm/client/hydrateStart.js +31 -0
  9. package/dist/esm/client/hydrateStart.js.map +1 -0
  10. package/dist/esm/client/index.d.ts +2 -0
  11. package/dist/esm/client/index.js +2 -0
  12. package/dist/esm/client-rpc/createClientRpc.d.ts +6 -0
  13. package/dist/esm/client-rpc/createClientRpc.js +21 -0
  14. package/dist/esm/client-rpc/createClientRpc.js.map +1 -0
  15. package/dist/esm/client-rpc/frame-decoder.d.ts +23 -0
  16. package/dist/esm/client-rpc/frame-decoder.js +231 -0
  17. package/dist/esm/client-rpc/frame-decoder.js.map +1 -0
  18. package/dist/esm/client-rpc/index.d.ts +1 -0
  19. package/dist/esm/client-rpc/index.js +2 -0
  20. package/dist/esm/client-rpc/serverFnFetcher.d.ts +1 -0
  21. package/dist/esm/client-rpc/serverFnFetcher.js +231 -0
  22. package/dist/esm/client-rpc/serverFnFetcher.js.map +1 -0
  23. package/dist/esm/constants.d.ts +53 -0
  24. package/dist/esm/constants.js +46 -0
  25. package/dist/esm/constants.js.map +1 -0
  26. package/dist/esm/createMiddleware.d.ts +195 -0
  27. package/dist/esm/createMiddleware.js +26 -0
  28. package/dist/esm/createMiddleware.js.map +1 -0
  29. package/dist/esm/createServerFn.d.ts +131 -0
  30. package/dist/esm/createServerFn.js +200 -0
  31. package/dist/esm/createServerFn.js.map +1 -0
  32. package/dist/esm/createStart.d.ts +50 -0
  33. package/dist/esm/createStart.js +29 -0
  34. package/dist/esm/createStart.js.map +1 -0
  35. package/dist/esm/fake-start-entry.d.ts +2 -0
  36. package/dist/esm/fake-start-entry.js +7 -0
  37. package/dist/esm/fake-start-entry.js.map +1 -0
  38. package/dist/esm/getDefaultSerovalPlugins.d.ts +1 -0
  39. package/dist/esm/getDefaultSerovalPlugins.js +10 -0
  40. package/dist/esm/getDefaultSerovalPlugins.js.map +1 -0
  41. package/dist/esm/getGlobalStartContext.d.ts +3 -0
  42. package/dist/esm/getGlobalStartContext.js +12 -0
  43. package/dist/esm/getGlobalStartContext.js.map +1 -0
  44. package/dist/esm/getRouterInstance.d.ts +2 -0
  45. package/dist/esm/getRouterInstance.js +8 -0
  46. package/dist/esm/getRouterInstance.js.map +1 -0
  47. package/dist/esm/getStartContextServerOnly.d.ts +2 -0
  48. package/dist/esm/getStartContextServerOnly.js +8 -0
  49. package/dist/esm/getStartContextServerOnly.js.map +1 -0
  50. package/dist/esm/getStartOptions.d.ts +2 -0
  51. package/dist/esm/getStartOptions.js +8 -0
  52. package/dist/esm/getStartOptions.js.map +1 -0
  53. package/dist/esm/global.d.ts +7 -0
  54. package/dist/esm/index.d.ts +20 -0
  55. package/dist/esm/index.js +12 -0
  56. package/dist/esm/safeObjectMerge.d.ts +10 -0
  57. package/dist/esm/safeObjectMerge.js +30 -0
  58. package/dist/esm/safeObjectMerge.js.map +1 -0
  59. package/dist/esm/serverRoute.d.ts +65 -0
  60. package/dist/esm/startEntry.d.ts +8 -0
  61. package/dist/esm/tests/createServerFn.test-d.d.ts +1 -0
  62. package/dist/esm/tests/createServerMiddleware.test-d.d.ts +1 -0
  63. package/package.json +98 -0
  64. package/skills/start-core/SKILL.md +210 -0
  65. package/skills/start-core/deployment/SKILL.md +306 -0
  66. package/skills/start-core/execution-model/SKILL.md +302 -0
  67. package/skills/start-core/middleware/SKILL.md +365 -0
  68. package/skills/start-core/server-functions/SKILL.md +335 -0
  69. package/skills/start-core/server-routes/SKILL.md +280 -0
  70. package/src/client/ServerFunctionSerializationAdapter.ts +16 -0
  71. package/src/client/hydrateStart.ts +43 -0
  72. package/src/client/index.ts +2 -0
  73. package/src/client-rpc/createClientRpc.ts +20 -0
  74. package/src/client-rpc/frame-decoder.ts +389 -0
  75. package/src/client-rpc/index.ts +1 -0
  76. package/src/client-rpc/serverFnFetcher.ts +416 -0
  77. package/src/constants.ts +90 -0
  78. package/src/createMiddleware.ts +824 -0
  79. package/src/createServerFn.ts +813 -0
  80. package/src/createStart.ts +166 -0
  81. package/src/fake-start-entry.ts +2 -0
  82. package/src/getDefaultSerovalPlugins.ts +17 -0
  83. package/src/getGlobalStartContext.ts +18 -0
  84. package/src/getRouterInstance.ts +8 -0
  85. package/src/getStartContextServerOnly.ts +4 -0
  86. package/src/getStartOptions.ts +8 -0
  87. package/src/global.ts +9 -0
  88. package/src/index.tsx +119 -0
  89. package/src/safeObjectMerge.ts +38 -0
  90. package/src/serverRoute.ts +509 -0
  91. package/src/start-entry.d.ts +11 -0
  92. package/src/startEntry.ts +10 -0
  93. package/src/tests/createServerFn.test-d.ts +866 -0
  94. package/src/tests/createServerMiddleware.test-d.ts +810 -0
@@ -0,0 +1,810 @@
1
+ import { expectTypeOf, test } from 'vitest'
2
+ import { createMiddleware } from '../createMiddleware'
3
+ import type { RequestServerNextFn } from '../createMiddleware'
4
+ import type { ConstrainValidator, CustomFetch } from '../createServerFn'
5
+ import type { Register } from '@benjavicente/router-core'
6
+ import type { ServerFnMeta } from '../constants'
7
+
8
+ test('createServeMiddleware removes middleware after middleware,', () => {
9
+ const middleware = createMiddleware({ type: 'function' })
10
+
11
+ expectTypeOf(middleware).toHaveProperty('middleware')
12
+ expectTypeOf(middleware).toHaveProperty('server')
13
+ expectTypeOf(middleware).toHaveProperty('inputValidator')
14
+
15
+ const middlewareAfterMiddleware = middleware.middleware([])
16
+
17
+ expectTypeOf(middlewareAfterMiddleware).toHaveProperty('inputValidator')
18
+ expectTypeOf(middlewareAfterMiddleware).toHaveProperty('server')
19
+ expectTypeOf(middlewareAfterMiddleware).not.toHaveProperty('middleware')
20
+
21
+ const middlewareAfterInput = middleware.inputValidator(() => {})
22
+
23
+ expectTypeOf(middlewareAfterInput).toHaveProperty('server')
24
+ expectTypeOf(middlewareAfterInput).not.toHaveProperty('middleware')
25
+
26
+ const middlewareAfterServer = middleware.server(async (options) => {
27
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
28
+ expectTypeOf(options.data).toEqualTypeOf<undefined>()
29
+ expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>()
30
+
31
+ const result = await options.next({
32
+ context: {
33
+ a: 'a',
34
+ },
35
+ })
36
+
37
+ expectTypeOf(result.context).toEqualTypeOf<{ a: string }>()
38
+
39
+ expectTypeOf(result.sendContext).toEqualTypeOf<undefined>()
40
+
41
+ return result
42
+ })
43
+
44
+ expectTypeOf(middlewareAfterServer).not.toHaveProperty('server')
45
+ expectTypeOf(middlewareAfterServer).not.toHaveProperty('input')
46
+ expectTypeOf(middlewareAfterServer).not.toHaveProperty('middleware')
47
+ })
48
+
49
+ test('createMiddleware merges server context', () => {
50
+ const middleware1 = createMiddleware({ type: 'function' }).server(
51
+ async (options) => {
52
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
53
+ expectTypeOf(options.data).toEqualTypeOf<undefined>()
54
+ expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>()
55
+
56
+ const result = await options.next({ context: { a: true } })
57
+
58
+ expectTypeOf(result).toEqualTypeOf<{
59
+ 'use functions must return the result of next()': true
60
+ '~types': {
61
+ context: {
62
+ a: boolean
63
+ }
64
+ sendContext: undefined
65
+ }
66
+ context: { a: boolean }
67
+ sendContext: undefined
68
+ }>()
69
+
70
+ return result
71
+ },
72
+ )
73
+
74
+ const middleware2 = createMiddleware({ type: 'function' }).server(
75
+ async (options) => {
76
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
77
+ expectTypeOf(options.data).toEqualTypeOf<undefined>()
78
+ expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>()
79
+
80
+ const result = await options.next({ context: { b: 'test' } })
81
+
82
+ expectTypeOf(result).toEqualTypeOf<{
83
+ 'use functions must return the result of next()': true
84
+ '~types': {
85
+ context: {
86
+ b: string
87
+ }
88
+ sendContext: undefined
89
+ }
90
+ context: { b: string }
91
+ sendContext: undefined
92
+ }>()
93
+
94
+ return result
95
+ },
96
+ )
97
+
98
+ const middleware3 = createMiddleware({ type: 'function' })
99
+ .middleware([middleware1, middleware2])
100
+ .server(async (options) => {
101
+ expectTypeOf(options.context).toEqualTypeOf<{ a: boolean; b: string }>()
102
+
103
+ const result = await options.next({ context: { c: 0 } })
104
+
105
+ expectTypeOf(result).toEqualTypeOf<{
106
+ 'use functions must return the result of next()': true
107
+ '~types': {
108
+ context: {
109
+ c: number
110
+ }
111
+ sendContext: undefined
112
+ }
113
+ context: { a: boolean; b: string; c: number }
114
+ sendContext: undefined
115
+ }>()
116
+
117
+ return result
118
+ })
119
+
120
+ createMiddleware({ type: 'function' })
121
+ .middleware([middleware3])
122
+ .server(async (options) => {
123
+ expectTypeOf(options.context).toEqualTypeOf<{
124
+ a: boolean
125
+ b: string
126
+ c: number
127
+ }>()
128
+
129
+ const result = await options.next({ context: { d: 5 } })
130
+
131
+ expectTypeOf(result).toEqualTypeOf<{
132
+ 'use functions must return the result of next()': true
133
+ '~types': {
134
+ context: {
135
+ d: number
136
+ }
137
+ sendContext: undefined
138
+ }
139
+ context: { a: boolean; b: string; c: number; d: number }
140
+ sendContext: undefined
141
+ }>()
142
+
143
+ return result
144
+ })
145
+ })
146
+
147
+ test('createMiddleware merges client context and sends to the server', () => {
148
+ const middleware1 = createMiddleware({ type: 'function' }).client(
149
+ async (options) => {
150
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
151
+
152
+ const result = await options.next({ context: { a: true } })
153
+
154
+ expectTypeOf(result).toEqualTypeOf<{
155
+ 'use functions must return the result of next()': true
156
+ context: { a: boolean }
157
+ sendContext: undefined
158
+ headers: HeadersInit
159
+ fetch?: CustomFetch
160
+ }>()
161
+
162
+ return result
163
+ },
164
+ )
165
+
166
+ const middleware2 = createMiddleware({ type: 'function' }).client(
167
+ async (options) => {
168
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
169
+
170
+ const result = await options.next({ context: { b: 'test' } })
171
+
172
+ expectTypeOf(result).toEqualTypeOf<{
173
+ 'use functions must return the result of next()': true
174
+ context: { b: string }
175
+ sendContext: undefined
176
+ headers: HeadersInit
177
+ fetch?: CustomFetch
178
+ }>()
179
+
180
+ return result
181
+ },
182
+ )
183
+
184
+ const middleware3 = createMiddleware({ type: 'function' })
185
+ .middleware([middleware1, middleware2])
186
+ .client(async (options) => {
187
+ expectTypeOf(options.context).toEqualTypeOf<{ a: boolean; b: string }>()
188
+
189
+ const result = await options.next({ context: { c: 0 } })
190
+
191
+ expectTypeOf(result).toEqualTypeOf<{
192
+ 'use functions must return the result of next()': true
193
+ context: { a: boolean; b: string; c: number }
194
+ sendContext: undefined
195
+ headers: HeadersInit
196
+ fetch?: CustomFetch
197
+ }>()
198
+
199
+ return result
200
+ })
201
+
202
+ const middleware4 = createMiddleware({ type: 'function' })
203
+ .middleware([middleware3])
204
+ .client(async (options) => {
205
+ expectTypeOf(options.context).toEqualTypeOf<{
206
+ a: boolean
207
+ b: string
208
+ c: number
209
+ }>()
210
+
211
+ const result = await options.next({
212
+ sendContext: { ...options.context, d: 5 },
213
+ })
214
+
215
+ expectTypeOf(result).toEqualTypeOf<{
216
+ 'use functions must return the result of next()': true
217
+ context: { a: boolean; b: string; c: number }
218
+ sendContext: { a: boolean; b: string; c: number; d: 5 }
219
+ headers: HeadersInit
220
+ fetch?: CustomFetch
221
+ }>()
222
+
223
+ return result
224
+ })
225
+
226
+ createMiddleware({ type: 'function' })
227
+ .middleware([middleware4])
228
+ .server(async (options) => {
229
+ expectTypeOf(options.context).toEqualTypeOf<{
230
+ a: boolean
231
+ b: string
232
+ c: number
233
+ d: 5
234
+ }>()
235
+
236
+ const result = await options.next({
237
+ context: {
238
+ e: 'e',
239
+ },
240
+ })
241
+
242
+ expectTypeOf(result).toEqualTypeOf<{
243
+ 'use functions must return the result of next()': true
244
+ '~types': {
245
+ context: {
246
+ e: string
247
+ }
248
+ sendContext: undefined
249
+ }
250
+ context: { a: boolean; b: string; c: number; d: 5; e: string }
251
+ sendContext: undefined
252
+ }>()
253
+
254
+ return result
255
+ })
256
+ })
257
+
258
+ test('createMiddleware merges input', () => {
259
+ const middleware1 = createMiddleware({ type: 'function' })
260
+ .inputValidator(() => {
261
+ return {
262
+ a: 'a',
263
+ } as const
264
+ })
265
+ .server(({ data, next }) => {
266
+ expectTypeOf(data).toEqualTypeOf<{ readonly a: 'a' }>()
267
+ return next()
268
+ })
269
+
270
+ const middleware2 = createMiddleware({ type: 'function' })
271
+ .middleware([middleware1])
272
+ .inputValidator(() => {
273
+ return {
274
+ b: 'b',
275
+ } as const
276
+ })
277
+ .server(({ data, next }) => {
278
+ expectTypeOf(data).toEqualTypeOf<{ readonly a: 'a'; readonly b: 'b' }>
279
+ return next()
280
+ })
281
+
282
+ createMiddleware({ type: 'function' })
283
+ .middleware([middleware2])
284
+ .inputValidator(() => ({ c: 'c' }) as const)
285
+ .server(({ next, data }) => {
286
+ expectTypeOf(data).toEqualTypeOf<{
287
+ readonly a: 'a'
288
+ readonly b: 'b'
289
+ readonly c: 'c'
290
+ }>
291
+ return next()
292
+ })
293
+ })
294
+
295
+ test('createMiddleware merges server context and client context, sends server context to the client and merges ', () => {
296
+ const middleware1 = createMiddleware({ type: 'function' })
297
+ .client(async (options) => {
298
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
299
+
300
+ const result = await options.next({
301
+ context: { fromClient1: 'fromClient1' },
302
+ })
303
+
304
+ expectTypeOf(result).toEqualTypeOf<{
305
+ 'use functions must return the result of next()': true
306
+ context: { fromClient1: string }
307
+ sendContext: undefined
308
+ headers: HeadersInit
309
+ fetch?: CustomFetch
310
+ }>()
311
+
312
+ return result
313
+ })
314
+ .server(async (options) => {
315
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
316
+
317
+ const result = await options.next({
318
+ context: { fromServer1: 'fromServer1' },
319
+ })
320
+
321
+ expectTypeOf(result).toEqualTypeOf<{
322
+ 'use functions must return the result of next()': true
323
+ '~types': {
324
+ context: {
325
+ fromServer1: string
326
+ }
327
+ sendContext: undefined
328
+ }
329
+ context: { fromServer1: string }
330
+ sendContext: undefined
331
+ }>()
332
+
333
+ return result
334
+ })
335
+
336
+ const middleware2 = createMiddleware({ type: 'function' })
337
+ .client(async (options) => {
338
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
339
+
340
+ const result = await options.next({
341
+ context: { fromClient2: 'fromClient2' },
342
+ })
343
+
344
+ expectTypeOf(result).toEqualTypeOf<{
345
+ 'use functions must return the result of next()': true
346
+ context: { fromClient2: string }
347
+ sendContext: undefined
348
+ headers: HeadersInit
349
+ fetch?: CustomFetch
350
+ }>()
351
+
352
+ return result
353
+ })
354
+ .server(async (options) => {
355
+ expectTypeOf(options.context).toEqualTypeOf<undefined>()
356
+
357
+ const result = await options.next({
358
+ context: { fromServer2: 'fromServer2' },
359
+ })
360
+
361
+ expectTypeOf(result).toEqualTypeOf<{
362
+ 'use functions must return the result of next()': true
363
+ '~types': {
364
+ context: {
365
+ fromServer2: string
366
+ }
367
+ sendContext: undefined
368
+ }
369
+ context: { fromServer2: string }
370
+ sendContext: undefined
371
+ }>()
372
+
373
+ return result
374
+ })
375
+
376
+ const middleware3 = createMiddleware({ type: 'function' })
377
+ .middleware([middleware1, middleware2])
378
+ .client(async (options) => {
379
+ expectTypeOf(options.context).toEqualTypeOf<{
380
+ fromClient1: string
381
+ fromClient2: string
382
+ }>()
383
+
384
+ const result = await options.next({
385
+ context: { fromClient3: 'fromClient3' },
386
+ })
387
+
388
+ expectTypeOf(result).toEqualTypeOf<{
389
+ 'use functions must return the result of next()': true
390
+ context: {
391
+ fromClient1: string
392
+ fromClient2: string
393
+ fromClient3: string
394
+ }
395
+ sendContext: undefined
396
+ headers: HeadersInit
397
+ fetch?: CustomFetch
398
+ }>()
399
+
400
+ return result
401
+ })
402
+ .server(async (options) => {
403
+ expectTypeOf(options.context).toEqualTypeOf<{
404
+ fromServer1: string
405
+ fromServer2: string
406
+ }>()
407
+
408
+ const result = await options.next({
409
+ context: { fromServer3: 'fromServer3' },
410
+ })
411
+
412
+ expectTypeOf(result).toEqualTypeOf<{
413
+ 'use functions must return the result of next()': true
414
+ '~types': {
415
+ context: {
416
+ fromServer3: string
417
+ }
418
+ sendContext: undefined
419
+ }
420
+ context: {
421
+ fromServer1: string
422
+ fromServer2: string
423
+ fromServer3: string
424
+ }
425
+ sendContext: undefined
426
+ }>()
427
+
428
+ return result
429
+ })
430
+
431
+ const middleware4 = createMiddleware({ type: 'function' })
432
+ .middleware([middleware3])
433
+ .client(async (options) => {
434
+ expectTypeOf(options.context).toEqualTypeOf<{
435
+ fromClient1: string
436
+ fromClient2: string
437
+ fromClient3: string
438
+ }>()
439
+
440
+ const result = await options.next({
441
+ context: { fromClient4: 'fromClient4' },
442
+ sendContext: { toServer1: 'toServer1' },
443
+ })
444
+
445
+ expectTypeOf(result).toEqualTypeOf<{
446
+ 'use functions must return the result of next()': true
447
+ context: {
448
+ fromClient1: string
449
+ fromClient2: string
450
+ fromClient3: string
451
+ fromClient4: string
452
+ }
453
+ sendContext: { toServer1: 'toServer1' }
454
+ headers: HeadersInit
455
+ fetch?: CustomFetch
456
+ }>()
457
+
458
+ return result
459
+ })
460
+ .server(async (options) => {
461
+ expectTypeOf(options.context).toEqualTypeOf<{
462
+ fromServer1: string
463
+ fromServer2: string
464
+ fromServer3: string
465
+ toServer1: 'toServer1'
466
+ }>()
467
+
468
+ const result = await options.next({
469
+ context: { fromServer4: 'fromServer4' },
470
+ sendContext: { toClient1: 'toClient1' },
471
+ })
472
+
473
+ expectTypeOf(result).toEqualTypeOf<{
474
+ 'use functions must return the result of next()': true
475
+ '~types': {
476
+ context: {
477
+ fromServer4: string
478
+ }
479
+ sendContext: {
480
+ toClient1: 'toClient1'
481
+ }
482
+ }
483
+ context: {
484
+ fromServer1: string
485
+ fromServer2: string
486
+ fromServer3: string
487
+ fromServer4: string
488
+ toServer1: 'toServer1'
489
+ }
490
+ sendContext: { toClient1: 'toClient1' }
491
+ }>()
492
+
493
+ return result
494
+ })
495
+
496
+ createMiddleware({ type: 'function' })
497
+ .middleware([middleware4])
498
+ .client(async (options) => {
499
+ expectTypeOf(options.context).toEqualTypeOf<{
500
+ fromClient1: string
501
+ fromClient2: string
502
+ fromClient3: string
503
+ fromClient4: string
504
+ }>()
505
+
506
+ const result = await options.next({
507
+ context: { fromClient5: 'fromClient5' },
508
+ sendContext: { toServer2: 'toServer2' },
509
+ })
510
+
511
+ expectTypeOf(result).toEqualTypeOf<{
512
+ 'use functions must return the result of next()': true
513
+ context: {
514
+ fromClient1: string
515
+ fromClient2: string
516
+ fromClient3: string
517
+ fromClient4: string
518
+ fromClient5: string
519
+ toClient1: 'toClient1'
520
+ }
521
+ sendContext: { toServer1: 'toServer1'; toServer2: 'toServer2' }
522
+ headers: HeadersInit
523
+ fetch?: CustomFetch
524
+ }>()
525
+
526
+ return result
527
+ })
528
+ .server(async (options) => {
529
+ expectTypeOf(options.context).toEqualTypeOf<{
530
+ fromServer1: string
531
+ fromServer2: string
532
+ fromServer3: string
533
+ fromServer4: string
534
+ toServer1: 'toServer1'
535
+ toServer2: 'toServer2'
536
+ }>()
537
+
538
+ const result = await options.next({
539
+ context: { fromServer5: 'fromServer5' },
540
+ sendContext: { toClient2: 'toClient2' },
541
+ })
542
+
543
+ expectTypeOf(result).toEqualTypeOf<{
544
+ 'use functions must return the result of next()': true
545
+ '~types': {
546
+ context: {
547
+ fromServer5: string
548
+ }
549
+ sendContext: {
550
+ toClient2: 'toClient2'
551
+ }
552
+ }
553
+ context: {
554
+ fromServer1: string
555
+ fromServer2: string
556
+ fromServer3: string
557
+ fromServer4: string
558
+ fromServer5: string
559
+ toServer1: 'toServer1'
560
+ toServer2: 'toServer2'
561
+ }
562
+ sendContext: { toClient1: 'toClient1'; toClient2: 'toClient2' }
563
+ }>()
564
+
565
+ return result
566
+ })
567
+ })
568
+
569
+ test('createMiddleware sendContext cannot send a function', () => {
570
+ createMiddleware({ type: 'function' })
571
+ .client(({ next }) => {
572
+ expectTypeOf(next<{ func: () => 'func' }>)
573
+ .parameter(0)
574
+ .exclude<undefined>()
575
+ .toHaveProperty('sendContext')
576
+ .toEqualTypeOf<{ func: 'Function is not serializable' } | undefined>()
577
+
578
+ return next()
579
+ })
580
+ .server(({ next }) => {
581
+ expectTypeOf(next<undefined, { func: () => 'func' }>)
582
+ .parameter(0)
583
+ .exclude<undefined>()
584
+ .toHaveProperty('sendContext')
585
+ .toEqualTypeOf<{ func: 'Function is not serializable' } | undefined>()
586
+
587
+ return next()
588
+ })
589
+ })
590
+
591
+ test('createMiddleware cannot validate function', () => {
592
+ const validator = createMiddleware({ type: 'function' }).inputValidator<
593
+ (input: { func: () => 'string' }) => { output: 'string' }
594
+ >
595
+
596
+ expectTypeOf(validator)
597
+ .parameter(0)
598
+ .toEqualTypeOf<
599
+ ConstrainValidator<
600
+ Register,
601
+ 'GET',
602
+ (input: { func: () => 'string' }) => { output: 'string' }
603
+ >
604
+ >()
605
+ })
606
+
607
+ test('createMiddleware can validate Date', () => {
608
+ const validator = createMiddleware({ type: 'function' }).inputValidator<
609
+ (input: Date) => { output: 'string' }
610
+ >
611
+
612
+ expectTypeOf(validator)
613
+ .parameter(0)
614
+ .toEqualTypeOf<
615
+ ConstrainValidator<Register, 'GET', (input: Date) => { output: 'string' }>
616
+ >()
617
+ })
618
+
619
+ test('createMiddleware can validate FormData', () => {
620
+ const validator = createMiddleware({ type: 'function' }).inputValidator<
621
+ (input: FormData) => { output: 'string' }
622
+ >
623
+
624
+ expectTypeOf(validator)
625
+ .parameter(0)
626
+ .toEqualTypeOf<
627
+ ConstrainValidator<
628
+ Register,
629
+ 'GET',
630
+ (input: FormData) => { output: 'string' }
631
+ >
632
+ >()
633
+ })
634
+
635
+ test('createMiddleware merging from parent with undefined validator', () => {
636
+ const middleware1 = createMiddleware({ type: 'function' }).inputValidator(
637
+ (input: { test: string }) => input.test,
638
+ )
639
+
640
+ createMiddleware({ type: 'function' })
641
+ .middleware([middleware1])
642
+ .server((ctx) => {
643
+ expectTypeOf(ctx.data).toEqualTypeOf<string>()
644
+
645
+ return ctx.next()
646
+ })
647
+ })
648
+
649
+ test('createMiddleware validator infers unknown for default input type', () => {
650
+ createMiddleware({ type: 'function' })
651
+ .inputValidator((input) => {
652
+ expectTypeOf(input).toEqualTypeOf<unknown>()
653
+
654
+ if (typeof input === 'number') return 'success' as const
655
+
656
+ return 'failed' as const
657
+ })
658
+ .server(({ data, next }) => {
659
+ expectTypeOf(data).toEqualTypeOf<'success' | 'failed'>()
660
+
661
+ return next()
662
+ })
663
+ })
664
+
665
+ test('createMiddleware with type request, no middleware or context', () => {
666
+ createMiddleware({ type: 'request' }).server(async (options) => {
667
+ expectTypeOf(options).toEqualTypeOf<{
668
+ request: Request
669
+ next: RequestServerNextFn<{}, undefined>
670
+ pathname: string
671
+ context: undefined
672
+ serverFnMeta?: ServerFnMeta
673
+ }>()
674
+
675
+ const result = await options.next()
676
+
677
+ expectTypeOf(result).toEqualTypeOf<{
678
+ context: undefined
679
+ pathname: string
680
+ request: Request
681
+ response: Response
682
+ }>()
683
+
684
+ return result
685
+ })
686
+ })
687
+
688
+ test('createMiddleware with type request, no middleware with context', () => {
689
+ createMiddleware({ type: 'request' }).server(async (options) => {
690
+ expectTypeOf(options).toEqualTypeOf<{
691
+ request: Request
692
+ next: RequestServerNextFn<{}, undefined>
693
+ pathname: string
694
+ context: undefined
695
+ serverFnMeta?: ServerFnMeta
696
+ }>()
697
+
698
+ const result = await options.next({ context: { a: 'a' } })
699
+
700
+ expectTypeOf(result).toEqualTypeOf<{
701
+ context: { a: string }
702
+ pathname: string
703
+ request: Request
704
+ response: Response
705
+ }>()
706
+
707
+ return result
708
+ })
709
+ })
710
+
711
+ test('createMiddleware with type request, middleware and context', () => {
712
+ const middleware1 = createMiddleware({ type: 'request' }).server(
713
+ async (options) => {
714
+ expectTypeOf(options).toEqualTypeOf<{
715
+ request: Request
716
+ next: RequestServerNextFn<{}, undefined>
717
+ pathname: string
718
+ context: undefined
719
+ serverFnMeta?: ServerFnMeta
720
+ }>()
721
+
722
+ const result = await options.next({ context: { a: 'a' } })
723
+
724
+ expectTypeOf(result).toEqualTypeOf<{
725
+ context: { a: string }
726
+ pathname: string
727
+ request: Request
728
+ response: Response
729
+ }>()
730
+
731
+ return result
732
+ },
733
+ )
734
+
735
+ createMiddleware({ type: 'request' })
736
+ .middleware([middleware1])
737
+ .server(async (options) => {
738
+ expectTypeOf(options).toEqualTypeOf<{
739
+ request: Request
740
+ next: RequestServerNextFn<{}, undefined>
741
+ pathname: string
742
+ context: { a: string }
743
+ serverFnMeta?: ServerFnMeta
744
+ }>()
745
+
746
+ const result = await options.next({ context: { b: 'b' } })
747
+
748
+ expectTypeOf(result).toEqualTypeOf<{
749
+ context: { a: string; b: string }
750
+ pathname: string
751
+ request: Request
752
+ response: Response
753
+ }>()
754
+
755
+ return result
756
+ })
757
+ })
758
+
759
+ test('createMiddleware with type request can return Response directly', () => {
760
+ createMiddleware({ type: 'request' }).server(async (options) => {
761
+ expectTypeOf(options).toEqualTypeOf<{
762
+ request: Request
763
+ next: RequestServerNextFn<{}, undefined>
764
+ pathname: string
765
+ context: undefined
766
+ serverFnMeta?: ServerFnMeta
767
+ }>()
768
+
769
+ // Should be able to return a Response directly
770
+ if (Math.random() > 0.5) {
771
+ return new Response('Unauthorized', { status: 401 })
772
+ }
773
+
774
+ // Or return the result from next()
775
+ return options.next()
776
+ })
777
+ })
778
+
779
+ test('createMiddleware with type request can return Promise<Response>', () => {
780
+ createMiddleware({ type: 'request' }).server(async (options) => {
781
+ expectTypeOf(options).toEqualTypeOf<{
782
+ request: Request
783
+ next: RequestServerNextFn<{}, undefined>
784
+ pathname: string
785
+ context: undefined
786
+ serverFnMeta?: ServerFnMeta
787
+ }>()
788
+
789
+ // Should be able to return a Promise<Response>
790
+ return Promise.resolve(new Response('OK', { status: 200 }))
791
+ })
792
+ })
793
+
794
+ test('createMiddleware with type request can return sync Response', () => {
795
+ createMiddleware({ type: 'request' }).server((options) => {
796
+ expectTypeOf(options).toEqualTypeOf<{
797
+ request: Request
798
+ next: RequestServerNextFn<{}, undefined>
799
+ pathname: string
800
+ context: undefined
801
+ serverFnMeta?: ServerFnMeta
802
+ }>()
803
+
804
+ // Should be able to return a synchronous Response
805
+ return new Response(JSON.stringify({ error: 'Not Found' }), {
806
+ status: 404,
807
+ headers: { 'Content-Type': 'application/json' },
808
+ })
809
+ })
810
+ })