@orpc/server 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. package/dist/{chunk-26DTFWOI.js → chunk-YYGRQD4L.js} +26 -36
  2. package/dist/chunk-YYGRQD4L.js.map +1 -0
  3. package/dist/fetch.js +12 -12
  4. package/dist/fetch.js.map +1 -1
  5. package/dist/index.js +9 -15
  6. package/dist/index.js.map +1 -1
  7. package/dist/src/adapters/fetch.d.ts +2 -2
  8. package/dist/src/adapters/fetch.d.ts.map +1 -1
  9. package/dist/src/builder.d.ts +2 -2
  10. package/dist/src/builder.d.ts.map +1 -1
  11. package/dist/src/procedure-builder.d.ts +2 -2
  12. package/dist/src/procedure-builder.d.ts.map +1 -1
  13. package/dist/src/procedure-caller.d.ts +7 -16
  14. package/dist/src/procedure-caller.d.ts.map +1 -1
  15. package/dist/src/procedure-implementer.d.ts +2 -2
  16. package/dist/src/procedure-implementer.d.ts.map +1 -1
  17. package/dist/src/procedure.d.ts +11 -10
  18. package/dist/src/procedure.d.ts.map +1 -1
  19. package/dist/src/router-caller.d.ts +8 -17
  20. package/dist/src/router-caller.d.ts.map +1 -1
  21. package/dist/src/router.d.ts +2 -2
  22. package/dist/src/router.d.ts.map +1 -1
  23. package/dist/src/types.d.ts +0 -1
  24. package/dist/src/types.d.ts.map +1 -1
  25. package/dist/tsconfig.tsbuildinfo +1 -1
  26. package/package.json +8 -6
  27. package/src/adapters/fetch.test.ts +18 -18
  28. package/src/adapters/fetch.ts +9 -5
  29. package/src/builder.test.ts +4 -4
  30. package/src/builder.ts +6 -6
  31. package/src/middleware.test.ts +1 -1
  32. package/src/procedure-builder.test.ts +2 -2
  33. package/src/procedure-builder.ts +6 -6
  34. package/src/procedure-caller.test.ts +27 -36
  35. package/src/procedure-caller.ts +36 -44
  36. package/src/procedure-implementer.test.ts +8 -8
  37. package/src/procedure-implementer.ts +6 -6
  38. package/src/procedure.test.ts +20 -20
  39. package/src/procedure.ts +30 -45
  40. package/src/router-builder.test.ts +4 -4
  41. package/src/router-caller.test.ts +5 -52
  42. package/src/router-caller.ts +11 -31
  43. package/src/router-implementer.test.ts +6 -6
  44. package/src/router.test-d.ts +2 -2
  45. package/src/router.test.ts +10 -10
  46. package/src/router.ts +4 -4
  47. package/src/types.ts +0 -1
  48. package/dist/chunk-26DTFWOI.js.map +0 -1
@@ -3,6 +3,7 @@
3
3
  import type {
4
4
  PartialOnUndefinedDeep,
5
5
  Promisable,
6
+ Value,
6
7
  } from '@orpc/shared'
7
8
  import type { Router } from '../router'
