@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,223 +0,0 @@
1
- import type { MiddlewareMeta } from './middleware'
2
- import type { ProcedureImplementer } from './procedure-implementer'
3
- import type { Meta } from './types'
4
- import { ContractProcedure } from '@orpc/contract'
5
- import { z } from 'zod'
6
- import { os } from '.'
7
- import { type DecoratedProcedure, isProcedure } from './procedure'
8
- import { ProcedureBuilder } from './procedure-builder'
9
-
10
- const schema1 = z.object({ id: z.string() })
11
- const example1 = { id: '1' }
12
- const schema2 = z.object({ name: z.string() })
13
- const example2 = { name: 'unnoq' }
14
-
15
- const builder = new ProcedureBuilder<
16
- { auth: boolean },
17
- undefined,
18
- undefined,
19
- undefined
20
- >({
21
- contract: new ContractProcedure({
22
- InputSchema: undefined,
23
- OutputSchema: undefined,
24
- }),
25
- })
26
-
27
- it('input', () => {
28
- const builder2 = builder.input(schema1, example1)
29
-
30
- expectTypeOf(builder2).toEqualTypeOf<
31
- ProcedureBuilder<{ auth: boolean }, undefined, typeof schema1, undefined>
32
- >()
33
-
34
- expect(builder2.zz$pb).toMatchObject({
35
- contract: {
36
- zz$cp: {
37
- InputSchema: schema1,
38
- inputExample: example1,
39
- },
40
- },
41
- })
42
- })
43
-
44
- it('output', () => {
45
- const builder2 = builder.output(schema2, example2)
46
-
47
- expectTypeOf(builder2).toEqualTypeOf<
48
- ProcedureBuilder<{ auth: boolean }, undefined, undefined, typeof schema2>
49
- >()
50
-
51
- expect(builder2.zz$pb).toMatchObject({
52
- contract: {
53
- zz$cp: {
54
- OutputSchema: schema2,
55
- outputExample: example2,
56
- },
57
- },
58
- })
59
- })
60
-
61
- it('route', () => {
62
- const builder2 = builder.route({
63
- method: 'GET',
64
- path: '/test',
65
- deprecated: true,
66
- description: 'des',
67
- summary: 'sum',
68
- tags: ['hi'],
69
- })
70
-
71
- expectTypeOf(builder2).toEqualTypeOf<
72
- ProcedureBuilder<{ auth: boolean }, undefined, undefined, undefined>
73
- >()
74
-
75
- expect(builder2.zz$pb).toMatchObject({
76
- contract: {
77
- zz$cp: {
78
- method: 'GET',
79
- path: '/test',
80
- deprecated: true,
81
- description: 'des',
82
- summary: 'sum',
83
- tags: ['hi'],
84
- },
85
- },
86
- })
87
- })
88
-
89
- describe('use middleware', () => {
90
- it('infer types', () => {
91
- const implementer = builder
92
- .use((input, context, meta) => {
93
- expectTypeOf(input).toEqualTypeOf<unknown>()
94
- expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
95
- expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<unknown>>()
96
-
97
- return meta.next({
98
- context: {
99
- userId: '1',
100
- },
101
- })
102
- })
103
- .use((input, context, meta) => {
104
- expectTypeOf(input).toEqualTypeOf<unknown>()
105
- expectTypeOf(context).toEqualTypeOf<
106
- { userId: string } & { auth: boolean }
107
- >()
108
- expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<unknown>>()
109
-
110
- return meta.next({})
111
- })
112
-
113
- expectTypeOf(implementer).toEqualTypeOf<
114
- ProcedureImplementer<
115
- { auth: boolean },
116
- { userId: string },
117
- undefined,
118
- undefined
119
- >
120
- >()
121
- })
122
-
123
- it('map middleware input', () => {
124
- // @ts-expect-error mismatch input
125
- builder.use((input: { postId: string }) => {
126
- return { context: { a: 'a' } }
127
- })
128
-
129
- builder.use(
130
- (input: { postId: string }, _, meta) => {
131
- return meta.next({ context: { a: 'a' } })
132
- },
133
- // @ts-expect-error mismatch input
134
- input => ({ postId: 12455 }),
135
- )
136
-
137
- builder.use(
138
- (input: { postId: string }, context, meta) => meta.next({}),
139
- input => ({ postId: '12455' }),
140
- )
141
-
142
- const implementer = builder.input(schema1).use(
143
- (input: { id: number }, _, meta) => {
144
- return meta.next({
145
- context: {
146
- userId555: '1',
147
- },
148
- })
149
- },
150
- input => ({ id: Number.parseInt(input.id) }),
151
- )
152
-
153
- expectTypeOf(implementer).toEqualTypeOf<
154
- ProcedureImplementer<
155
- { auth: boolean },
156
- { userId555: string },
157
- typeof schema1,
158
- undefined
159
- >
160
- >()
161
- })
162
- })
163
-
164
- describe('handler', () => {
165
- it('infer types', () => {
166
- const handler = builder.func((input, context, meta) => {
167
- expectTypeOf(input).toEqualTypeOf<unknown>()
168
- expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
169
- expectTypeOf(meta).toEqualTypeOf<Meta>()
170
- })
171
-
172
- expectTypeOf(handler).toEqualTypeOf<
173
- DecoratedProcedure<
174
- { auth: boolean },
175
- undefined,
176
- undefined,
177
- undefined,
178
- void
179
- >
180
- >()
181
-
182
- expect(isProcedure(handler)).toBe(true)
183
- })
184
-
185
- it('combine middlewares', () => {
186
- const mid1 = os.middleware((input, context, meta) => {
187
- return meta.next({
188
- context: {
189
- userId: '1',
190
- },
191
- })
192
- })
193
-
194
- const mid2 = os.middleware((_, __, meta) => meta.next({}))
195
-
196
- const handler = builder
197
- .use(mid1)
198
- .use(mid2)
199
- .func((input, context, meta) => {
200
- expectTypeOf(input).toEqualTypeOf<unknown>()
201
- expectTypeOf(context).toEqualTypeOf<
202
- { userId: string } & { auth: boolean }
203
- >()
204
- expectTypeOf(meta).toEqualTypeOf<Meta>()
205
-
206
- return {
207
- name: 'unnoq',
208
- }
209
- })
210
-
211
- expectTypeOf(handler).toEqualTypeOf<
212
- DecoratedProcedure<
213
- { auth: boolean },
214
- { userId: string },
215
- undefined,
216
- undefined,
217
- { name: string }
218
- >
219
- >()
220
-
221
- expect(handler.zz$p.middlewares).toEqual([mid1, mid2])
222
- })
223
- })
@@ -1,158 +0,0 @@
1
- import type { MapInputMiddleware, Middleware } from './middleware'
2
- import type { Context, MergeContext } from './types'
3
- import {
4
- type ContractProcedure,
5
- DecoratedContractProcedure,
6
- type RouteOptions,
7
- type Schema,
8
- type SchemaInput,
9
- type SchemaOutput,
10
- } from '@orpc/contract'
11
- import {
12
- type DecoratedProcedure,
13
- decorateProcedure,
14
- type ProcedureFunc,
15
- } from './procedure'
16
- import { ProcedureImplementer } from './procedure-implementer'
17
-
18
- export class ProcedureBuilder<
19
- TContext extends Context,
20
- TExtraContext extends Context,
21
- TInputSchema extends Schema,
22
- TOutputSchema extends Schema,
23
- > {
24
- constructor(
25
- public zz$pb: {
26
- contract: ContractProcedure<TInputSchema, TOutputSchema>
27
- middlewares?: Middleware<any, any, any, any>[]
28
- },
29
- ) {}
30
-
31
- /**
32
- * Self chainable
33
- */
34
-
35
- route(
36
- opts: RouteOptions,
37
- ): ProcedureBuilder<TContext, TExtraContext, TInputSchema, TOutputSchema> {
38
- return new ProcedureBuilder({
39
- ...this.zz$pb,
40
- contract: DecoratedContractProcedure.decorate(this.zz$pb.contract).route(
41
- opts,
42
- ),
43
- })
44
- }
45
-
46
- input<USchema extends Schema = undefined>(
47
- schema: USchema,
48
- example?: SchemaInput<USchema>,
49
- ): ProcedureBuilder<TContext, TExtraContext, USchema, TOutputSchema> {
50
- return new ProcedureBuilder({
51
- ...this.zz$pb,
52
- contract: DecoratedContractProcedure.decorate(this.zz$pb.contract).input(
53
- schema,
54
- example,
55
- ),
56
- })
57
- }
58
-
59
- output<USchema extends Schema = undefined>(
60
- schema: USchema,
61
- example?: SchemaOutput<USchema>,
62
- ): ProcedureBuilder<TContext, TExtraContext, TInputSchema, USchema> {
63
- return new ProcedureBuilder({
64
- ...this.zz$pb,
65
- contract: DecoratedContractProcedure.decorate(this.zz$pb.contract).output(
66
- schema,
67
- example,
68
- ),
69
- })
70
- }
71
-
72
- /**
73
- * Convert to ProcedureBuilder
74
- */
75
-
76
- use<
77
- UExtraContext extends
78
- | Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>>
79
- | undefined = undefined,
80
- >(
81
- middleware: Middleware<
82
- MergeContext<TContext, TExtraContext>,
83
- UExtraContext,
84
- SchemaOutput<TInputSchema>,
85
- SchemaInput<TOutputSchema>
86
- >,
87
- ): ProcedureImplementer<
88
- TContext,
89
- MergeContext<TExtraContext, UExtraContext>,
90
- TInputSchema,
91
- TOutputSchema
92
- >
93
-
94
- use<
95
- UExtraContext extends
96
- | Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>>
97
- | undefined = undefined,
98
- UMappedInput = unknown,
99
- >(
100
- middleware: Middleware<
101
- MergeContext<TContext, TExtraContext>,
102
- UExtraContext,
103
- UMappedInput,
104
- SchemaInput<TOutputSchema>
105
- >,
106
- mapInput: MapInputMiddleware<SchemaOutput<TInputSchema>, UMappedInput>,
107
- ): ProcedureImplementer<
108
- TContext,
109
- MergeContext<TExtraContext, UExtraContext>,
110
- TInputSchema,
111
- TOutputSchema
112
- >
113
-
114
- use(
115
- middleware: Middleware<any, any, any, any>,
116
- mapInput?: MapInputMiddleware<any, any>,
117
- ): ProcedureImplementer<any, any, any, any> {
118
- if (!mapInput) {
119
- return new ProcedureImplementer({
120
- contract: this.zz$pb.contract,
121
- middlewares: this.zz$pb.middlewares,
122
- }).use(middleware)
123
- }
124
-
125
- return new ProcedureImplementer({
126
- contract: this.zz$pb.contract,
127
- middlewares: this.zz$pb.middlewares,
128
- }).use(middleware, mapInput)
129
- }
130
-
131
- /**
132
- * Convert to Procedure
133
- */
134
-
135
- func<UFuncOutput extends SchemaOutput<TOutputSchema>>(
136
- func: ProcedureFunc<
137
- TContext,
138
- TExtraContext,
139
- TInputSchema,
140
- TOutputSchema,
141
- UFuncOutput
142
- >,
143
- ): DecoratedProcedure<
144
- TContext,
145
- TExtraContext,
146
- TInputSchema,
147
- TOutputSchema,
148
- UFuncOutput
149
- > {
150
- return decorateProcedure({
151
- zz$p: {
152
- middlewares: this.zz$pb.middlewares,
153
- contract: this.zz$pb.contract,
154
- func,
155
- },
156
- })
157
- }
158
- }
@@ -1,171 +0,0 @@
1
- import { z } from 'zod'
2
- import { createProcedureCaller, os } from '.'
3
-
4
- describe('createProcedureCaller', () => {
5
- const path = ['ping']
6
- const context = { auth: true }
7
-
8
- const osw = os.context<{ auth?: boolean }>()
9
- const procedure = osw
10
- .input(z.object({ value: z.string().transform(v => Number(v)) }))
11
- .output(z.object({ value: z.number().transform(v => v.toString()) }))
12
- .func((input, context, meta) => {
13
- expect(context).toEqual(context)
14
- expect(meta.path).toBe(path)
15
-
16
- return input
17
- })
18
-
19
- it('infer context', () => {
20
- createProcedureCaller({
21
- procedure,
22
- // @ts-expect-error invalid context
23
- context: { auth: 123 },
24
- })
25
-
26
- createProcedureCaller({
27
- procedure,
28
- context,
29
- })
30
- })
31
-
32
- it('with validate', async () => {
33
- const caller = createProcedureCaller({
34
- procedure,
35
- context: async () => context,
36
- path,
37
- })
38
-
39
- expectTypeOf(caller).toMatchTypeOf<
40
- (input: { value: string }) => Promise<{
41
- value: string
42
- }>
43
- >()
44
-
45
- expect(await caller({ value: '123' })).toEqual({ value: '123' })
46
-
47
- // @ts-expect-error - invalid input
48
- expect(caller({ value: {} })).rejects.toThrowError(
49
- 'Validation input failed',
50
- )
51
- })
52
-
53
- it('without validate and schema', () => {
54
- const procedure = osw.func(() => {
55
- return { value: true }
56
- })
57
-
58
- const caller = createProcedureCaller({
59
- procedure,
60
- context,
61
- })
62
-
63
- expectTypeOf(caller).toMatchTypeOf<
64
- (value: unknown) => Promise<{ value: boolean }>
65
- >()
66
-
67
- expect(caller({ value: 123 })).resolves.toEqual({ value: true })
68
- })
69
-
70
- it('middlewares', () => {
71
- const ref = { value: 0 }
72
-
73
- const mid1 = vi.fn(
74
- osw.middleware(async (input: { id: string }, context, meta) => {
75
- expect(input).toEqual({ id: '1' })
76
-
77
- expect(ref.value).toBe(0)
78
- ref.value++
79
-
80
- try {
81
- const result = await meta.next({
82
- context: {
83
- userId: '1',
84
- },
85
- })
86
- expect(ref.value).toBe(5)
87
- ref.value++
88
- return result
89
- }
90
- finally {
91
- expect(ref.value).toBe(6)
92
- ref.value++
93
- }
94
- }),
95
- )
96
-
97
- const mid2 = vi.fn(
98
- osw.middleware(async (input, context, meta) => {
99
- expect(ref.value).toBe(1)
100
- ref.value++
101
-
102
- try {
103
- const result = await meta.next({})
104
- expect(ref.value).toBe(3)
105
- ref.value++
106
- return result
107
- }
108
- finally {
109
- expect(ref.value).toBe(4)
110
- ref.value++
111
- }
112
- }),
113
- )
114
-
115
- const ping = osw
116
- .input(z.object({ id: z.string() }))
117
- .use(mid1)
118
- .use(mid2)
119
- .func((input, context, meta) => {
120
- expect(context).toEqual({ userId: '1', auth: false })
121
-
122
- expect(ref.value).toBe(2)
123
- ref.value++
124
-
125
- return 'pong'
126
- })
127
-
128
- const caller = createProcedureCaller({
129
- procedure: ping,
130
- context: { auth: false },
131
- })
132
-
133
- expect(caller({ id: '1' })).resolves.toEqual('pong')
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
- })
156
-
157
- it('optional input when possible', async () => {
158
- os.func(() => { })()
159
- os.func(() => { })({})
160
- // @ts-expect-error input is required
161
- expect(os.input(z.string()).func(() => { })()).rejects.toThrow()
162
- os.input(z.string().optional()).func(() => { })()
163
- // @ts-expect-error input is required
164
- expect(os.input(z.object({})).func(() => { })()).rejects.toThrow()
165
- os.input(z.object({}).optional()).func(() => { })()
166
- os.input(z.unknown()).func(() => { })()
167
- os.input(z.any()).func(() => { })()
168
- // @ts-expect-error input is required
169
- expect(os.input(z.boolean()).func(() => { })()).rejects.toThrow()
170
- })
171
- })
@@ -1,138 +0,0 @@
1
- import type { SchemaInput, SchemaOutput } from '@orpc/contract'
2
- import type { MiddlewareMeta } from './middleware'
3
- import type { Procedure } from './procedure'
4
- import type { Context } from './types'
5
- import { type Value, value } from '@orpc/shared'
6
- import { ORPCError } from '@orpc/shared/error'
7
- import { OpenAPIDeserializer } from '@orpc/transformer'
8
- import { mergeContext } from './utils'
9
-
10
- export interface CreateProcedureCallerOptions<
11
- TProcedure extends Procedure<any, any, any, any, any>,
12
- > {
13
- procedure: TProcedure
14
-
15
- /**
16
- * The context used when calling the procedure.
17
- */
18
- context: Value<
19
- TProcedure extends Procedure<infer UContext, any, any, any, any>
20
- ? UContext
21
- : never
22
- >
23
-
24
- /**
25
- * This is helpful for logging and analytics.
26
- *
27
- * @internal
28
- */
29
- path?: string[]
30
- }
31
-
32
- export type ProcedureCaller<
33
- TProcedure extends Procedure<any, any, any, any, any>,
34
- > = TProcedure extends Procedure<
35
- any,
36
- any,
37
- infer UInputSchema,
38
- infer UOutputSchema,
39
- infer UFuncOutput
40
- >
41
- ? (
42
- ...input: [input: SchemaInput<UInputSchema> | FormData] | (undefined extends SchemaInput<UInputSchema> ? [] : never)
43
- ) => Promise<
44
- SchemaOutput<UOutputSchema, UFuncOutput>
45
- >
46
- : never
47
-
48
- export function createProcedureCaller<
49
- TProcedure extends Procedure<any, any, any, any, any>,
50
- >(
51
- options: CreateProcedureCallerOptions<TProcedure>,
52
- ): ProcedureCaller<TProcedure> {
53
- const path = options.path ?? []
54
- const procedure = options.procedure
55
-
56
- const caller = async (input: unknown): Promise<unknown> => {
57
- const input_ = (() => {
58
- if (!(input instanceof FormData)) {
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 = (() => {
70
- const schema = procedure.zz$p.contract.zz$cp.InputSchema
71
- if (!schema) {
72
- return input_
73
- }
74
-
75
- try {
76
- return schema.parse(input_)
77
- }
78
- catch (e) {
79
- throw new ORPCError({
80
- message: 'Validation input failed',
81
- code: 'BAD_REQUEST',
82
- cause: e,
83
- })
84
- }
85
- })()
86
-
87
- const middlewares = procedure.zz$p.middlewares ?? []
88
- let currentMidIndex = 0
89
- let currentContext: Context = await value(options.context)
90
-
91
- const next: MiddlewareMeta<unknown>['next'] = async (nextOptions) => {
92
- const mid = middlewares[currentMidIndex]
93
- currentMidIndex += 1
94
- currentContext = mergeContext(currentContext, nextOptions.context)
95
-
96
- if (mid) {
97
- return await mid(validInput, currentContext, {
98
- path,
99
- procedure,
100
- next,
101
- output: output => ({ output, context: undefined }),
102
- })
103
- }
104
- else {
105
- return {
106
- output: await await procedure.zz$p.func(validInput, currentContext, {
107
- path,
108
- procedure,
109
- }),
110
- context: currentContext,
111
- }
112
- }
113
- }
114
-
115
- const output = (await next({})).output
116
-
117
- const validOutput = await (async () => {
118
- const schema = procedure.zz$p.contract.zz$cp.OutputSchema
119
- if (!schema) {
120
- return output
121
- }
122
-
123
- const result = await schema.safeParseAsync(output)
124
- if (result.error) {
125
- throw new ORPCError({
126
- message: 'Validation output failed',
127
- code: 'INTERNAL_SERVER_ERROR',
128
- cause: result.error,
129
- })
130
- }
131
- return result.data
132
- })()
133
-
134
- return validOutput
135
- }
136
-
137
- return caller as ProcedureCaller<TProcedure>
138
- }