@orpc/openapi 1.14.6 → 2.0.0-beta.2
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/README.md +74 -109
- package/dist/adapters/fetch/index.d.mts +20 -16
- package/dist/adapters/fetch/index.d.ts +20 -16
- package/dist/adapters/fetch/index.mjs +24 -8
- package/dist/adapters/node/index.d.mts +8 -13
- package/dist/adapters/node/index.d.ts +8 -13
- package/dist/adapters/node/index.mjs +10 -7
- package/dist/adapters/standard/index.d.mts +46 -16
- package/dist/adapters/standard/index.d.ts +46 -16
- package/dist/adapters/standard/index.mjs +9 -6
- package/dist/extensions/route.d.mts +43 -0
- package/dist/extensions/route.d.ts +43 -0
- package/dist/extensions/route.mjs +14 -0
- package/dist/helpers/index.d.mts +51 -0
- package/dist/helpers/index.d.ts +51 -0
- package/dist/helpers/index.mjs +39 -0
- package/dist/index.d.mts +96 -110
- package/dist/index.d.ts +96 -110
- package/dist/index.mjs +894 -34
- package/dist/plugins/index.d.mts +55 -51
- package/dist/plugins/index.d.ts +55 -51
- package/dist/plugins/index.mjs +147 -142
- package/dist/shared/openapi.B2SK0ZAr.mjs +359 -0
- package/dist/shared/openapi.B9PQzqBn.mjs +49 -0
- package/dist/shared/openapi.BQzzr4-4.d.ts +299 -0
- package/dist/shared/openapi.BYcWgK1j.d.ts +79 -0
- package/dist/shared/openapi.BcEtAxQj.d.mts +299 -0
- package/dist/shared/openapi.Bt87OzTt.mjs +131 -0
- package/dist/shared/openapi.C7m7NAmH.d.mts +142 -0
- package/dist/shared/openapi.C7m7NAmH.d.ts +142 -0
- package/dist/shared/openapi.CYgMBSUF.d.mts +18 -0
- package/dist/shared/openapi.CYgMBSUF.d.ts +18 -0
- package/dist/shared/openapi.DR-y5p-D.mjs +315 -0
- package/dist/shared/openapi.DmAa7YPO.mjs +275 -0
- package/dist/shared/openapi.XeW6_5tm.d.mts +79 -0
- package/package.json +30 -24
- package/dist/adapters/aws-lambda/index.d.mts +0 -20
- package/dist/adapters/aws-lambda/index.d.ts +0 -20
- package/dist/adapters/aws-lambda/index.mjs +0 -18
- package/dist/adapters/fastify/index.d.mts +0 -23
- package/dist/adapters/fastify/index.d.ts +0 -23
- package/dist/adapters/fastify/index.mjs +0 -18
- package/dist/shared/openapi.BB-W-NKv.mjs +0 -204
- package/dist/shared/openapi.BGy4N6eR.d.mts +0 -120
- package/dist/shared/openapi.BGy4N6eR.d.ts +0 -120
- package/dist/shared/openapi.BwdtJjDu.mjs +0 -878
- package/dist/shared/openapi.DwaweYRb.d.mts +0 -54
- package/dist/shared/openapi.DwaweYRb.d.ts +0 -54
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { AnySchema, ErrorMap, MetaPlugin, AnyProcedureContract } from '@orpc/contract';
|
|
2
|
+
import { Lazy } from '@orpc/server';
|
|
3
|
+
import { Value } from '@orpc/shared';
|
|
4
|
+
import { StandardBodyHint } from '@standardserver/core';
|
|
5
|
+
import { O as OpenAPIOperationObject } from './openapi.CYgMBSUF.js';
|
|
6
|
+
|
|
7
|
+
interface OpenAPIMeta {
|
|
8
|
+
/**
|
|
9
|
+
* HTTP method accepted by this procedure.
|
|
10
|
+
*
|
|
11
|
+
* @default 'POST'
|
|
12
|
+
*/
|
|
13
|
+
method?: 'HEAD' | 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* URL path for this procedure. Supports dynamic segments via `${}` syntax.
|
|
16
|
+
*
|
|
17
|
+
* @example `/users`, `/users/${id}`
|
|
18
|
+
* @default Router segments joined by `'/`
|
|
19
|
+
*/
|
|
20
|
+
path?: `/${string}` | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Unique identifier for this operation in the OpenAPI spec.
|
|
23
|
+
*
|
|
24
|
+
* @default Router segments joined by `.`
|
|
25
|
+
*/
|
|
26
|
+
operationId?: string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Short summary of the procedure, used as the operation summary in the generated spec.
|
|
29
|
+
*/
|
|
30
|
+
summary?: string | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Detailed description of the procedure, used as the operation description in the generated spec.
|
|
33
|
+
*/
|
|
34
|
+
description?: string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Marks the procedure as deprecated in the generated spec.
|
|
37
|
+
*/
|
|
38
|
+
deprecated?: boolean | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Tags associated with this procedure.
|
|
41
|
+
*
|
|
42
|
+
* **Note**: Tags are merged when defined multiple times.
|
|
43
|
+
*/
|
|
44
|
+
tags?: string[] | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* HTTP status code returned on success. Must be in the 200–399 range.
|
|
47
|
+
*
|
|
48
|
+
* @default 200
|
|
49
|
+
*/
|
|
50
|
+
successStatus?: number | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Description of the successful response.
|
|
53
|
+
*
|
|
54
|
+
* @default 'OK'
|
|
55
|
+
*/
|
|
56
|
+
successDescription?: string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Controls how individual path parameters are decoded.
|
|
59
|
+
*
|
|
60
|
+
* **Note**: Param styles are merged when defined multiple times.
|
|
61
|
+
*
|
|
62
|
+
* Each key maps a path parameter name to one of the following strategies:
|
|
63
|
+
*
|
|
64
|
+
* | Strategy | Encoded path segment | Decoded | OpenAPI Parameter Style |
|
|
65
|
+
* |--------------------------|----------------------|------------------------------|----------------------------------|
|
|
66
|
+
* | `primitive` *(default)* | `/users/42` | `{ id: '42' }` | `simple` |
|
|
67
|
+
* | `comma-delimited-array` | `/users/a,b,c` | `{ id: ['a', 'b', 'c'] }` | `simple` |
|
|
68
|
+
* | `comma-delimited-object` | `/users/a,1,b,2` | `{ id: { a: '1', b: '2' } }` | `simple` |
|
|
69
|
+
*
|
|
70
|
+
* **Strategy details:**
|
|
71
|
+
*
|
|
72
|
+
* - **`primitive`**: Keeps the decoded path segment as a string.
|
|
73
|
+
* - **`comma-delimited-array`**: Splits the decoded path segment on `,` into an array.
|
|
74
|
+
* - **`comma-delimited-object`**: Splits the decoded path segment on `,` into alternating key-value pairs.
|
|
75
|
+
*
|
|
76
|
+
* **Note**: `*-delimited-*` strategies do not support keys or values containing the delimiter character.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* // openapi.path = '/users/{id}/{tags}/{filters}'
|
|
81
|
+
* // GET /users/42/red,blue/size,large,brand,nike
|
|
82
|
+
*
|
|
83
|
+
* const paramsStyles = {
|
|
84
|
+
* id: 'primitive',
|
|
85
|
+
* tags: 'comma-delimited-array',
|
|
86
|
+
* filters: 'comma-delimited-object',
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* const inputSchema = z.object({
|
|
90
|
+
* id: z.string(),
|
|
91
|
+
* tags: z.array(z.string()),
|
|
92
|
+
* filters: z.object({
|
|
93
|
+
* size: z.string(),
|
|
94
|
+
* brand: z.string(),
|
|
95
|
+
* }),
|
|
96
|
+
* })
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @default `primitive` for all parameters
|
|
100
|
+
*/
|
|
101
|
+
paramsStyles?: Record<string, 'primitive' | 'comma-delimited-array' | 'comma-delimited-object' | undefined> | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Controls how individual query parameters are encoding/decoding.
|
|
104
|
+
*
|
|
105
|
+
* **Note**: Query styles are merged when defined multiple times.
|
|
106
|
+
*
|
|
107
|
+
* Each key maps a query parameter name to one of the following strategies:
|
|
108
|
+
*
|
|
109
|
+
* | Strategy | Encoded | Decoded | OpenAPI Parameter Style |
|
|
110
|
+
* |--------------------------|---------------------------|--------------------------------|------------------------------------|
|
|
111
|
+
* | `primitive` | `?a=1&a=2` | `{ a: '2' }` | `form` / `explode: false` |
|
|
112
|
+
* | `array` | `?a=1&a=2` | `{ a: ['1', '2'] }` | `form` / `explode: true` |
|
|
113
|
+
* | `comma-delimited-array` | `?a=1,2,3` | `{ a: ['1', '2', '3'] }` | `form` / `explode: false` |
|
|
114
|
+
* | `comma-delimited-object` | `?a=A,1,B,2` | `{ a: { A: '1', B: '2' } }` | `form` / `explode: false` |
|
|
115
|
+
* | `space-delimited-array` | `?a=1 2 3` | `{ a: ['1', '2', '3'] }` | `spaceDelimited` / `explode: false`|
|
|
116
|
+
* | `space-delimited-object` | `?a=A 1 B 2` | `{ a: { A: '1', B: '2' } }` | `spaceDelimited` / `explode: false`|
|
|
117
|
+
* | `pipe-delimited-array` | `?a=1\|2\|3` | `{ a: ['1', '2', '3'] }` | `pipeDelimited` / `explode: false` |
|
|
118
|
+
* | `pipe-delimited-object` | `?a=A\|1\|B\|2` | `{ a: { A: '1', B: '2' } }` | `pipeDelimited` / `explode: false` |
|
|
119
|
+
* | `json` | `?meta={"key":"value"}` | `{ meta: { key: 'value' } }` | `content: application/json` |
|
|
120
|
+
* | _default_ | `?a[]=1&a[]=2&b=3&c[d]=4` | `{a:['1', '2'], b:3, c:{d:4}}` | `deepObject` / `explode: true` |
|
|
121
|
+
*
|
|
122
|
+
* **Strategy details:**
|
|
123
|
+
*
|
|
124
|
+
* - **`primitive`**: Takes the last occurrence of a repeated parameter.
|
|
125
|
+
* - **`array`**: Always produces an array, even for a single occurrence.
|
|
126
|
+
* - **`*-delimited-array`**: Splits the last value on the delimiter (`,`, space, or `|`) into an array.
|
|
127
|
+
* - **`*-delimited-object`**: Splits the last value on the delimiter into alternating key–value pairs.
|
|
128
|
+
* - **`json`**: Parses the last value as JSON; falls back to the raw string if parsing fails.
|
|
129
|
+
* - **`undefined`**: Standard bracket-notation decoding This is the default.
|
|
130
|
+
*
|
|
131
|
+
* **Note**: `*-delimited-*` strategies do not support keys or values containing the delimiter character.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* // GET /search?keyword=abc&tags=a,b,c&meta={"key":"value"}
|
|
136
|
+
* const queryParsing = {
|
|
137
|
+
* keyword: 'primitive',
|
|
138
|
+
* tags: 'comma-delimited-array',
|
|
139
|
+
* meta: 'json',
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* const inputSchema = z.object({
|
|
143
|
+
* keyword: z.string(),
|
|
144
|
+
* tags: z.array(z.string()),
|
|
145
|
+
* meta: z.object({ key: z.string() }),
|
|
146
|
+
* })
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @default `undefined` for all parameters (bracket-notation decoding)
|
|
150
|
+
*/
|
|
151
|
+
queryStyles?: Record<string, 'primitive' | 'array' | 'comma-delimited-array' | 'comma-delimited-object' | 'space-delimited-array' | 'space-delimited-object' | 'pipe-delimited-array' | 'pipe-delimited-object' | 'json' | undefined> | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Hint for how to parse the incoming request body.
|
|
154
|
+
*
|
|
155
|
+
* Note: The `standard-server` `Content-Type` header takes priority over this option.
|
|
156
|
+
* `form-data` and `url-search-params` are decoded using bracket notation,
|
|
157
|
+
* so the resulting value will be an object or array.
|
|
158
|
+
*
|
|
159
|
+
* @default Inferred from `Content-Type`, `Content-Disposition`, and `Content-Length`
|
|
160
|
+
*/
|
|
161
|
+
requestBodyHint?: StandardBodyHint | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* Hint for how to parse the response body.
|
|
164
|
+
*
|
|
165
|
+
* Note: The `standard-server` `Content-Type` header takes priority over this option.
|
|
166
|
+
* `form-data` and `url-search-params` are decoded using bracket notation,
|
|
167
|
+
* so the resulting value will be an object or array.
|
|
168
|
+
*
|
|
169
|
+
* @default Inferred from `Content-Type`, `Content-Disposition`, and `Content-Length`
|
|
170
|
+
*/
|
|
171
|
+
responseBodyHint?: StandardBodyHint | undefined;
|
|
172
|
+
/**
|
|
173
|
+
* Determines how the input should be structured
|
|
174
|
+
* based on params, query, headers, and body.
|
|
175
|
+
*
|
|
176
|
+
* - `compact` — Merges params with either query or body
|
|
177
|
+
* (depending on the HTTP method) into a single flat object.
|
|
178
|
+
* Use this when you don't need access to headers and your
|
|
179
|
+
* param/query/body keys don't conflict.
|
|
180
|
+
*
|
|
181
|
+
* ```ts
|
|
182
|
+
* // GET /users/42?search=hello
|
|
183
|
+
* const inputValue = { id: 42, search: 'hello' }
|
|
184
|
+
*
|
|
185
|
+
* const inputSchema = z.object({
|
|
186
|
+
* id: z.coerce.number(), // from params
|
|
187
|
+
* search: z.string(), // from query
|
|
188
|
+
* })
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* - `detailed` — Keeps each part of the request as a
|
|
192
|
+
* separate nested field. Use this when you need access
|
|
193
|
+
* to headers, or when params and query/body keys
|
|
194
|
+
* might conflict.
|
|
195
|
+
*
|
|
196
|
+
* ```ts
|
|
197
|
+
* const inputValue = {
|
|
198
|
+
* params: { id: 1 },
|
|
199
|
+
* query: { search: 'hello' },
|
|
200
|
+
* headers: { 'content-type': 'application/json' },
|
|
201
|
+
* body: 'body value',
|
|
202
|
+
* }
|
|
203
|
+
*
|
|
204
|
+
* const inputSchema = z.object({
|
|
205
|
+
* params: z.object({ id: z.coerce.number() }),
|
|
206
|
+
* query: z.object({ search: z.string() }),
|
|
207
|
+
* headers: z.object({ 'content-type': z.string() }),
|
|
208
|
+
* body: z.string(),
|
|
209
|
+
* })
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @default 'compact'
|
|
213
|
+
*/
|
|
214
|
+
inputStructure?: 'compact' | 'detailed' | undefined;
|
|
215
|
+
/**
|
|
216
|
+
* Determines how the output should be structured
|
|
217
|
+
* into the HTTP response.
|
|
218
|
+
*
|
|
219
|
+
* - `compact` — The return value is sent directly as the
|
|
220
|
+
* response body. Status code comes from successStatus.
|
|
221
|
+
*
|
|
222
|
+
* ```ts
|
|
223
|
+
* const outputValue = { id: 1, name: 'Alice' }
|
|
224
|
+
*
|
|
225
|
+
* const outputSchema = z.object({
|
|
226
|
+
* id: z.number(),
|
|
227
|
+
* name: z.string(),
|
|
228
|
+
* })
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* - `detailed` — Return an object with optional properties:
|
|
232
|
+
* - status: HTTP status code (200–399). Defaults to
|
|
233
|
+
* successStatus if omitted. Use a literal type
|
|
234
|
+
* (e.g. z.literal(201)) so the generated spec can reflects
|
|
235
|
+
* the exact code.
|
|
236
|
+
* - headers: Custom headers to merge into the response
|
|
237
|
+
* (Record<string, string | string[] | undefined>).
|
|
238
|
+
* - body: The response body.
|
|
239
|
+
*
|
|
240
|
+
* ```ts
|
|
241
|
+
* const outputValue = {
|
|
242
|
+
* status: 201,
|
|
243
|
+
* headers: { 'x-custom-header': 'value' },
|
|
244
|
+
* body: 'body value',
|
|
245
|
+
* }
|
|
246
|
+
*
|
|
247
|
+
* const outputSchema = z.object({
|
|
248
|
+
* status: z.literal(201).meta({ description: 'Record Created' }),
|
|
249
|
+
* headers: z.object({ 'x-custom-header': z.string() }),
|
|
250
|
+
* body: z.string(),
|
|
251
|
+
* })
|
|
252
|
+
* ```
|
|
253
|
+
*
|
|
254
|
+
* @default 'compact'
|
|
255
|
+
*/
|
|
256
|
+
outputStructure?: 'compact' | 'detailed' | undefined;
|
|
257
|
+
/**
|
|
258
|
+
* Override or extend the generated OpenAPI operation object for this procedure.
|
|
259
|
+
*
|
|
260
|
+
* Pass a plain object to replace entire operation object, or a function that receives the current
|
|
261
|
+
* operation object and returns the modified version.
|
|
262
|
+
*
|
|
263
|
+
* **Note**: Spec is merged when defined multiple times.
|
|
264
|
+
*/
|
|
265
|
+
spec?: Value<OpenAPIOperationObject, [current: OpenAPIOperationObject]>;
|
|
266
|
+
/**
|
|
267
|
+
* Prefix for the path. Useful when you want to apply a common path prefix across multiple procedures.
|
|
268
|
+
*
|
|
269
|
+
* **Note**: Prefixes are merged when defined multiple times.
|
|
270
|
+
*/
|
|
271
|
+
prefix?: `/${string}` | undefined;
|
|
272
|
+
}
|
|
273
|
+
interface OpenAPIMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
274
|
+
name: '~openapi';
|
|
275
|
+
}
|
|
276
|
+
interface OpenAPIMethodMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
277
|
+
name: '~openapi/method';
|
|
278
|
+
}
|
|
279
|
+
interface OpenAPIPathMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
280
|
+
name: '~openapi/path';
|
|
281
|
+
}
|
|
282
|
+
interface OpenAPISpecMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
283
|
+
name: '~openapi/spec';
|
|
284
|
+
}
|
|
285
|
+
interface OpenAPIPrefixMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
286
|
+
name: '~openapi/prefix';
|
|
287
|
+
}
|
|
288
|
+
interface OpenAPIFunction {
|
|
289
|
+
(meta: OpenAPIMeta): OpenAPIMetaPlugin<any, any, any>;
|
|
290
|
+
method(method: OpenAPIMeta['method']): OpenAPIMethodMetaPlugin<any, any, any>;
|
|
291
|
+
path(method: OpenAPIMeta['path']): OpenAPIPathMetaPlugin<any, any, any>;
|
|
292
|
+
spec(method: OpenAPIMeta['spec']): OpenAPISpecMetaPlugin<any, any, any>;
|
|
293
|
+
prefix(method: OpenAPIMeta['prefix']): OpenAPIPrefixMetaPlugin<any, any, any>;
|
|
294
|
+
}
|
|
295
|
+
declare const openapi: OpenAPIFunction;
|
|
296
|
+
declare function getOpenAPIMeta(procedureOrLazy: AnyProcedureContract | Lazy<any>): OpenAPIMeta | undefined;
|
|
297
|
+
|
|
298
|
+
export { getOpenAPIMeta as g, openapi as o };
|
|
299
|
+
export type { OpenAPIMeta as O, OpenAPIFunction as a, OpenAPIMetaPlugin as b, OpenAPIMethodMetaPlugin as c, OpenAPIPathMetaPlugin as d, OpenAPIPrefixMetaPlugin as e, OpenAPISpecMetaPlugin as f };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { AnyORPCError } from '@orpc/client';
|
|
2
|
+
import { AnyProcedure, AnyRouter, Context } from '@orpc/server';
|
|
3
|
+
import { StandardHandlerCodec, StandardHandlerHandleOptions, StandardHandlerCodecResolvedProcedure } from '@orpc/server/standard';
|
|
4
|
+
import { Value, Promisable } from '@orpc/shared';
|
|
5
|
+
import { StandardLazyRequest, StandardResponse } from '@standardserver/core';
|
|
6
|
+
import { AnyProcedureContract } from '@orpc/contract';
|
|
7
|
+
import { O as OpenAPISerializer } from './openapi.C7m7NAmH.js';
|
|
8
|
+
|
|
9
|
+
interface OpenAPIMatcherOptions {
|
|
10
|
+
/**
|
|
11
|
+
* Filter which procedures are exposed for matching. Return `false` to exclude.
|
|
12
|
+
*
|
|
13
|
+
* @default true
|
|
14
|
+
*/
|
|
15
|
+
filter?: Value<boolean, [contract: AnyProcedureContract | AnyProcedure, path: string[]]>;
|
|
16
|
+
}
|
|
17
|
+
declare class OpenAPIMatcher {
|
|
18
|
+
private readonly filter;
|
|
19
|
+
private readonly rootRouter;
|
|
20
|
+
private readonly tree;
|
|
21
|
+
private pendingLazyRouters;
|
|
22
|
+
constructor(router: AnyRouter, options?: OpenAPIMatcherOptions);
|
|
23
|
+
private index;
|
|
24
|
+
match(method: string, pathname: `/${string}`, prefix: `/${string}` | undefined): Promise<{
|
|
25
|
+
path: string[];
|
|
26
|
+
procedure: AnyProcedure;
|
|
27
|
+
params?: Record<string, string> | undefined;
|
|
28
|
+
} | undefined>;
|
|
29
|
+
private matchPathname;
|
|
30
|
+
private resolvePendingLazyRouters;
|
|
31
|
+
private resolveProcedure;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare class OpenAPIHandlerCodecError extends TypeError {
|
|
35
|
+
}
|
|
36
|
+
interface OpenAPIHandlerCodecOptions<_T extends Context> extends OpenAPIMatcherOptions {
|
|
37
|
+
/**
|
|
38
|
+
* Override the default OpenAPI serializer.
|
|
39
|
+
*/
|
|
40
|
+
serializer?: Pick<OpenAPISerializer, keyof OpenAPISerializer>;
|
|
41
|
+
/**
|
|
42
|
+
* Mapping ORPCError Code -> HTTP Status Code
|
|
43
|
+
*
|
|
44
|
+
* @default COMMON_ERROR_STATUS_MAP, DEFAULT_ERROR_STATUS
|
|
45
|
+
*/
|
|
46
|
+
errorStatusMap?: Record<string, number> | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Customize how an ORPC error is serialized into a response body.
|
|
49
|
+
* Use this if your API needs a different error output structure.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* - Return `null | undefined` to fallback to default behavior
|
|
53
|
+
*
|
|
54
|
+
* @default ((e) => e.toJSON())
|
|
55
|
+
*/
|
|
56
|
+
customErrorResponseBodyEncoder?: (error: AnyORPCError) => unknown;
|
|
57
|
+
}
|
|
58
|
+
declare class OpenAPIHandlerCodec<T extends Context> implements StandardHandlerCodec<T> {
|
|
59
|
+
private readonly matcher;
|
|
60
|
+
private readonly serializer;
|
|
61
|
+
private readonly errorStatusMap;
|
|
62
|
+
private readonly customErrorResponseBodySerializer;
|
|
63
|
+
constructor(router: AnyRouter, options?: OpenAPIHandlerCodecOptions<T>);
|
|
64
|
+
decodeInput(matched: {
|
|
65
|
+
procedure: AnyProcedure;
|
|
66
|
+
params?: undefined | Record<string, string>;
|
|
67
|
+
}, request: StandardLazyRequest): Promise<unknown>;
|
|
68
|
+
resolveProcedure(request: StandardLazyRequest, options: StandardHandlerHandleOptions<T>): Promise<StandardHandlerCodecResolvedProcedure | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* @throws {Error} If `outputStructure` is "detailed" and the output doesn't match the expected structure.
|
|
71
|
+
*/
|
|
72
|
+
encodeOutput(output: unknown, procedure: AnyProcedure, path: string[], _options: StandardHandlerHandleOptions<T>): Promisable<StandardResponse>;
|
|
73
|
+
encodeError(error: AnyORPCError, _procedure: AnyProcedure, _path: string[], _options: StandardHandlerHandleOptions<T>): Promisable<StandardResponse>;
|
|
74
|
+
private deserializeQuery;
|
|
75
|
+
private deserializeParams;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { OpenAPIHandlerCodec as a, OpenAPIHandlerCodecError as b, OpenAPIMatcher as c };
|
|
79
|
+
export type { OpenAPIHandlerCodecOptions as O, OpenAPIMatcherOptions as d };
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { AnySchema, ErrorMap, MetaPlugin, AnyProcedureContract } from '@orpc/contract';
|
|
2
|
+
import { Lazy } from '@orpc/server';
|
|
3
|
+
import { Value } from '@orpc/shared';
|
|
4
|
+
import { StandardBodyHint } from '@standardserver/core';
|
|
5
|
+
import { O as OpenAPIOperationObject } from './openapi.CYgMBSUF.mjs';
|
|
6
|
+
|
|
7
|
+
interface OpenAPIMeta {
|
|
8
|
+
/**
|
|
9
|
+
* HTTP method accepted by this procedure.
|
|
10
|
+
*
|
|
11
|
+
* @default 'POST'
|
|
12
|
+
*/
|
|
13
|
+
method?: 'HEAD' | 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* URL path for this procedure. Supports dynamic segments via `${}` syntax.
|
|
16
|
+
*
|
|
17
|
+
* @example `/users`, `/users/${id}`
|
|
18
|
+
* @default Router segments joined by `'/`
|
|
19
|
+
*/
|
|
20
|
+
path?: `/${string}` | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Unique identifier for this operation in the OpenAPI spec.
|
|
23
|
+
*
|
|
24
|
+
* @default Router segments joined by `.`
|
|
25
|
+
*/
|
|
26
|
+
operationId?: string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Short summary of the procedure, used as the operation summary in the generated spec.
|
|
29
|
+
*/
|
|
30
|
+
summary?: string | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* Detailed description of the procedure, used as the operation description in the generated spec.
|
|
33
|
+
*/
|
|
34
|
+
description?: string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Marks the procedure as deprecated in the generated spec.
|
|
37
|
+
*/
|
|
38
|
+
deprecated?: boolean | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Tags associated with this procedure.
|
|
41
|
+
*
|
|
42
|
+
* **Note**: Tags are merged when defined multiple times.
|
|
43
|
+
*/
|
|
44
|
+
tags?: string[] | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* HTTP status code returned on success. Must be in the 200–399 range.
|
|
47
|
+
*
|
|
48
|
+
* @default 200
|
|
49
|
+
*/
|
|
50
|
+
successStatus?: number | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Description of the successful response.
|
|
53
|
+
*
|
|
54
|
+
* @default 'OK'
|
|
55
|
+
*/
|
|
56
|
+
successDescription?: string | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Controls how individual path parameters are decoded.
|
|
59
|
+
*
|
|
60
|
+
* **Note**: Param styles are merged when defined multiple times.
|
|
61
|
+
*
|
|
62
|
+
* Each key maps a path parameter name to one of the following strategies:
|
|
63
|
+
*
|
|
64
|
+
* | Strategy | Encoded path segment | Decoded | OpenAPI Parameter Style |
|
|
65
|
+
* |--------------------------|----------------------|------------------------------|----------------------------------|
|
|
66
|
+
* | `primitive` *(default)* | `/users/42` | `{ id: '42' }` | `simple` |
|
|
67
|
+
* | `comma-delimited-array` | `/users/a,b,c` | `{ id: ['a', 'b', 'c'] }` | `simple` |
|
|
68
|
+
* | `comma-delimited-object` | `/users/a,1,b,2` | `{ id: { a: '1', b: '2' } }` | `simple` |
|
|
69
|
+
*
|
|
70
|
+
* **Strategy details:**
|
|
71
|
+
*
|
|
72
|
+
* - **`primitive`**: Keeps the decoded path segment as a string.
|
|
73
|
+
* - **`comma-delimited-array`**: Splits the decoded path segment on `,` into an array.
|
|
74
|
+
* - **`comma-delimited-object`**: Splits the decoded path segment on `,` into alternating key-value pairs.
|
|
75
|
+
*
|
|
76
|
+
* **Note**: `*-delimited-*` strategies do not support keys or values containing the delimiter character.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* // openapi.path = '/users/{id}/{tags}/{filters}'
|
|
81
|
+
* // GET /users/42/red,blue/size,large,brand,nike
|
|
82
|
+
*
|
|
83
|
+
* const paramsStyles = {
|
|
84
|
+
* id: 'primitive',
|
|
85
|
+
* tags: 'comma-delimited-array',
|
|
86
|
+
* filters: 'comma-delimited-object',
|
|
87
|
+
* }
|
|
88
|
+
*
|
|
89
|
+
* const inputSchema = z.object({
|
|
90
|
+
* id: z.string(),
|
|
91
|
+
* tags: z.array(z.string()),
|
|
92
|
+
* filters: z.object({
|
|
93
|
+
* size: z.string(),
|
|
94
|
+
* brand: z.string(),
|
|
95
|
+
* }),
|
|
96
|
+
* })
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @default `primitive` for all parameters
|
|
100
|
+
*/
|
|
101
|
+
paramsStyles?: Record<string, 'primitive' | 'comma-delimited-array' | 'comma-delimited-object' | undefined> | undefined;
|
|
102
|
+
/**
|
|
103
|
+
* Controls how individual query parameters are encoding/decoding.
|
|
104
|
+
*
|
|
105
|
+
* **Note**: Query styles are merged when defined multiple times.
|
|
106
|
+
*
|
|
107
|
+
* Each key maps a query parameter name to one of the following strategies:
|
|
108
|
+
*
|
|
109
|
+
* | Strategy | Encoded | Decoded | OpenAPI Parameter Style |
|
|
110
|
+
* |--------------------------|---------------------------|--------------------------------|------------------------------------|
|
|
111
|
+
* | `primitive` | `?a=1&a=2` | `{ a: '2' }` | `form` / `explode: false` |
|
|
112
|
+
* | `array` | `?a=1&a=2` | `{ a: ['1', '2'] }` | `form` / `explode: true` |
|
|
113
|
+
* | `comma-delimited-array` | `?a=1,2,3` | `{ a: ['1', '2', '3'] }` | `form` / `explode: false` |
|
|
114
|
+
* | `comma-delimited-object` | `?a=A,1,B,2` | `{ a: { A: '1', B: '2' } }` | `form` / `explode: false` |
|
|
115
|
+
* | `space-delimited-array` | `?a=1 2 3` | `{ a: ['1', '2', '3'] }` | `spaceDelimited` / `explode: false`|
|
|
116
|
+
* | `space-delimited-object` | `?a=A 1 B 2` | `{ a: { A: '1', B: '2' } }` | `spaceDelimited` / `explode: false`|
|
|
117
|
+
* | `pipe-delimited-array` | `?a=1\|2\|3` | `{ a: ['1', '2', '3'] }` | `pipeDelimited` / `explode: false` |
|
|
118
|
+
* | `pipe-delimited-object` | `?a=A\|1\|B\|2` | `{ a: { A: '1', B: '2' } }` | `pipeDelimited` / `explode: false` |
|
|
119
|
+
* | `json` | `?meta={"key":"value"}` | `{ meta: { key: 'value' } }` | `content: application/json` |
|
|
120
|
+
* | _default_ | `?a[]=1&a[]=2&b=3&c[d]=4` | `{a:['1', '2'], b:3, c:{d:4}}` | `deepObject` / `explode: true` |
|
|
121
|
+
*
|
|
122
|
+
* **Strategy details:**
|
|
123
|
+
*
|
|
124
|
+
* - **`primitive`**: Takes the last occurrence of a repeated parameter.
|
|
125
|
+
* - **`array`**: Always produces an array, even for a single occurrence.
|
|
126
|
+
* - **`*-delimited-array`**: Splits the last value on the delimiter (`,`, space, or `|`) into an array.
|
|
127
|
+
* - **`*-delimited-object`**: Splits the last value on the delimiter into alternating key–value pairs.
|
|
128
|
+
* - **`json`**: Parses the last value as JSON; falls back to the raw string if parsing fails.
|
|
129
|
+
* - **`undefined`**: Standard bracket-notation decoding This is the default.
|
|
130
|
+
*
|
|
131
|
+
* **Note**: `*-delimited-*` strategies do not support keys or values containing the delimiter character.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* // GET /search?keyword=abc&tags=a,b,c&meta={"key":"value"}
|
|
136
|
+
* const queryParsing = {
|
|
137
|
+
* keyword: 'primitive',
|
|
138
|
+
* tags: 'comma-delimited-array',
|
|
139
|
+
* meta: 'json',
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* const inputSchema = z.object({
|
|
143
|
+
* keyword: z.string(),
|
|
144
|
+
* tags: z.array(z.string()),
|
|
145
|
+
* meta: z.object({ key: z.string() }),
|
|
146
|
+
* })
|
|
147
|
+
* ```
|
|
148
|
+
*
|
|
149
|
+
* @default `undefined` for all parameters (bracket-notation decoding)
|
|
150
|
+
*/
|
|
151
|
+
queryStyles?: Record<string, 'primitive' | 'array' | 'comma-delimited-array' | 'comma-delimited-object' | 'space-delimited-array' | 'space-delimited-object' | 'pipe-delimited-array' | 'pipe-delimited-object' | 'json' | undefined> | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Hint for how to parse the incoming request body.
|
|
154
|
+
*
|
|
155
|
+
* Note: The `standard-server` `Content-Type` header takes priority over this option.
|
|
156
|
+
* `form-data` and `url-search-params` are decoded using bracket notation,
|
|
157
|
+
* so the resulting value will be an object or array.
|
|
158
|
+
*
|
|
159
|
+
* @default Inferred from `Content-Type`, `Content-Disposition`, and `Content-Length`
|
|
160
|
+
*/
|
|
161
|
+
requestBodyHint?: StandardBodyHint | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* Hint for how to parse the response body.
|
|
164
|
+
*
|
|
165
|
+
* Note: The `standard-server` `Content-Type` header takes priority over this option.
|
|
166
|
+
* `form-data` and `url-search-params` are decoded using bracket notation,
|
|
167
|
+
* so the resulting value will be an object or array.
|
|
168
|
+
*
|
|
169
|
+
* @default Inferred from `Content-Type`, `Content-Disposition`, and `Content-Length`
|
|
170
|
+
*/
|
|
171
|
+
responseBodyHint?: StandardBodyHint | undefined;
|
|
172
|
+
/**
|
|
173
|
+
* Determines how the input should be structured
|
|
174
|
+
* based on params, query, headers, and body.
|
|
175
|
+
*
|
|
176
|
+
* - `compact` — Merges params with either query or body
|
|
177
|
+
* (depending on the HTTP method) into a single flat object.
|
|
178
|
+
* Use this when you don't need access to headers and your
|
|
179
|
+
* param/query/body keys don't conflict.
|
|
180
|
+
*
|
|
181
|
+
* ```ts
|
|
182
|
+
* // GET /users/42?search=hello
|
|
183
|
+
* const inputValue = { id: 42, search: 'hello' }
|
|
184
|
+
*
|
|
185
|
+
* const inputSchema = z.object({
|
|
186
|
+
* id: z.coerce.number(), // from params
|
|
187
|
+
* search: z.string(), // from query
|
|
188
|
+
* })
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* - `detailed` — Keeps each part of the request as a
|
|
192
|
+
* separate nested field. Use this when you need access
|
|
193
|
+
* to headers, or when params and query/body keys
|
|
194
|
+
* might conflict.
|
|
195
|
+
*
|
|
196
|
+
* ```ts
|
|
197
|
+
* const inputValue = {
|
|
198
|
+
* params: { id: 1 },
|
|
199
|
+
* query: { search: 'hello' },
|
|
200
|
+
* headers: { 'content-type': 'application/json' },
|
|
201
|
+
* body: 'body value',
|
|
202
|
+
* }
|
|
203
|
+
*
|
|
204
|
+
* const inputSchema = z.object({
|
|
205
|
+
* params: z.object({ id: z.coerce.number() }),
|
|
206
|
+
* query: z.object({ search: z.string() }),
|
|
207
|
+
* headers: z.object({ 'content-type': z.string() }),
|
|
208
|
+
* body: z.string(),
|
|
209
|
+
* })
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* @default 'compact'
|
|
213
|
+
*/
|
|
214
|
+
inputStructure?: 'compact' | 'detailed' | undefined;
|
|
215
|
+
/**
|
|
216
|
+
* Determines how the output should be structured
|
|
217
|
+
* into the HTTP response.
|
|
218
|
+
*
|
|
219
|
+
* - `compact` — The return value is sent directly as the
|
|
220
|
+
* response body. Status code comes from successStatus.
|
|
221
|
+
*
|
|
222
|
+
* ```ts
|
|
223
|
+
* const outputValue = { id: 1, name: 'Alice' }
|
|
224
|
+
*
|
|
225
|
+
* const outputSchema = z.object({
|
|
226
|
+
* id: z.number(),
|
|
227
|
+
* name: z.string(),
|
|
228
|
+
* })
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* - `detailed` — Return an object with optional properties:
|
|
232
|
+
* - status: HTTP status code (200–399). Defaults to
|
|
233
|
+
* successStatus if omitted. Use a literal type
|
|
234
|
+
* (e.g. z.literal(201)) so the generated spec can reflects
|
|
235
|
+
* the exact code.
|
|
236
|
+
* - headers: Custom headers to merge into the response
|
|
237
|
+
* (Record<string, string | string[] | undefined>).
|
|
238
|
+
* - body: The response body.
|
|
239
|
+
*
|
|
240
|
+
* ```ts
|
|
241
|
+
* const outputValue = {
|
|
242
|
+
* status: 201,
|
|
243
|
+
* headers: { 'x-custom-header': 'value' },
|
|
244
|
+
* body: 'body value',
|
|
245
|
+
* }
|
|
246
|
+
*
|
|
247
|
+
* const outputSchema = z.object({
|
|
248
|
+
* status: z.literal(201).meta({ description: 'Record Created' }),
|
|
249
|
+
* headers: z.object({ 'x-custom-header': z.string() }),
|
|
250
|
+
* body: z.string(),
|
|
251
|
+
* })
|
|
252
|
+
* ```
|
|
253
|
+
*
|
|
254
|
+
* @default 'compact'
|
|
255
|
+
*/
|
|
256
|
+
outputStructure?: 'compact' | 'detailed' | undefined;
|
|
257
|
+
/**
|
|
258
|
+
* Override or extend the generated OpenAPI operation object for this procedure.
|
|
259
|
+
*
|
|
260
|
+
* Pass a plain object to replace entire operation object, or a function that receives the current
|
|
261
|
+
* operation object and returns the modified version.
|
|
262
|
+
*
|
|
263
|
+
* **Note**: Spec is merged when defined multiple times.
|
|
264
|
+
*/
|
|
265
|
+
spec?: Value<OpenAPIOperationObject, [current: OpenAPIOperationObject]>;
|
|
266
|
+
/**
|
|
267
|
+
* Prefix for the path. Useful when you want to apply a common path prefix across multiple procedures.
|
|
268
|
+
*
|
|
269
|
+
* **Note**: Prefixes are merged when defined multiple times.
|
|
270
|
+
*/
|
|
271
|
+
prefix?: `/${string}` | undefined;
|
|
272
|
+
}
|
|
273
|
+
interface OpenAPIMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
274
|
+
name: '~openapi';
|
|
275
|
+
}
|
|
276
|
+
interface OpenAPIMethodMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
277
|
+
name: '~openapi/method';
|
|
278
|
+
}
|
|
279
|
+
interface OpenAPIPathMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
280
|
+
name: '~openapi/path';
|
|
281
|
+
}
|
|
282
|
+
interface OpenAPISpecMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
283
|
+
name: '~openapi/spec';
|
|
284
|
+
}
|
|
285
|
+
interface OpenAPIPrefixMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
286
|
+
name: '~openapi/prefix';
|
|
287
|
+
}
|
|
288
|
+
interface OpenAPIFunction {
|
|
289
|
+
(meta: OpenAPIMeta): OpenAPIMetaPlugin<any, any, any>;
|
|
290
|
+
method(method: OpenAPIMeta['method']): OpenAPIMethodMetaPlugin<any, any, any>;
|
|
291
|
+
path(method: OpenAPIMeta['path']): OpenAPIPathMetaPlugin<any, any, any>;
|
|
292
|
+
spec(method: OpenAPIMeta['spec']): OpenAPISpecMetaPlugin<any, any, any>;
|
|
293
|
+
prefix(method: OpenAPIMeta['prefix']): OpenAPIPrefixMetaPlugin<any, any, any>;
|
|
294
|
+
}
|
|
295
|
+
declare const openapi: OpenAPIFunction;
|
|
296
|
+
declare function getOpenAPIMeta(procedureOrLazy: AnyProcedureContract | Lazy<any>): OpenAPIMeta | undefined;
|
|
297
|
+
|
|
298
|
+
export { getOpenAPIMeta as g, openapi as o };
|
|
299
|
+
export type { OpenAPIMeta as O, OpenAPIFunction as a, OpenAPIMetaPlugin as b, OpenAPIMethodMetaPlugin as c, OpenAPIPathMetaPlugin as d, OpenAPIPrefixMetaPlugin as e, OpenAPISpecMetaPlugin as f };
|