8
9
  import {
@@ -16,6 +17,7 @@ import {
16
17
  isPlainObject,
17
18
  mapValues,
18
19
  trim,
20
+ value,
19
21
  } from '@orpc/shared'
20
22
  import { ORPCError } from '@orpc/shared/error'
21
23
  import {
@@ -91,6 +93,8 @@ export function createFetchHandler<TRouter extends Router<any>>(
91
93
  ? new ORPCSerializer()
92
94
  : new OpenAPISerializer({ accept })
93
95
 
96
+ const context = await value(requestOptions.context)
97
+
94
98
  const handler = async () => {
95
99
  const url = new URL(requestOptions.request.url)
96
100
  const pathname = `/${trim(url.pathname.replace(requestOptions.prefix ?? '', ''), '/')}`
@@ -196,9 +200,7 @@ export function createFetchHandler<TRouter extends Router<any>>(
196
200
  })()
197
201
 
198
202
  const caller = createProcedureCaller({
199
- context: requestOptions.context,
200
- internal: false,
201
- validate: true,
203
+ context,
202
204
  procedure,
203
205
  path,
204
206
  })
@@ -214,7 +216,7 @@ export function createFetchHandler<TRouter extends Router<any>>(
214
216
  }
215
217
 
216
218
  try {
217
- return await options.hooks?.(requestOptions.context as any, {
219
+ return await options.hooks?.(context as any, {
218
220
  next: handler,
219
221
  response: response => response,
220
222
  }) ?? await handler()
@@ -268,7 +270,9 @@ export type FetchHandlerOptions<TRouter extends Router<any>> = {
268
270
  /**
269
271
  * The context used to handle the request.
270
272
  */
271
- context: TRouter extends Router<infer UContext> ? UContext : never
273
+ context: Value<
274
+ TRouter extends Router<infer UContext> ? UContext : never
275
+ >
272
276
  }>
273
277
 
274
278
  export interface FetchHandler<TRouter extends Router<any>> {
@@ -74,7 +74,7 @@ describe('use middleware', () => {
74
74
  return { postId: '1' }
75
75
  },
76
76
  )
77
- .handler((_, context) => {
77
+ .func((_, context) => {
78
78
  expectTypeOf(context).toMatchTypeOf<{ user: string }>()
79
79
  })
80
80
  })
@@ -145,7 +145,7 @@ it('router method', () => {
145
145
  // Because of the router keyword is special, we can't use instanceof
146
146
  expect(osw.router.zz$pi.contract).toEqual(userFindContract)
147
147
  expect(
148
- osw.router.handler(() => {
148
+ osw.router.func(() => {
149
149
  return { name: '' }
150
150
  }),
151
151
  ).toSatisfy(isProcedure)
@@ -286,7 +286,7 @@ describe('handler method', () => {
286
286
  it('without middlewares', () => {
287
287
  const osw = os.context<{ auth: boolean }>()
288
288
 
289
- const procedure = osw.handler((input, context, meta) => {
289
+ const procedure = osw.func((input, context, meta) => {
290
290
  expectTypeOf(input).toEqualTypeOf<unknown>()
291
291
  expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
292
292
  expectTypeOf(meta).toEqualTypeOf<Meta>()
@@ -317,7 +317,7 @@ describe('handler method', () => {
317
317
 
318
318
  const osw = os.context<{ auth: boolean }>().use(mid)
319
319
 
320
- const procedure = osw.handler((input, context, meta) => {
320
+ const procedure = osw.func((input, context, meta) => {
321
321
  expectTypeOf(input).toEqualTypeOf<unknown>()
322
322
  expectTypeOf(context).toMatchTypeOf<{ auth: boolean }>()
323
323
  expectTypeOf(meta).toEqualTypeOf<Meta>()
package/src/builder.ts CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  type DecoratedProcedure,
22
22
  decorateProcedure,
23
- type ProcedureHandler,
23
+ type ProcedureFunc,
24
24
  } from './procedure'
25
25
  import { ProcedureBuilder } from './procedure-builder'
26
26
  import { ProcedureImplementer } from './procedure-implementer'
@@ -137,20 +137,20 @@ export class Builder<TContext extends Context, TExtraContext extends Context> {
137
137
  /**
138
138
  * Convert to Procedure
139
139
  */
140
- handler<UHandlerOutput = undefined>(
141
- handler: ProcedureHandler<
140
+ func<UFuncOutput = undefined>(
141
+ func: ProcedureFunc<
142
142
  TContext,
143
143
  TExtraContext,
144
144
  undefined,
145
145
  undefined,
146
- UHandlerOutput
146
+ UFuncOutput
147
147
  >,
148
148
  ): DecoratedProcedure<
149
149
  TContext,
150
150
  TExtraContext,
151
151
  undefined,
152
152
  undefined,
153
- UHandlerOutput
153
+ UFuncOutput
154
154
  > {
155
155
  return decorateProcedure({
156
156
  zz$p: {
@@ -159,7 +159,7 @@ export class Builder<TContext extends Context, TExtraContext extends Context> {
159
159
  InputSchema: undefined,
160
160
  OutputSchema: undefined,
161
161
  }),
162
- handler,
162
+ func,
163
163
  },
164
164
  })
165
165
  }
@@ -249,7 +249,7 @@ it('middleware can output', async () => {
249
249
  mid2Called = true
250
250
  return meta.output('from middleware 2')
251
251
  })
252
- .handler(() => {
252
+ .func(() => {
253
253
  handlerCalled = true
254
254
  return 'from handler'
255
255
  })
@@ -163,7 +163,7 @@ describe('use middleware', () => {
163
163
 
164
164
  describe('handler', () => {
165
165
  it('infer types', () => {
166
- const handler = builder.handler((input, context, meta) => {
166
+ const handler = builder.func((input, context, meta) => {
167
167
  expectTypeOf(input).toEqualTypeOf<unknown>()
168
168
  expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
169
169
  expectTypeOf(meta).toEqualTypeOf<Meta>()
@@ -196,7 +196,7 @@ describe('handler', () => {
196
196
  const handler = builder
197
197
  .use(mid1)
198
198
  .use(mid2)
199
- .handler((input, context, meta) => {
199
+ .func((input, context, meta) => {
200
200
  expectTypeOf(input).toEqualTypeOf<unknown>()
201
201
  expectTypeOf(context).toEqualTypeOf<
202
202
  { userId: string } & { auth: boolean }
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  type DecoratedProcedure,
13
13
  decorateProcedure,
14
- type ProcedureHandler,
14
+ type ProcedureFunc,
15
15
  } from './procedure'
16
16
  import { ProcedureImplementer } from './procedure-implementer'
17
17
 
@@ -132,26 +132,26 @@ export class ProcedureBuilder<
132
132
  * Convert to Procedure
133
133
  */
134
134
 
135
- handler<UHandlerOutput extends SchemaOutput<TOutputSchema>>(
136
- handler: ProcedureHandler<
135
+ func<UFuncOutput extends SchemaOutput<TOutputSchema>>(
136
+ func: ProcedureFunc<
137
137
  TContext,
138
138
  TExtraContext,
139
139
  TInputSchema,
140
140
  TOutputSchema,
141
- UHandlerOutput
141
+ UFuncOutput
142
142
  >,
143
143
  ): DecoratedProcedure<
144
144
  TContext,
145
145
  TExtraContext,
146
146
  TInputSchema,
147
147
  TOutputSchema,
148
- UHandlerOutput
148
+ UFuncOutput
149
149
  > {
150
150
  return decorateProcedure({
151
151
  zz$p: {
152
152
  middlewares: this.zz$pb.middlewares,
153
153
  contract: this.zz$pb.contract,
154
- handler,
154
+ func,
155
155
  },
156
156
  })
157
157
  }
@@ -2,17 +2,15 @@ import { z } from 'zod'
2
2
  import { createProcedureCaller, os } from '.'
3
3
 
4
4
  describe('createProcedureCaller', () => {
5
- let internal = false
6
- let path = ['ping']
7
- let context = { auth: true }
5
+ const path = ['ping']
6
+ const context = { auth: true }
8
7
 
9
8
  const osw = os.context<{ auth?: boolean }>()
10
9
  const procedure = osw
11
10
  .input(z.object({ value: z.string().transform(v => Number(v)) }))
12
11
  .output(z.object({ value: z.number().transform(v => v.toString()) }))
13
- .handler((input, context, meta) => {
12
+ .func((input, context, meta) => {
14
13
  expect(context).toEqual(context)
15
- expect(meta.internal).toBe(internal)
16
14
  expect(meta.path).toBe(path)
17
15
 
18
16
  return input
@@ -34,8 +32,7 @@ describe('createProcedureCaller', () => {
34
32
  it('with validate', async () => {
35
33
  const caller = createProcedureCaller({
36
34
  procedure,
37
- context,
38
- internal,
35
+ context: async () => context,
39
36
  path,
40
37
  })
41
38
 
@@ -53,41 +50,14 @@ describe('createProcedureCaller', () => {
53
50
  )
54
51
  })
55
52
 
56
- it('without validate', async () => {
57
- internal = true
58
- path = []
59
- context = { auth: false }
60
-
61
- const caller = createProcedureCaller({
62
- procedure,
63
- context,
64
- internal,
65
- path,
66
- validate: false,
67
- })
68
-
69
- expectTypeOf(caller).toMatchTypeOf<
70
- (input: { value: number }) => Promise<{
71
- value: number
72
- }>
73
- >()
74
-
75
- expect(await caller({ value: 123 })).toEqual({ value: 123 })
76
-
77
- // @ts-expect-error it's not validate so bellow still works
78
- expect(await caller({ value: '123' })).toEqual({ value: '123' })
79
- })
80
-
81
53
  it('without validate and schema', () => {
82
- const procedure = osw.handler(() => {
54
+ const procedure = osw.func(() => {
83
55
  return { value: true }
84
56
  })
85
57
 
86
58
  const caller = createProcedureCaller({
87
59
  procedure,
88
60
  context,
89
- internal,
90
- validate: false,
91
61
  })
92
62
 
93
63
  expectTypeOf(caller).toMatchTypeOf<
@@ -146,7 +116,7 @@ describe('createProcedureCaller', () => {
146
116
  .input(z.object({ id: z.string() }))
147
117
  .use(mid1)
148
118
  .use(mid2)
149
- .handler((input, context, meta) => {
119
+ .func((input, context, meta) => {
150
120
  expect(context).toEqual({ userId: '1', auth: false })
151
121
 
152
122
  expect(ref.value).toBe(2)
@@ -162,4 +132,25 @@ describe('createProcedureCaller', () => {
162
132
 
163
133
  expect(caller({ id: '1' })).resolves.toEqual('pong')
164
134
  })
135
+
136
+ it('accept form data', async () => {
137
+ const ping = osw
138
+ .input(z.object({ id: z.number() }))
139
+ .output(z.object({ id: z.number() }))
140
+ .func((input, context, meta) => {
141
+ expect(context).toEqual(context)
142
+
143
+ return input
144
+ })
145
+
146
+ const caller = createProcedureCaller({
147
+ procedure: ping,
148
+ context,
149
+ })
150
+
151
+ const form = new FormData()
152
+ form.append('id', '1')
153
+
154
+ expect(await caller(form)).toEqual({ id: 1 })
155
+ })
165
156
  })
@@ -2,84 +2,78 @@ import type { SchemaInput, SchemaOutput } from '@orpc/contract'
2
2
  import type { MiddlewareMeta } from './middleware'
3
3
  import type { Procedure } from './procedure'
4
4
  import type { Context } from './types'
5
+ import { type Value, value } from '@orpc/shared'
5
6
  import { ORPCError } from '@orpc/shared/error'
7
+ import { OpenAPIDeserializer } from '@orpc/transformer'
6
8
  import { mergeContext } from './utils'
7
9
 
8
10
  export interface CreateProcedureCallerOptions<
9
11
  TProcedure extends Procedure<any, any, any, any, any>,
10
- TValidate extends boolean,
11
12
  > {
12
13
  procedure: TProcedure
13
14
 
14
15
  /**
15
16
  * The context used when calling the procedure.
16
17
  */
17
- context: TProcedure extends Procedure<infer UContext, any, any, any, any>
18
- ? UContext
19
- : never
18
+ context: Value<
19
+ TProcedure extends Procedure<infer UContext, any, any, any, any>
20
+ ? UContext
21
+ : never
22
+ >
20
23
 
21
24
  /**
22
25
  * This is helpful for logging and analytics.
23
- */
24
- path?: string[]
25
-
26
- /**
27
- * This flag helpful when you want bypass some logics not necessary to internal server calls.
28
26
  *
29
- * @default true
27
+ * @internal
30
28
  */
31
- internal?: boolean
32
-
33
- /**
34
- * Indicate whether validate input and output.
35
- *
36
- * @default true
37
- */
38
- validate?: TValidate
29
+ path?: string[]
39
30
  }
40
31
 
41
32
  export type ProcedureCaller<
42
33
  TProcedure extends Procedure<any, any, any, any, any>,
43
- TValidate extends boolean,
44
34
  > = TProcedure extends Procedure<
45
35
  any,
46
36
  any,
47
37
  infer UInputSchema,
48
38
  infer UOutputSchema,
49
- infer UHandlerOutput
39
+ infer UFuncOutput
50
40
  >
51
41
  ? (
52
- input: TValidate extends true
53
- ? SchemaInput<UInputSchema>
54
- : SchemaOutput<UInputSchema>,
42
+ input: SchemaInput<UInputSchema> | FormData,
55
43
  ) => Promise<
56
- TValidate extends true
57
- ? SchemaOutput<UOutputSchema, UHandlerOutput>
58
- : SchemaInput<UOutputSchema, UHandlerOutput>
44
+ SchemaOutput<UOutputSchema, UFuncOutput>
59
45
  >
60
46
  : never
61
47
 
62
48
  export function createProcedureCaller<
63
49
  TProcedure extends Procedure<any, any, any, any, any>,
64
- TValidate extends boolean = true,
65
50
  >(
66
- options: CreateProcedureCallerOptions<TProcedure, TValidate>,
67
- ): ProcedureCaller<TProcedure, TValidate> {
68
- const internal = options.internal ?? true
51
+ options: CreateProcedureCallerOptions<TProcedure>,
52
+ ): ProcedureCaller<TProcedure> {
69
53
  const path = options.path ?? []
70
54
  const procedure = options.procedure
71
- const validate = options.validate ?? true
72
55
 
73
56
  const caller = async (input: unknown): Promise<unknown> => {
74
- const validInput = (() => {
75
- if (!validate)
57
+ const input_ = (() => {
58
+ if (!(input instanceof FormData)) {
76
59
  return input
60
+ }
61
+
62
+ const transformer = new OpenAPIDeserializer({
63
+ schema: procedure.zz$p.contract.zz$cp.InputSchema,
64
+ })
65
+
66
+ return transformer.deserializeAsFormData(input)
67
+ })()
68
+
69
+ const validInput = (() => {
77
70
  const schema = procedure.zz$p.contract.zz$cp.InputSchema
78
- if (!schema)
79
- return input
71
+ if (!schema) {
72
+ return input_
73
+ }
80
74
 
81
75
  try {
82
- return schema.parse(input)
76
+ return schema.parse(input_)
83
77
  }
84
78
  catch (e) {
85
79
  throw new ORPCError({
@@ -92,7 +86,7 @@ export function createProcedureCaller<
92
86
 
93
87
  const middlewares = procedure.zz$p.middlewares ?? []
94
88
  let currentMidIndex = 0
95
- let currentContext: Context = options.context
89
+ let currentContext: Context = await value(options.context)
96
90
 
97
91
  const next: MiddlewareMeta<unknown>['next'] = async (nextOptions) => {
98
92
  const mid = middlewares[currentMidIndex]
@@ -103,17 +97,15 @@ export function createProcedureCaller<
103
97
  return await mid(validInput, currentContext, {
104
98
  path,
105
99
  procedure,
106
- internal,
107
100
  next,
108
101
  output: output => ({ output, context: undefined }),
109
102
  })
110
103
  }
111
104
  else {
112
105
  return {
113
- output: await await procedure.zz$p.handler(validInput, currentContext, {
106
+ output: await await procedure.zz$p.func(validInput, currentContext, {
114
107
  path,
115
108
  procedure,
116
- internal,
117
109
  }),
118
110
  context: currentContext,
119
111
  }
@@ -123,11 +115,11 @@ export function createProcedureCaller<
123
115
  const output = (await next({})).output
124
116
 
125
117
  const validOutput = await (async () => {
126
- if (!validate)
127
- return output
128
118
  const schema = procedure.zz$p.contract.zz$cp.OutputSchema
129
- if (!schema)
119
+ if (!schema) {
130
120
  return output
121
+ }
122
+
131
123
  const result = await schema.safeParseAsync(output)
132
124
  if (result.error) {
133
125
  throw new ORPCError({
@@ -142,5 +134,5 @@ export function createProcedureCaller<
142
134
  return validOutput
143
135
  }
144
136
 
145
- return caller as ProcedureCaller<TProcedure, TValidate>
137
+ return caller as ProcedureCaller<TProcedure>
146
138
  }
@@ -111,9 +111,9 @@ describe('use middleware', () => {
111
111
 
112
112
  describe('output schema', () => {
113
113
  it('auto infer output schema if output schema is not specified', async () => {
114
- const sr = os.handler(() => ({ a: 1 }))
114
+ const sr = os.func(() => ({ a: 1 }))
115
115
 
116
- const result = await sr.zz$p.handler({}, undefined, {
116
+ const result = await sr.zz$p.func({}, undefined, {
117
117
  method: 'GET',
118
118
  path: '/',
119
119
  } as any)
@@ -129,9 +129,9 @@ describe('output schema', () => {
129
129
  }),
130
130
  })
131
131
 
132
- const sr = srb1.handler(() => ({ b: 1 }))
132
+ const sr = srb1.func(() => ({ b: 1 }))
133
133
 
134
- const result = await sr.zz$p.handler({}, {}, {
134
+ const result = await sr.zz$p.func({}, {}, {
135
135
  method: 'GET',
136
136
  path: '/',
137
137
  } as any)
@@ -142,7 +142,7 @@ describe('output schema', () => {
142
142
 
143
143
  describe('handler', () => {
144
144
  it('infer types', () => {
145
- const handler = implementer1.handler((input, context, meta) => {
145
+ const handler = implementer1.func((input, context, meta) => {
146
146
  expectTypeOf(input).toEqualTypeOf<unknown>()
147
147
  expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
148
148
  expectTypeOf(meta).toEqualTypeOf<Meta>()
@@ -163,7 +163,7 @@ describe('handler', () => {
163
163
  >()
164
164
  expect(isProcedure(handler)).toBe(true)
165
165
 
166
- implementer2.handler((input, context, meta) => {
166
+ implementer2.func((input, context, meta) => {
167
167
  expectTypeOf(input).toEqualTypeOf<{ id: string }>()
168
168
  expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
169
169
  expectTypeOf(meta).toEqualTypeOf<Meta>()
@@ -174,7 +174,7 @@ describe('handler', () => {
174
174
  })
175
175
 
176
176
  // @ts-expect-error mismatch output
177
- implementer2.handler(() => {})
177
+ implementer2.func(() => {})
178
178
  })
179
179
 
180
180
  it('combine middlewares', () => {
@@ -193,7 +193,7 @@ describe('handler', () => {
193
193
  const handler = implementer2
194
194
  .use(mid1)
195
195
  .use(mid2)
196
- .handler((input, context, meta) => {
196
+ .func((input, context, meta) => {
197
197
  expectTypeOf(input).toEqualTypeOf<{ id: string }>()
198
198
  expectTypeOf(context).toEqualTypeOf<
199
199
  { auth: boolean } & { userId: string }
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  type DecoratedProcedure,
10
10
  decorateProcedure,
11
- type ProcedureHandler,
11
+ type ProcedureFunc,
12
12
  } from './procedure'
13
13
 
14
14
  export class ProcedureImplementer<
@@ -76,26 +76,26 @@ export class ProcedureImplementer<
76
76
  })
77
77
  }
78
78
 
79
- handler<UHandlerOutput extends SchemaOutput<TOutputSchema>>(
80
- handler: ProcedureHandler<
79
+ func<UFuncOutput extends SchemaOutput<TOutputSchema>>(
80
+ func: ProcedureFunc<
81
81
  TContext,
82
82
  TExtraContext,
83
83
  TInputSchema,
84
84
  TOutputSchema,
85
- UHandlerOutput
85
+ UFuncOutput
86
86
  >,
87
87
  ): DecoratedProcedure<
88
88
  TContext,
89
89
  TExtraContext,
90
90
  TInputSchema,
91
91
  TOutputSchema,
92
- UHandlerOutput
92
+ UFuncOutput
93
93
  > {
94
94
  return decorateProcedure({
95
95
  zz$p: {
96
96
  middlewares: this.zz$pi.middlewares,
97
97
  contract: this.zz$pi.contract,
98
- handler,
98
+ func,
99
99
  },
100
100
  })
101
101
  }