@orpc/server 0.10.0 → 0.11.0

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 (64) hide show
  1. package/dist/{chunk-TDFYNRZV.js → chunk-CVLK2PBB.js} +0 -1
  2. package/dist/fetch.js +1 -2
  3. package/dist/index.js +1 -2
  4. package/dist/src/adapters/fetch.d.ts +0 -1
  5. package/dist/src/builder.d.ts +0 -1
  6. package/dist/src/index.d.ts +0 -1
  7. package/dist/src/middleware.d.ts +0 -1
  8. package/dist/src/procedure-builder.d.ts +0 -1
  9. package/dist/src/procedure-caller.d.ts +0 -1
  10. package/dist/src/procedure-implementer.d.ts +0 -1
  11. package/dist/src/procedure.d.ts +0 -1
  12. package/dist/src/router-builder.d.ts +0 -1
  13. package/dist/src/router-caller.d.ts +0 -1
  14. package/dist/src/router-implementer.d.ts +0 -1
  15. package/dist/src/router.d.ts +0 -1
  16. package/dist/src/types.d.ts +0 -1
  17. package/dist/src/utils.d.ts +0 -1
  18. package/package.json +12 -16
  19. package/dist/chunk-TDFYNRZV.js.map +0 -1
  20. package/dist/fetch.js.map +0 -1
  21. package/dist/index.js.map +0 -1
  22. package/dist/src/adapters/fetch.d.ts.map +0 -1
  23. package/dist/src/builder.d.ts.map +0 -1
  24. package/dist/src/index.d.ts.map +0 -1
  25. package/dist/src/middleware.d.ts.map +0 -1
  26. package/dist/src/procedure-builder.d.ts.map +0 -1
  27. package/dist/src/procedure-caller.d.ts.map +0 -1
  28. package/dist/src/procedure-implementer.d.ts.map +0 -1
  29. package/dist/src/procedure.d.ts.map +0 -1
  30. package/dist/src/router-builder.d.ts.map +0 -1
  31. package/dist/src/router-caller.d.ts.map +0 -1
  32. package/dist/src/router-implementer.d.ts.map +0 -1
  33. package/dist/src/router.d.ts.map +0 -1
  34. package/dist/src/types.d.ts.map +0 -1
  35. package/dist/src/utils.d.ts.map +0 -1
  36. package/dist/tsconfig.tsbuildinfo +0 -1
  37. package/src/adapters/fetch.test.ts +0 -629
  38. package/src/adapters/fetch.ts +0 -290
  39. package/src/builder.test.ts +0 -371
  40. package/src/builder.ts +0 -238
  41. package/src/index.ts +0 -16
  42. package/src/middleware.test.ts +0 -260
  43. package/src/middleware.ts +0 -136
  44. package/src/procedure-builder.test.ts +0 -223
  45. package/src/procedure-builder.ts +0 -158
  46. package/src/procedure-caller.test.ts +0 -171
  47. package/src/procedure-caller.ts +0 -138
  48. package/src/procedure-implementer.test.ts +0 -220
  49. package/src/procedure-implementer.ts +0 -102
  50. package/src/procedure.test.ts +0 -317
  51. package/src/procedure.ts +0 -237
  52. package/src/router-builder.test.ts +0 -106
  53. package/src/router-builder.ts +0 -122
  54. package/src/router-caller.test.ts +0 -126
  55. package/src/router-caller.ts +0 -64
  56. package/src/router-implementer.test.ts +0 -116
  57. package/src/router-implementer.ts +0 -113
  58. package/src/router.test-d.ts +0 -48
  59. package/src/router.test.ts +0 -142
  60. package/src/router.ts +0 -91
  61. package/src/types.test.ts +0 -18
  62. package/src/types.ts +0 -13
  63. package/src/utils.test.ts +0 -16
  64. package/src/utils.ts +0 -16
