@orpc/server 0.10.0-beta.1 → 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.
- package/dist/{chunk-TDFYNRZV.js → chunk-CVLK2PBB.js} +0 -1
- package/dist/fetch.js +1 -2
- package/dist/index.js +1 -2
- package/dist/src/adapters/fetch.d.ts +0 -1
- package/dist/src/builder.d.ts +0 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/middleware.d.ts +0 -1
- package/dist/src/procedure-builder.d.ts +0 -1
- package/dist/src/procedure-caller.d.ts +0 -1
- package/dist/src/procedure-implementer.d.ts +0 -1
- package/dist/src/procedure.d.ts +0 -1
- package/dist/src/router-builder.d.ts +0 -1
- package/dist/src/router-caller.d.ts +0 -1
- package/dist/src/router-implementer.d.ts +0 -1
- package/dist/src/router.d.ts +0 -1
- package/dist/src/types.d.ts +0 -1
- package/dist/src/utils.d.ts +0 -1
- package/package.json +12 -16
- package/dist/chunk-TDFYNRZV.js.map +0 -1
- package/dist/fetch.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/src/adapters/fetch.d.ts.map +0 -1
- package/dist/src/builder.d.ts.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/middleware.d.ts.map +0 -1
- package/dist/src/procedure-builder.d.ts.map +0 -1
- package/dist/src/procedure-caller.d.ts.map +0 -1
- package/dist/src/procedure-implementer.d.ts.map +0 -1
- package/dist/src/procedure.d.ts.map +0 -1
- package/dist/src/router-builder.d.ts.map +0 -1
- package/dist/src/router-caller.d.ts.map +0 -1
- package/dist/src/router-implementer.d.ts.map +0 -1
- package/dist/src/router.d.ts.map +0 -1
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/utils.d.ts.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/adapters/fetch.test.ts +0 -629
- package/src/adapters/fetch.ts +0 -290
- package/src/builder.test.ts +0 -371
- package/src/builder.ts +0 -238
- package/src/index.ts +0 -16
- package/src/middleware.test.ts +0 -260
- package/src/middleware.ts +0 -136
- package/src/procedure-builder.test.ts +0 -223
- package/src/procedure-builder.ts +0 -158
- package/src/procedure-caller.test.ts +0 -171
- package/src/procedure-caller.ts +0 -138
- package/src/procedure-implementer.test.ts +0 -220
- package/src/procedure-implementer.ts +0 -102
- package/src/procedure.test.ts +0 -317
- package/src/procedure.ts +0 -237
- package/src/router-builder.test.ts +0 -106
- package/src/router-builder.ts +0 -122
- package/src/router-caller.test.ts +0 -126
- package/src/router-caller.ts +0 -64
- package/src/router-implementer.test.ts +0 -116
- package/src/router-implementer.ts +0 -113
- package/src/router.test-d.ts +0 -48
- package/src/router.test.ts +0 -142
- package/src/router.ts +0 -91
- package/src/types.test.ts +0 -18
- package/src/types.ts +0 -13
- package/src/utils.test.ts +0 -16
- package/src/utils.ts +0 -16
package/src/adapters/fetch.ts
DELETED
@@ -1,290 +0,0 @@
|
|
1
|
-
/// <reference lib="dom" />
|
2
|
-
|
3
|
-
import type {
|
4
|
-
PartialOnUndefinedDeep,
|
5
|
-
Promisable,
|
6
|
-
Value,
|
7
|
-
} from '@orpc/shared'
|
8
|
-
import type { Router } from '../router'
|
9
|
-
import {
|
10
|
-
type HTTPPath,
|
11
|
-
ORPC_HEADER,
|
12
|
-
ORPC_HEADER_VALUE,
|
13
|
-
standardizeHTTPPath,
|
14
|
-
} from '@orpc/contract'
|
15
|
-
import {
|
16
|
-
get,
|
17
|
-
isPlainObject,
|
18
|
-
mapValues,
|
19
|
-
trim,
|
20
|
-
value,
|
21
|
-
} from '@orpc/shared'
|
22
|
-
import { ORPCError } from '@orpc/shared/error'
|
23
|
-
import {
|
24
|
-
OpenAPIDeserializer,
|
25
|
-
OpenAPISerializer,
|
26
|
-
ORPCDeserializer,
|
27
|
-
ORPCSerializer,
|
28
|
-
zodCoerce,
|
29
|
-
} from '@orpc/transformer'
|
30
|
-
import { LinearRouter } from 'hono/router/linear-router'
|
31
|
-
import { RegExpRouter } from 'hono/router/reg-exp-router'
|
32
|
-
import { isProcedure, type WELL_DEFINED_PROCEDURE } from '../procedure'
|
33
|
-
import { createProcedureCaller } from '../procedure-caller'
|
34
|
-
|
35
|
-
export interface FetchHandlerHooks {
|
36
|
-
next: () => Promise<Response>
|
37
|
-
response: (response: Response) => Response
|
38
|
-
}
|
39
|
-
|
40
|
-
export interface CreateFetchHandlerOptions<TRouter extends Router<any>> {
|
41
|
-
router: TRouter
|
42
|
-
|
43
|
-
/**
|
44
|
-
* Hooks for executing logics on lifecycle events.
|
45
|
-
*/
|
46
|
-
hooks?: (
|
47
|
-
context: TRouter extends Router<infer UContext> ? UContext : never,
|
48
|
-
hooks: FetchHandlerHooks,
|
49
|
-
) => Promisable<Response>
|
50
|
-
|
51
|
-
/**
|
52
|
-
* It will help improve the cold start time. But it will increase the performance.
|
53
|
-
*
|
54
|
-
* @default false
|
55
|
-
*/
|
56
|
-
serverless?: boolean
|
57
|
-
}
|
58
|
-
|
59
|
-
export function createFetchHandler<TRouter extends Router<any>>(
|
60
|
-
options: CreateFetchHandlerOptions<TRouter>,
|
61
|
-
): FetchHandler<TRouter> {
|
62
|
-
const routing = options.serverless
|
63
|
-
? new LinearRouter<[string[], WELL_DEFINED_PROCEDURE]>()
|
64
|
-
: new RegExpRouter<[string[], WELL_DEFINED_PROCEDURE]>()
|
65
|
-
|
66
|
-
const addRouteRecursively = (router: Router<any>, basePath: string[]) => {
|
67
|
-
for (const key in router) {
|
68
|
-
const currentPath = [...basePath, key]
|
69
|
-
const item = router[key] as WELL_DEFINED_PROCEDURE | Router<any>
|
70
|
-
|
71
|
-
if (isProcedure(item)) {
|
72
|
-
if (item.zz$p.contract.zz$cp.path) {
|
73
|
-
const method = item.zz$p.contract.zz$cp.method ?? 'POST'
|
74
|
-
const path = openAPIPathToRouterPath(item.zz$p.contract.zz$cp.path)
|
75
|
-
|
76
|
-
routing.add(method, path, [currentPath, item])
|
77
|
-
}
|
78
|
-
}
|
79
|
-
else {
|
80
|
-
addRouteRecursively(item, currentPath)
|
81
|
-
}
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
addRouteRecursively(options.router, [])
|
86
|
-
|
87
|
-
return async (requestOptions) => {
|
88
|
-
const isORPCTransformer
|
89
|
-
= requestOptions.request.headers.get(ORPC_HEADER) === ORPC_HEADER_VALUE
|
90
|
-
const accept = requestOptions.request.headers.get('Accept') || undefined
|
91
|
-
|
92
|
-
const serializer = isORPCTransformer
|
93
|
-
? new ORPCSerializer()
|
94
|
-
: new OpenAPISerializer({ accept })
|
95
|
-
|
96
|
-
const context = await value(requestOptions.context)
|
97
|
-
|
98
|
-
const handler = async () => {
|
99
|
-
const url = new URL(requestOptions.request.url)
|
100
|
-
const pathname = `/${trim(url.pathname.replace(requestOptions.prefix ?? '', ''), '/')}`
|
101
|
-
|
102
|
-
let path: string[] | undefined
|
103
|
-
let procedure: WELL_DEFINED_PROCEDURE | undefined
|
104
|
-
let params: Record<string, string> | undefined
|
105
|
-
|
106
|
-
if (isORPCTransformer) {
|
107
|
-
path = trim(pathname, '/').split('/').map(decodeURIComponent)
|
108
|
-
const val = get(options.router, path)
|
109
|
-
|
110
|
-
if (isProcedure(val)) {
|
111
|
-
procedure = val
|
112
|
-
}
|
113
|
-
}
|
114
|
-
else {
|
115
|
-
const customMethod
|
116
|
-
= requestOptions.request.method === 'POST'
|
117
|
-
? url.searchParams.get('method')?.toUpperCase()
|
118
|
-
: undefined
|
119
|
-
const method = customMethod || requestOptions.request.method
|
120
|
-
|
121
|
-
const [matches, params_] = routing.match(method, pathname)
|
122
|
-
|
123
|
-
const [match] = matches.sort((a, b) => {
|
124
|
-
return Object.keys(a[1]).length - Object.keys(b[1]).length
|
125
|
-
})
|
126
|
-
|
127
|
-
if (match) {
|
128
|
-
path = match[0][0]
|
129
|
-
procedure = match[0][1]
|
130
|
-
|
131
|
-
if (params_) {
|
132
|
-
params = mapValues(
|
133
|
-
(match as any)[1]!,
|
134
|
-
v => params_[v as number]!,
|
135
|
-
)
|
136
|
-
}
|
137
|
-
else {
|
138
|
-
params = match[1] as Record<string, string>
|
139
|
-
}
|
140
|
-
}
|
141
|
-
|
142
|
-
if (!path || !procedure) {
|
143
|
-
path = trim(pathname, '/').split('/').map(decodeURIComponent)
|
144
|
-
|
145
|
-
const val = get(options.router, path)
|
146
|
-
|
147
|
-
if (isProcedure(val)) {
|
148
|
-
procedure = val
|
149
|
-
}
|
150
|
-
}
|
151
|
-
}
|
152
|
-
|
153
|
-
if (!path || !procedure) {
|
154
|
-
throw new ORPCError({ code: 'NOT_FOUND', message: 'Not found' })
|
155
|
-
}
|
156
|
-
|
157
|
-
const deserializer = isORPCTransformer
|
158
|
-
? new ORPCDeserializer()
|
159
|
-
: new OpenAPIDeserializer({
|
160
|
-
schema: procedure.zz$p.contract.zz$cp.InputSchema,
|
161
|
-
})
|
162
|
-
|
163
|
-
const input_ = await (async () => {
|
164
|
-
try {
|
165
|
-
return await deserializer.deserialize(requestOptions.request)
|
166
|
-
}
|
167
|
-
catch (e) {
|
168
|
-
throw new ORPCError({
|
169
|
-
code: 'BAD_REQUEST',
|
170
|
-
message:
|
171
|
-
'Cannot parse request. Please check the request body and Content-Type header.',
|
172
|
-
cause: e,
|
173
|
-
})
|
174
|
-
}
|
175
|
-
})()
|
176
|
-
|
177
|
-
const input = (() => {
|
178
|
-
if (!params || Object.keys(params).length === 0) {
|
179
|
-
return input_
|
180
|
-
}
|
181
|
-
|
182
|
-
const coercedParams = procedure.zz$p.contract.zz$cp.InputSchema
|
183
|
-
? (zodCoerce(
|
184
|
-
procedure.zz$p.contract.zz$cp.InputSchema,
|
185
|
-
{ ...params },
|
186
|
-
{
|
187
|
-
bracketNotation: true,
|
188
|
-
},
|
189
|
-
) as object)
|
190
|
-
: params
|
191
|
-
|
192
|
-
if (!isPlainObject(input_)) {
|
193
|
-
return coercedParams
|
194
|
-
}
|
195
|
-
|
196
|
-
return {
|
197
|
-
...coercedParams,
|
198
|
-
...input_,
|
199
|
-
}
|
200
|
-
})()
|
201
|
-
|
202
|
-
const caller = createProcedureCaller({
|
203
|
-
context,
|
204
|
-
procedure,
|
205
|
-
path,
|
206
|
-
})
|
207
|
-
|
208
|
-
const output = await caller(input)
|
209
|
-
|
210
|
-
const { body, headers } = serializer.serialize(output)
|
211
|
-
|
212
|
-
return new Response(body, {
|
213
|
-
status: 200,
|
214
|
-
headers,
|
215
|
-
})
|
216
|
-
}
|
217
|
-
|
218
|
-
try {
|
219
|
-
return await options.hooks?.(context as any, {
|
220
|
-
next: handler,
|
221
|
-
response: response => response,
|
222
|
-
}) ?? await handler()
|
223
|
-
}
|
224
|
-
catch (e) {
|
225
|
-
const error = toORPCError(e)
|
226
|
-
|
227
|
-
try {
|
228
|
-
const { body, headers } = serializer.serialize(error.toJSON())
|
229
|
-
|
230
|
-
return new Response(body, {
|
231
|
-
status: error.status,
|
232
|
-
headers,
|
233
|
-
})
|
234
|
-
}
|
235
|
-
catch (e) {
|
236
|
-
const error = toORPCError(e)
|
237
|
-
|
238
|
-
// fallback to OpenAPI serializer (without accept) when expected serializer has failed
|
239
|
-
const { body, headers } = new OpenAPISerializer().serialize(
|
240
|
-
error.toJSON(),
|
241
|
-
)
|
242
|
-
|
243
|
-
return new Response(body, {
|
244
|
-
status: error.status,
|
245
|
-
headers,
|
246
|
-
})
|
247
|
-
}
|
248
|
-
}
|
249
|
-
}
|
250
|
-
}
|
251
|
-
|
252
|
-
function openAPIPathToRouterPath(path: HTTPPath): string {
|
253
|
-
return standardizeHTTPPath(path).replace(/\{([^}]+)\}/g, ':$1')
|
254
|
-
}
|
255
|
-
|
256
|
-
export type FetchHandlerOptions<TRouter extends Router<any>> = {
|
257
|
-
/**
|
258
|
-
* The request need to be handled.
|
259
|
-
*/
|
260
|
-
request: Request
|
261
|
-
|
262
|
-
/**
|
263
|
-
* Remove the prefix from the request path.
|
264
|
-
*
|
265
|
-
* @example /orpc
|
266
|
-
* @example /api
|
267
|
-
*/
|
268
|
-
prefix?: string
|
269
|
-
} & PartialOnUndefinedDeep<{
|
270
|
-
/**
|
271
|
-
* The context used to handle the request.
|
272
|
-
*/
|
273
|
-
context: Value<
|
274
|
-
TRouter extends Router<infer UContext> ? UContext : never
|
275
|
-
>
|
276
|
-
}>
|
277
|
-
|
278
|
-
export interface FetchHandler<TRouter extends Router<any>> {
|
279
|
-
(options: FetchHandlerOptions<TRouter>): Promise<Response>
|
280
|
-
}
|
281
|
-
|
282
|
-
function toORPCError(e: unknown): ORPCError<any, any> {
|
283
|
-
return e instanceof ORPCError
|
284
|
-
? e
|
285
|
-
: new ORPCError({
|
286
|
-
code: 'INTERNAL_SERVER_ERROR',
|
287
|
-
message: 'Internal server error',
|
288
|
-
cause: e,
|
289
|
-
})
|
290
|
-
}
|
package/src/builder.test.ts
DELETED
@@ -1,371 +0,0 @@
|
|
1
|
-
import type {
|
2
|
-
Builder,
|
3
|
-
DecoratedMiddleware,
|
4
|
-
DecoratedProcedure,
|
5
|
-
Meta,
|
6
|
-
MiddlewareMeta,
|
7
|
-
} from '.'
|
8
|
-
import { oc } from '@orpc/contract'
|
9
|
-
import { z } from 'zod'
|
10
|
-
import {
|
11
|
-
isProcedure,
|
12
|
-
os,
|
13
|
-
ProcedureBuilder,
|
14
|
-
ProcedureImplementer,
|
15
|
-
RouterImplementer,
|
16
|
-
} from '.'
|
17
|
-
import { RouterBuilder } from './router-builder'
|
18
|
-
|
19
|
-
it('context method', () => {
|
20
|
-
expectTypeOf<
|
21
|
-
typeof os extends Builder<infer TContext, any> ? TContext : never
|
22
|
-
>().toEqualTypeOf<undefined | Record<string, unknown>>()
|
23
|
-
|
24
|
-
const os2 = os.context<{ foo: 'bar' }>()
|
25
|
-
|
26
|
-
expectTypeOf<
|
27
|
-
typeof os2 extends Builder<infer TContext, any> ? TContext : never
|
28
|
-
>().toEqualTypeOf<{ foo: 'bar' }>()
|
29
|
-
|
30
|
-
const os3 = os.context<{ foo: 'bar' }>().context()
|
31
|
-
|
32
|
-
expectTypeOf<
|
33
|
-
typeof os3 extends Builder<infer TContext, any> ? TContext : never
|
34
|
-
>().toEqualTypeOf<{ foo: 'bar' }>()
|
35
|
-
})
|
36
|
-
|
37
|
-
describe('use middleware', () => {
|
38
|
-
type Context = { auth: boolean }
|
39
|
-
|
40
|
-
const osw = os.context<Context>()
|
41
|
-
|
42
|
-
it('infer types', () => {
|
43
|
-
osw.use((input, context, meta) => {
|
44
|
-
expectTypeOf(input).toEqualTypeOf<unknown>()
|
45
|
-
expectTypeOf(context).toEqualTypeOf<Context>()
|
46
|
-
expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<unknown>>()
|
47
|
-
|
48
|
-
return meta.next({})
|
49
|
-
})
|
50
|
-
})
|
51
|
-
|
52
|
-
it('can map context', () => {
|
53
|
-
osw
|
54
|
-
.use((_, __, meta) => {
|
55
|
-
return meta.next({ context: { userId: '1' } })
|
56
|
-
})
|
57
|
-
.use((_, context, meta) => {
|
58
|
-
expectTypeOf(context).toMatchTypeOf<Context & { userId: string }>()
|
59
|
-
|
60
|
-
return meta.next({})
|
61
|
-
})
|
62
|
-
})
|
63
|
-
|
64
|
-
it('can map input', () => {
|
65
|
-
osw
|
66
|
-
// @ts-expect-error mismatch input
|
67
|
-
.use((input: { postId: string }) => {})
|
68
|
-
.use(
|
69
|
-
(input: { postId: string }, _, meta) => {
|
70
|
-
return meta.next({ context: { user: '1' } })
|
71
|
-
},
|
72
|
-
(input) => {
|
73
|
-
expectTypeOf(input).toEqualTypeOf<unknown>()
|
74
|
-
return { postId: '1' }
|
75
|
-
},
|
76
|
-
)
|
77
|
-
.func((_, context) => {
|
78
|
-
expectTypeOf(context).toMatchTypeOf<{ user: string }>()
|
79
|
-
})
|
80
|
-
})
|
81
|
-
})
|
82
|
-
|
83
|
-
describe('create middleware', () => {
|
84
|
-
it('infer types', () => {
|
85
|
-
const mid = os
|
86
|
-
.context<{ auth: boolean }>()
|
87
|
-
.middleware((input, context, meta) => {
|
88
|
-
expectTypeOf(input).toEqualTypeOf<unknown>()
|
89
|
-
expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
|
90
|
-
expectTypeOf(meta).toEqualTypeOf<MiddlewareMeta<any>>()
|
91
|
-
|
92
|
-
return meta.next({ })
|
93
|
-
})
|
94
|
-
|
95
|
-
expectTypeOf(mid).toEqualTypeOf<
|
96
|
-
DecoratedMiddleware<{ auth: boolean }, undefined, unknown, any>
|
97
|
-
>()
|
98
|
-
})
|
99
|
-
|
100
|
-
it('map context', () => {
|
101
|
-
const mid = os.context<{ auth: boolean }>().middleware((_, __, meta) => {
|
102
|
-
return meta.next({ context: { userId: '1' } })
|
103
|
-
})
|
104
|
-
|
105
|
-
expectTypeOf(mid).toEqualTypeOf<
|
106
|
-
DecoratedMiddleware<
|
107
|
-
{ auth: boolean },
|
108
|
-
{ userId: string },
|
109
|
-
unknown,
|
110
|
-
any
|
111
|
-
>
|
112
|
-
>()
|
113
|
-
})
|
114
|
-
})
|
115
|
-
|
116
|
-
it('router method', () => {
|
117
|
-
const pingContract = oc.input(z.string()).output(z.string())
|
118
|
-
const userFindContract = oc
|
119
|
-
.input(z.object({ id: z.string() }))
|
120
|
-
.output(z.object({ name: z.string() }))
|
121
|
-
|
122
|
-
const contract = oc.router({
|
123
|
-
ping: pingContract,
|
124
|
-
user: {
|
125
|
-
find: userFindContract,
|
126
|
-
},
|
127
|
-
|
128
|
-
user2: oc.router({
|
129
|
-
find: userFindContract,
|
130
|
-
}),
|
131
|
-
|
132
|
-
router: userFindContract,
|
133
|
-
})
|
134
|
-
|
135
|
-
const osw = os.contract(contract)
|
136
|
-
|
137
|
-
expect(osw.ping).instanceOf(ProcedureImplementer)
|
138
|
-
expect(osw.ping.zz$pi.contract).toEqual(pingContract)
|
139
|
-
|
140
|
-
expect(osw.user).instanceOf(RouterImplementer)
|
141
|
-
|
142
|
-
expect(osw.user.find).instanceOf(ProcedureImplementer)
|
143
|
-
expect(osw.user.find.zz$pi.contract).toEqual(userFindContract)
|
144
|
-
|
145
|
-
// Because of the router keyword is special, we can't use instanceof
|
146
|
-
expect(osw.router.zz$pi.contract).toEqual(userFindContract)
|
147
|
-
expect(
|
148
|
-
osw.router.func(() => {
|
149
|
-
return { name: '' }
|
150
|
-
}),
|
151
|
-
).toSatisfy(isProcedure)
|
152
|
-
})
|
153
|
-
|
154
|
-
describe('define procedure builder', () => {
|
155
|
-
const osw = os.context<{ auth: boolean }>()
|
156
|
-
const schema1 = z.object({})
|
157
|
-
const example1 = {}
|
158
|
-
const schema2 = z.object({ a: z.string() })
|
159
|
-
const example2 = { a: '' }
|
160
|
-
|
161
|
-
it('input method', () => {
|
162
|
-
const builder = osw.input(schema1, example1)
|
163
|
-
|
164
|
-
expectTypeOf(builder).toEqualTypeOf<
|
165
|
-
ProcedureBuilder<{ auth: boolean }, undefined, typeof schema1, undefined>
|
166
|
-
>()
|
167
|
-
|
168
|
-
expect(builder).instanceOf(ProcedureBuilder)
|
169
|
-
expect(builder.zz$pb.middlewares).toBe(undefined)
|
170
|
-
expect(builder.zz$pb).toMatchObject({
|
171
|
-
contract: {
|
172
|
-
zz$cp: {
|
173
|
-
InputSchema: schema1,
|
174
|
-
inputExample: example1,
|
175
|
-
},
|
176
|
-
},
|
177
|
-
})
|
178
|
-
})
|
179
|
-
|
180
|
-
it('output method', () => {
|
181
|
-
const builder = osw.output(schema2, example2)
|
182
|
-
|
183
|
-
expectTypeOf(builder).toEqualTypeOf<
|
184
|
-
ProcedureBuilder<{ auth: boolean }, undefined, undefined, typeof schema2>
|
185
|
-
>()
|
186
|
-
|
187
|
-
expect(builder).instanceOf(ProcedureBuilder)
|
188
|
-
expect(builder.zz$pb.middlewares).toBe(undefined)
|
189
|
-
expect(builder.zz$pb).toMatchObject({
|
190
|
-
contract: {
|
191
|
-
zz$cp: {
|
192
|
-
OutputSchema: schema2,
|
193
|
-
outputExample: example2,
|
194
|
-
},
|
195
|
-
},
|
196
|
-
})
|
197
|
-
})
|
198
|
-
|
199
|
-
it('route method', () => {
|
200
|
-
const builder = osw.route({
|
201
|
-
method: 'GET',
|
202
|
-
path: '/test',
|
203
|
-
deprecated: true,
|
204
|
-
description: 'des',
|
205
|
-
summary: 'sum',
|
206
|
-
tags: ['cccc'],
|
207
|
-
})
|
208
|
-
|
209
|
-
expectTypeOf(builder).toEqualTypeOf<
|
210
|
-
ProcedureBuilder<{ auth: boolean }, undefined, undefined, undefined>
|
211
|
-
>()
|
212
|
-
|
213
|
-
expect(builder).instanceOf(ProcedureBuilder)
|
214
|
-
expect(builder.zz$pb.middlewares).toBe(undefined)
|
215
|
-
expect(builder.zz$pb).toMatchObject({
|
216
|
-
contract: {
|
217
|
-
zz$cp: {
|
218
|
-
method: 'GET',
|
219
|
-
path: '/test',
|
220
|
-
deprecated: true,
|
221
|
-
description: 'des',
|
222
|
-
summary: 'sum',
|
223
|
-
tags: ['cccc'],
|
224
|
-
},
|
225
|
-
},
|
226
|
-
})
|
227
|
-
})
|
228
|
-
|
229
|
-
it('with middlewares', () => {
|
230
|
-
const mid = os.middleware((_, __, meta) => {
|
231
|
-
return meta.next({
|
232
|
-
context: {
|
233
|
-
userId: 'string',
|
234
|
-
},
|
235
|
-
})
|
236
|
-
})
|
237
|
-
|
238
|
-
const mid2 = os.middleware((_, __, meta) => {
|
239
|
-
return meta.next({
|
240
|
-
context: {
|
241
|
-
mid2: true,
|
242
|
-
},
|
243
|
-
})
|
244
|
-
})
|
245
|
-
|
246
|
-
const osw = os.context<{ auth: boolean }>().use(mid).use(mid2)
|
247
|
-
|
248
|
-
const builder1 = osw.input(schema1)
|
249
|
-
const builder2 = osw.output(schema2)
|
250
|
-
const builder3 = osw.route({ method: 'GET', path: '/test' })
|
251
|
-
|
252
|
-
expectTypeOf(builder1).toEqualTypeOf<
|
253
|
-
ProcedureBuilder<
|
254
|
-
{ auth: boolean },
|
255
|
-
{ userId: string } & { mid2: boolean },
|
256
|
-
typeof schema1,
|
257
|
-
undefined
|
258
|
-
>
|
259
|
-
>()
|
260
|
-
|
261
|
-
expectTypeOf(builder2).toEqualTypeOf<
|
262
|
-
ProcedureBuilder<
|
263
|
-
{ auth: boolean },
|
264
|
-
{ userId: string } & { mid2: boolean },
|
265
|
-
undefined,
|
266
|
-
typeof schema2
|
267
|
-
>
|
268
|
-
>()
|
269
|
-
|
270
|
-
expectTypeOf(builder3).toEqualTypeOf<
|
271
|
-
ProcedureBuilder<
|
272
|
-
{ auth: boolean },
|
273
|
-
{ userId: string } & { mid2: boolean },
|
274
|
-
undefined,
|
275
|
-
undefined
|
276
|
-
>
|
277
|
-
>()
|
278
|
-
|
279
|
-
expect(builder1.zz$pb.middlewares).toEqual([mid, mid2])
|
280
|
-
expect(builder2.zz$pb.middlewares).toEqual([mid, mid2])
|
281
|
-
expect(builder3.zz$pb.middlewares).toEqual([mid, mid2])
|
282
|
-
})
|
283
|
-
})
|
284
|
-
|
285
|
-
describe('handler method', () => {
|
286
|
-
it('without middlewares', () => {
|
287
|
-
const osw = os.context<{ auth: boolean }>()
|
288
|
-
|
289
|
-
const procedure = osw.func((input, context, meta) => {
|
290
|
-
expectTypeOf(input).toEqualTypeOf<unknown>()
|
291
|
-
expectTypeOf(context).toEqualTypeOf<{ auth: boolean }>()
|
292
|
-
expectTypeOf(meta).toEqualTypeOf<Meta>()
|
293
|
-
})
|
294
|
-
|
295
|
-
expectTypeOf(procedure).toEqualTypeOf<
|
296
|
-
DecoratedProcedure<
|
297
|
-
{ auth: boolean },
|
298
|
-
undefined,
|
299
|
-
undefined,
|
300
|
-
undefined,
|
301
|
-
void
|
302
|
-
>
|
303
|
-
>()
|
304
|
-
|
305
|
-
expect(isProcedure(procedure)).toBe(true)
|
306
|
-
expect(procedure.zz$p.middlewares).toBe(undefined)
|
307
|
-
})
|
308
|
-
|
309
|
-
it('with middlewares', () => {
|
310
|
-
const mid = os.middleware((_, __, meta) => {
|
311
|
-
return meta.next({
|
312
|
-
context: {
|
313
|
-
userId: 'string',
|
314
|
-
},
|
315
|
-
})
|
316
|
-
})
|
317
|
-
|
318
|
-
const osw = os.context<{ auth: boolean }>().use(mid)
|
319
|
-
|
320
|
-
const procedure = osw.func((input, context, meta) => {
|
321
|
-
expectTypeOf(input).toEqualTypeOf<unknown>()
|
322
|
-
expectTypeOf(context).toMatchTypeOf<{ auth: boolean }>()
|
323
|
-
expectTypeOf(meta).toEqualTypeOf<Meta>()
|
324
|
-
})
|
325
|
-
|
326
|
-
expectTypeOf(procedure).toEqualTypeOf<
|
327
|
-
DecoratedProcedure<
|
328
|
-
{ auth: boolean },
|
329
|
-
{ userId: string },
|
330
|
-
undefined,
|
331
|
-
undefined,
|
332
|
-
void
|
333
|
-
>
|
334
|
-
>()
|
335
|
-
|
336
|
-
expect(isProcedure(procedure)).toBe(true)
|
337
|
-
expect(procedure.zz$p.middlewares).toEqual([mid])
|
338
|
-
})
|
339
|
-
})
|
340
|
-
|
341
|
-
it('prefix', () => {
|
342
|
-
const builder = os
|
343
|
-
.context<{ auth: boolean }>()
|
344
|
-
.use((_, __, meta) => {
|
345
|
-
return meta.next({ context: { userId: '1' } })
|
346
|
-
})
|
347
|
-
.prefix('/api')
|
348
|
-
|
349
|
-
expectTypeOf(builder).toEqualTypeOf<
|
350
|
-
RouterBuilder<{ auth: boolean }, { userId: string }>
|
351
|
-
>()
|
352
|
-
|
353
|
-
expect(builder).instanceOf(RouterBuilder)
|
354
|
-
expect(builder.zz$rb.prefix).toEqual('/api')
|
355
|
-
})
|
356
|
-
|
357
|
-
it('tags', () => {
|
358
|
-
const builder = os
|
359
|
-
.context<{ auth: boolean }>()
|
360
|
-
.use((_, __, meta) => {
|
361
|
-
return meta.next({ context: { userId: '1' } })
|
362
|
-
})
|
363
|
-
.tags('user', 'user2')
|
364
|
-
|
365
|
-
expectTypeOf(builder).toEqualTypeOf<
|
366
|
-
RouterBuilder<{ auth: boolean }, { userId: string }>
|
367
|
-
>()
|
368
|
-
|
369
|
-
expect(builder).instanceOf(RouterBuilder)
|
370
|
-
expect(builder.zz$rb.tags).toEqual(['user', 'user2'])
|
371
|
-
})
|