@@ -1,220 +0,0 @@
1
- import type { DecoratedProcedure, Meta, MiddlewareMeta } from '.'
2
- import { DecoratedContractProcedure } from '@orpc/contract'
3
- import { z } from 'zod'
4
- import { isProcedure, os } from '.'
5
- import { ProcedureImplementer } from './procedure-implementer'
6
-
7
- const p1 = new DecoratedContractProcedure({
8
- InputSchema: undefined,
9
- OutputSchema: undefined,
10
- method: undefined,
11
- path: undefined,
12
- })
13
- const implementer1 = new ProcedureImplementer<
14
- { auth: boolean },
15
- undefined,
16
- undefined,
17
- undefined
18
- >({ contract: p1 })
19
-
20
- const schema1 = z.object({ id: z.string() })
21
- const schema2 = z.object({ name: z.string() })
22
-
23
- const p2 = new DecoratedContractProcedure({
24
- InputSchema: schema1,
25
- OutputSchema: schema2,
26
- method: 'GET',
27
- path: '/test',
28
- })
29
-
30
- const implementer2 = new ProcedureImplementer<
31
- { auth: boolean },
32
- undefined,
33
- typeof schema1,
34
- typeof schema2
35
- >({ contract: p2 })
36
-
37
- describe('use middleware', () => {
38
- it('infer types', () => {
39
- const i = implementer1
40
- .use((input, context, meta) => {
41
- expectTypeOf(input).toEqualTypeOf<unknown>()
42
- expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
43
- expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<unknown>>()
44
-
45
- return meta.next({
46
- context: {
47
- userId: '1',
48
- },
49
- })
50
- })
51
- .use((input, context, meta) => {
52
- expectTypeOf(input).toEqualTypeOf<unknown>()
53
- expectTypeOf(context).toEqualTypeOf<
54
- { userId: string } & { auth: boolean }
55
- >()
56
- expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<unknown>>()
57
-
58
- return meta.next({})
59
- })
60
-
61
- expectTypeOf(i).toEqualTypeOf<
62
- ProcedureImplementer<
63
- { auth: boolean },
64
- { userId: string },
65
- undefined,
66
- undefined
67
- >
68
- >()
69
- })
70
-
71
- it('map middleware input', () => {
72
- // @ts-expect-error mismatch input
73
- implementer2.use((input: { postId: string }) => {
74
- return { context: { a: 'a' } }
75
- })
76
-
77
- implementer2.use(
78
- (input: { postId: string }, _, meta) => {
79
- return meta.next({ context: { a: 'a' } })
80
- },
81
- // @ts-expect-error mismatch input
82
- input => ({ postId: 12455 }),
83
- )
84
-
85
- implementer2.use(
86
- (input: { postId: string }, context, meta) => meta.next({}),
87
- input => ({ postId: '12455' }),
88
- )
89
-
90
- const i = implementer2.use(
91
- (input: { id: number }, _, meta) => {
92
- return meta.next({
93
- context: {
94
- userIdd: '1',
95
- },
96
- })
97
- },
98
- input => ({ id: Number.parseInt(input.id) }),
99
- )
100
-
101
- expectTypeOf(i).toEqualTypeOf<
102
- ProcedureImplementer<
103
- { auth: boolean },
104
- { userIdd: string },
105
- typeof schema1,
106
- typeof schema2
107
- >
108
- >()
109
- })
110
- })
111
-
112
- describe('output schema', () => {
113
- it('auto infer output schema if output schema is not specified', async () => {
114
- const sr = os.func(() => ({ a: 1 }))
115
-
116
- const result = await sr.zz$p.func({}, undefined, {
117
- method: 'GET',
118
- path: '/',
119
- } as any)
120
-
121
- expectTypeOf(result).toEqualTypeOf<{ a: number }>()
122
- })
123
-
124
- it('not infer output schema if output schema is specified', async () => {
125
- const srb1 = new ProcedureImplementer({
126
- contract: new DecoratedContractProcedure({
127
- OutputSchema: z.unknown(),
128
- InputSchema: undefined,
129
- }),
130
- })
131
-
132
- const sr = srb1.func(() => ({ b: 1 }))
133
-
134
- const result = await sr.zz$p.func({}, {}, {
135
- method: 'GET',
136
- path: '/',
137
- } as any)
138
-
139
- expectTypeOf(result).toEqualTypeOf<unknown>()
140
- })
141
- })
142
-
143
- describe('handler', () => {
144
- it('infer types', () => {
145
- const handler = implementer1.func((input, context, meta) => {
146
- expectTypeOf(input).toEqualTypeOf<unknown>()
147
- expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
148
- expectTypeOf(meta).toEqualTypeOf<Meta>()
149
-
150
- return {
151
- name: 'unnoq',
152
- }
153
- })
154
-
155
- expectTypeOf(handler).toEqualTypeOf<
156
- DecoratedProcedure<
157
- { auth: boolean },
158
- undefined,
159
- undefined,
160
- undefined,
161
- { name: string }
162
- >
163
- >()
164
- expect(isProcedure(handler)).toBe(true)
165
-
166
- implementer2.func((input, context, meta) => {
167
- expectTypeOf(input).toEqualTypeOf<{ id: string }>()
168
- expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
169
- expectTypeOf(meta).toEqualTypeOf<Meta>()
170
-
171
- return {
172
- name: 'unnoq',
173
- }
174
- })
175
-
176
- // @ts-expect-error mismatch output
177
- implementer2.func(() => {})
178
- })
179
-
180
- it('combine middlewares', () => {
181
- const mid1 = os.middleware((input, context, meta) => {
182
- return meta.next({
183
- context: {
184
- userId: '1',
185
- },
186
- })
187
- })
188
-
189
- const mid2 = os.middleware((input, context, meta) => {
190
- return meta.next({ })
191
- })
192
-
193
- const handler = implementer2
194
- .use(mid1)
195
- .use(mid2)
196
- .func((input, context, meta) => {
197
- expectTypeOf(input).toEqualTypeOf<{ id: string }>()
198
- expectTypeOf(context).toEqualTypeOf<
199
- { auth: boolean } & { userId: string }
200
- >()
201
- expectTypeOf(meta).toEqualTypeOf<Meta>()
202
-
203
- return {
204
- name: 'unnoq',
205
- }
206
- })
207
-
208
- expectTypeOf(handler).toEqualTypeOf<
209
- DecoratedProcedure<
210
- { auth: boolean },
211
- { userId: string },
212
- typeof schema1,
213
- typeof schema2,
214
- { name: string }
215
- >
216
- >()
217
-
218
- expect(handler.zz$p.middlewares).toEqual([mid1, mid2])
219
- })
220
- })
@@ -1,102 +0,0 @@
1
- import type { ContractProcedure, Schema, SchemaInput, SchemaOutput } from '@orpc/contract'
2
- import type { Context, MergeContext } from './types'
3
- import {
4
- decorateMiddleware,
5
- type MapInputMiddleware,
6
- type Middleware,
7
- } from './middleware'
8
- import {
9
- type DecoratedProcedure,
10
- decorateProcedure,
11
- type ProcedureFunc,
12
- } from './procedure'
13
-
14
- export class ProcedureImplementer<
15
- TContext extends Context,
16
- TExtraContext extends Context,
17
- TInputSchema extends Schema,
18
- TOutputSchema extends Schema,
19
- > {
20
- constructor(
21
- public zz$pi: {
22
- contract: ContractProcedure<TInputSchema, TOutputSchema>
23
- middlewares?: Middleware<any, any, any, any>[]
24
- },
25
- ) {}
26
-
27
- use<
28
- UExtraContext extends
29
- | Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>>
30
- | undefined = undefined,
31
- >(
32
- middleware: Middleware<
33
- MergeContext<TContext, TExtraContext>,
34
- UExtraContext,
35
- SchemaOutput<TInputSchema>,
36
- SchemaInput<TOutputSchema>
37
- >,
38
- ): ProcedureImplementer<
39
- TContext,
40
- MergeContext<TExtraContext, UExtraContext>,
41
- TInputSchema,
42
- TOutputSchema
43
- >
44
-
45
- use<
46
- UExtraContext extends
47
- | Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>>
48
- | undefined = undefined,
49
- UMappedInput = unknown,
50
- >(
51
- middleware: Middleware<
52
- MergeContext<TContext, TExtraContext>,
53
- UExtraContext,
54
- UMappedInput,
55
- SchemaInput<TOutputSchema>
56
- >,
57
- mapInput: MapInputMiddleware<SchemaOutput<TInputSchema>, UMappedInput>,
58
- ): ProcedureImplementer<
59
- TContext,
60
- MergeContext<TExtraContext, UExtraContext>,
61
- TInputSchema,
62
- TOutputSchema
63
- >
64
-
65
- use(
66
- middleware: Middleware<any, any, any, any>,
67
- mapInput?: MapInputMiddleware<any, any>,
68
- ): ProcedureImplementer<any, any, any, any> {
69
- const middleware_ = mapInput
70
- ? decorateMiddleware(middleware).mapInput(mapInput)
71
- : middleware
72
-
73
- return new ProcedureImplementer({
74
- ...this.zz$pi,
75
- middlewares: [...(this.zz$pi.middlewares ?? []), middleware_],
76
- })
77
- }
78
-
79
- func<UFuncOutput extends SchemaOutput<TOutputSchema>>(
80
- func: ProcedureFunc<
81
- TContext,
82
- TExtraContext,
83
- TInputSchema,
84
- TOutputSchema,
85
- UFuncOutput
86
- >,
87
- ): DecoratedProcedure<
88
- TContext,
89
- TExtraContext,
90
- TInputSchema,
91
- TOutputSchema,
92
- UFuncOutput
93
- > {
94
- return decorateProcedure({
95
- zz$p: {
96
- middlewares: this.zz$pi.middlewares,
97
- contract: this.zz$pi.contract,
98
- func,
99
- },
100
- })
101
- }
102
- }
@@ -1,317 +0,0 @@
1
- import type { MiddlewareMeta } from '.'
2
- import { ContractProcedure, DecoratedContractProcedure } from '@orpc/contract'
3
- import { z } from 'zod'
4
- import { os } from '.'
5
- import {
6
- type DecoratedProcedure,
7
- decorateProcedure,
8
- isProcedure,
9
- Procedure,
10
- } from './procedure'
11
-
12
- it('isProcedure', () => {
13
- expect(
14
- isProcedure(
15
- decorateProcedure(
16
- new Procedure({
17
- contract: new ContractProcedure({
18
- InputSchema: undefined,
19
- OutputSchema: undefined,
20
- }),
21
- func: () => {},
22
- }),
23
- ),
24
- ),
25
- ).toBe(true)
26
- expect({
27
- zz$p: {
28
- contract: new DecoratedContractProcedure({
29
- InputSchema: undefined,
30
- OutputSchema: undefined,
31
- }),
32
- func: () => {},
33
- },
34
- }).toSatisfy(isProcedure)
35
-
36
- expect({
37
- zz$p: {
38
- contract: new DecoratedContractProcedure({
39
- InputSchema: undefined,
40
- OutputSchema: undefined,
41
- }),
42
- },
43
- }).not.toSatisfy(isProcedure)
44
-
45
- expect({
46
- zz$p: {
47
- handler: () => {},
48
- },
49
- }).not.toSatisfy(isProcedure)
50
-
51
- expect({}).not.toSatisfy(isProcedure)
52
- expect(12233).not.toSatisfy(isProcedure)
53
- expect('12233').not.toSatisfy(isProcedure)
54
- expect(undefined).not.toSatisfy(isProcedure)
55
- expect(null).not.toSatisfy(isProcedure)
56
- })
57
-
58
- describe('route method', () => {
59
- it('sets route options correctly', () => {
60
- const p = os.context<{ auth: boolean }>().func(() => {
61
- return 'test'
62
- })
63
-
64
- const p2 = p.route({ path: '/test', method: 'GET' })
65
-
66
- expect(p2.zz$p.contract.zz$cp.path).toBe('/test')
67
- expect(p2.zz$p.contract.zz$cp.method).toBe('GET')
68
- })
69
-
70
- it('preserves existing context and handler', () => {
71
- const handler = () => 'test'
72
- const p = os.context<{ auth: boolean }>().func(handler)
73
-
74
- const p2 = p.route({ path: '/test' })
75
-
76
- expect(p2.zz$p.func).toBe(handler)
77
- // Context type is preserved through the route method
78
- expectTypeOf(p2).toEqualTypeOf<
79
- DecoratedProcedure<
80
- { auth: boolean },
81
- undefined,
82
- undefined,
83
- undefined,
84
- string
85
- >
86
- >()
87
- })
88
-
89
- it('works with prefix method', () => {
90
- const p = os
91
- .context<{ auth: boolean }>()
92
- .route({ path: '/api', method: 'POST' })
93
- .func(() => 'test')
94
-
95
- const p2 = p.prefix('/v1')
96
-
97
- expect(p2.zz$p.contract.zz$cp.path).toBe('/v1/api')
98
- expect(p2.zz$p.contract.zz$cp.method).toBe('POST')
99
- })
100
-
101
- it('works with middleware', () => {
102
- const mid = os.middleware((_, __, meta) => meta.next({ context: { userId: '1' } }))
103
-
104
- const p = os
105
- .context<{ auth: boolean }>()
106
- .route({ path: '/test' })
107
- .use(mid)
108
- .func((input, context) => {
109
- expectTypeOf(context).toEqualTypeOf<
110
- { auth: boolean } & { userId: string }
111
- >()
112
- return 'test'
113
- })
114
-
115
- expect(p.zz$p.contract.zz$cp.path).toBe('/test')
116
- expect(p.zz$p.middlewares).toEqual([mid])
117
- })
118
-
119
- it('overrides existing route options', () => {
120
- const p = os
121
- .context<{ auth: boolean }>()
122
- .route({ path: '/test1', method: 'GET' })
123
- .func(() => 'test')
124
-
125
- const p2 = p.route({ path: '/test2', method: 'POST' })
126
-
127
- expect(p2.zz$p.contract.zz$cp.path).toBe('/test2')
128
- expect(p2.zz$p.contract.zz$cp.method).toBe('POST')
129
- })
130
-
131
- it('preserves input/output schemas', () => {
132
- const inputSchema = z.object({ id: z.number() })
133
- const outputSchema = z.string()
134
- const p = os
135
- .context<{ auth: boolean }>()
136
- .input(inputSchema)
137
- .output(outputSchema)
138
- .route({ path: '/test' })
139
- .func((input) => {
140
- expectTypeOf(input).toEqualTypeOf<{ id: number }>()
141
- return 'test'
142
- })
143
-
144
- const p2 = p.route({ path: '/test2' })
145
-
146
- // Type checking that schemas are preserved
147
- expectTypeOf(p2).toEqualTypeOf<
148
- DecoratedProcedure<
149
- { auth: boolean },
150
- undefined,
151
- typeof inputSchema,
152
- typeof outputSchema,
153
- string
154
- >
155
- >()
156
- })
157
- })
158
-
159
- it('prefix method', () => {
160
- const p = os.context<{ auth: boolean }>().func(() => {
161
- return 'unnoq'
162
- })
163
-
164
- const p2 = p.prefix('/test')
165
-
166
- expect(p2.zz$p.contract.zz$cp.path).toBe(undefined)
167
-
168
- const p3 = os
169
- .context<{ auth: boolean }>()
170
- .route({ path: '/test1' })
171
- .func(() => {
172
- return 'unnoq'
173
- })
174
-
175
- const p4 = p3.prefix('/test')
176
- expect(p4.zz$p.contract.zz$cp.path).toBe('/test/test1')
177
- })
178
-
179
- describe('use middleware', () => {
180
- it('infer types', () => {
181
- const p1 = os
182
- .context<{ auth: boolean }>()
183
- .use((_, __, meta) => {
184
- return meta.next({ context: { postId: 'string' } })
185
- })
186
- .func(() => {
187
- return 'unnoq'
188
- })
189
-
190
- const p2 = p1
191
- .use((input, context, meta) => {
192
- expectTypeOf(input).toEqualTypeOf<unknown>()
193
- expectTypeOf(context).toEqualTypeOf<
194
- { auth: boolean } & { postId: string }
195
- >()
196
- expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<string>>()
197
-
198
- return meta.next({
199
- context: {
200
- userId: '1',
201
- },
202
- })
203
- })
204
- .use((input, context, meta) => {
205
- expectTypeOf(input).toEqualTypeOf<unknown>()
206
- expectTypeOf(context).toEqualTypeOf<
207
- { userId: string } & { postId: string } & { auth: boolean }
208
- >()
209
- expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<string>>()
210
-
211
- return meta.next({})
212
- })
213
-
214
- expectTypeOf(p2).toEqualTypeOf<
215
- DecoratedProcedure<
216
- { auth: boolean },
217
- { postId: string } & { userId: string },
218
- undefined,
219
- undefined,
220
- string
221
- >
222
- >()
223
- })
224
-
225
- it('can map input', () => {
226
- const mid = os.middleware((input: { id: number }, __, meta) => {
227
- return meta.next({})
228
- })
229
-
230
- os.input(z.object({ postId: z.number() })).use(mid, (input) => {
231
- expectTypeOf(input).toEqualTypeOf<{ postId: number }>()
232
-
233
- return {
234
- id: input.postId,
235
- }
236
- })
237
-
238
- // @ts-expect-error mismatch input
239
- os.input(z.object({ postId: z.number() })).use(mid)
240
-
241
- // @ts-expect-error mismatch input
242
- os.input(z.object({ postId: z.number() })).use(mid, (input) => {
243
- return {
244
- wrong: input.postId,
245
- }
246
- })
247
- })
248
-
249
- it('add middlewares to beginning', () => {
250
- const mid1 = vi.fn()
251
- const mid2 = vi.fn()
252
- const mid3 = vi.fn()
253
-
254
- const p1 = os.use(mid1).func(() => 'unnoq')
255
- const p2 = p1.use(mid2).use(mid3)
256
-
257
- expect(p2.zz$p.middlewares).toEqual([mid3, mid2, mid1])
258
- })
259
- })
260
-
261
- describe('server action', () => {
262
- it('only accept undefined context', () => {
263
- expectTypeOf(os.func(() => {})).toMatchTypeOf<(...args: any[]) => any>()
264
- expectTypeOf(
265
- os.context<{ auth: boolean } | undefined>().func(() => {}),
266
- ).toMatchTypeOf<(...args: any[]) => any>()
267
- expectTypeOf(
268
- os.context<{ auth: boolean }>().func(() => {}),
269
- ).not.toMatchTypeOf<(...args: any[]) => any>()
270
- })
271
-
272
- it('infer types', () => {
273
- const p = os
274
- .input(z.object({ id: z.number() }))
275
- .output(z.string())
276
- .func(() => 'string')
277
-
278
- expectTypeOf(p).toMatchTypeOf<
279
- (input: { id: number } | FormData) => Promise<string>
280
- >()
281
-
282
- const p2 = os.input(z.object({ id: z.number() })).func(() => 12333)
283
-
284
- expectTypeOf(p2).toMatchTypeOf<
285
- (input: { id: number } | FormData) => Promise<number>
286
- >()
287
- })
288
-
289
- it('works with input', async () => {
290
- const p = os
291
- .input(z.object({ id: z.number(), date: z.date() }))
292
- .func(async (input, context) => {
293
- expect(context).toBe(undefined)
294
- return input
295
- })
296
-
297
- expect(await p({ id: 123, date: new Date('2022-01-01') })).toEqual({
298
- id: 123,
299
- date: new Date('2022-01-01'),
300
- })
301
- })
302
-
303
- it('can deserialize form data', async () => {
304
- const p = os
305
- .input(z.object({ id: z.number(), nested: z.object({ date: z.date() }) }))
306
- .func(async input => input)
307
-
308
- const form = new FormData()
309
- form.append('id', '123')
310
- form.append('nested[date]', '2022-01-01')
311
-
312
- expect(await p(form)).toEqual({
313
- id: 123,
314
- nested: { date: new Date('2022-01-01') },
315
- })
316
- })
317
- })