@orpc/openapi 0.0.0-next.d7b5662 → 0.0.0-next.da8ae32
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-DRV7KYES.js +420 -0
- package/dist/chunk-HC5PVG4R.js +52 -0
- package/dist/chunk-NHYWV7BW.js +32 -0
- package/dist/fetch.js +5 -587
- package/dist/hono.js +9 -0
- package/dist/index.js +352 -112
- package/dist/next.js +9 -0
- package/dist/node.js +30 -0
- package/dist/src/adapters/fetch/index.d.ts +2 -0
- package/dist/src/adapters/fetch/openapi-handler.d.ts +11 -0
- package/dist/src/adapters/hono/index.d.ts +2 -0
- package/dist/src/adapters/next/index.d.ts +2 -0
- package/dist/src/adapters/node/index.d.ts +2 -0
- package/dist/src/adapters/node/openapi-handler.d.ts +11 -0
- package/dist/src/adapters/standard/index.d.ts +6 -0
- package/dist/src/adapters/standard/openapi-codec.d.ts +15 -0
- package/dist/src/adapters/standard/openapi-handler.d.ts +7 -0
- package/dist/src/adapters/standard/openapi-matcher.d.ts +20 -0
- package/dist/src/adapters/standard/openapi-serializer.d.ts +11 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/openapi-error.d.ts +3 -0
- package/dist/src/openapi-generator.d.ts +25 -9
- package/dist/src/openapi-input-structure-parser.d.ts +22 -0
- package/dist/src/openapi-operation-extender.d.ts +7 -0
- package/dist/src/openapi-output-structure-parser.d.ts +18 -0
- package/dist/src/openapi-parameters-builder.d.ts +3 -0
- package/dist/src/schema-converter.d.ts +2 -2
- package/dist/src/schema.d.ts +1 -1
- package/dist/src/utils.d.ts +1 -16
- package/dist/standard.js +14 -0
- package/package.json +27 -10
- package/dist/chunk-KNYXLM77.js +0 -107
- package/dist/src/fetch/index.d.ts +0 -10
- package/dist/src/fetch/input-builder-full.d.ts +0 -11
- package/dist/src/fetch/input-builder-simple.d.ts +0 -6
- package/dist/src/fetch/openapi-handler-server.d.ts +0 -7
- package/dist/src/fetch/openapi-handler-serverless.d.ts +0 -7
- package/dist/src/fetch/openapi-handler.d.ts +0 -30
- package/dist/src/fetch/openapi-payload-codec.d.ts +0 -15
- package/dist/src/fetch/openapi-procedure-matcher.d.ts +0 -19
- package/dist/src/fetch/schema-coercer.d.ts +0 -10
- /package/dist/src/{fetch → adapters/standard}/bracket-notation.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -1,9 +1,53 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JSONSerializer,
|
|
3
|
-
forEachAllContractProcedure,
|
|
4
|
-
forEachContractProcedure,
|
|
5
3
|
standardizeHTTPPath
|
|
6
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HC5PVG4R.js";
|
|
5
|
+
|
|
6
|
+
// src/openapi-operation-extender.ts
|
|
7
|
+
import { isProcedure } from "@orpc/server";
|
|
8
|
+
var OPERATION_EXTENDER_SYMBOL = Symbol("ORPC_OPERATION_EXTENDER");
|
|
9
|
+
function setOperationExtender(o, extend) {
|
|
10
|
+
return new Proxy(o, {
|
|
11
|
+
get(target, prop, receiver) {
|
|
12
|
+
if (prop === OPERATION_EXTENDER_SYMBOL) {
|
|
13
|
+
return extend;
|
|
14
|
+
}
|
|
15
|
+
return Reflect.get(target, prop, receiver);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function getOperationExtender(o) {
|
|
20
|
+
return o[OPERATION_EXTENDER_SYMBOL];
|
|
21
|
+
}
|
|
22
|
+
function extendOperation(operation, procedure) {
|
|
23
|
+
const operationExtenders = [];
|
|
24
|
+
for (const errorItem of Object.values(procedure["~orpc"].errorMap)) {
|
|
25
|
+
const maybeExtender = getOperationExtender(errorItem);
|
|
26
|
+
if (maybeExtender) {
|
|
27
|
+
operationExtenders.push(maybeExtender);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (isProcedure(procedure)) {
|
|
31
|
+
for (const middleware of procedure["~orpc"].middlewares) {
|
|
32
|
+
const maybeExtender = getOperationExtender(middleware);
|
|
33
|
+
if (maybeExtender) {
|
|
34
|
+
operationExtenders.push(maybeExtender);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
let currentOperation = operation;
|
|
39
|
+
for (const extender of operationExtenders) {
|
|
40
|
+
if (typeof extender === "function") {
|
|
41
|
+
currentOperation = extender(currentOperation, procedure);
|
|
42
|
+
} else {
|
|
43
|
+
currentOperation = {
|
|
44
|
+
...currentOperation,
|
|
45
|
+
...extender
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return currentOperation;
|
|
50
|
+
}
|
|
7
51
|
|
|
8
52
|
// src/openapi.ts
|
|
9
53
|
import { OpenApiBuilder } from "openapi3-ts/oas31";
|
|
@@ -35,15 +79,164 @@ var OpenAPIContentBuilder = class {
|
|
|
35
79
|
}
|
|
36
80
|
};
|
|
37
81
|
|
|
82
|
+
// src/openapi-generator.ts
|
|
83
|
+
import { fallbackContractConfig as fallbackContractConfig2, fallbackORPCErrorStatus } from "@orpc/contract";
|
|
84
|
+
import { eachAllContractProcedure } from "@orpc/server";
|
|
85
|
+
import { group } from "@orpc/shared";
|
|
86
|
+
|
|
87
|
+
// src/openapi-error.ts
|
|
88
|
+
var OpenAPIError = class extends Error {
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/openapi-input-structure-parser.ts
|
|
92
|
+
import { fallbackContractConfig } from "@orpc/contract";
|
|
93
|
+
var OpenAPIInputStructureParser = class {
|
|
94
|
+
constructor(schemaConverter, schemaUtils, pathParser) {
|
|
95
|
+
this.schemaConverter = schemaConverter;
|
|
96
|
+
this.schemaUtils = schemaUtils;
|
|
97
|
+
this.pathParser = pathParser;
|
|
98
|
+
}
|
|
99
|
+
parse(contract, structure) {
|
|
100
|
+
const inputSchema = this.schemaConverter.convert(contract["~orpc"].inputSchema, { strategy: "input" });
|
|
101
|
+
const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route?.method);
|
|
102
|
+
const httpPath = contract["~orpc"].route?.path;
|
|
103
|
+
if (this.schemaUtils.isAnySchema(inputSchema)) {
|
|
104
|
+
return {
|
|
105
|
+
paramsSchema: void 0,
|
|
106
|
+
querySchema: void 0,
|
|
107
|
+
headersSchema: void 0,
|
|
108
|
+
bodySchema: void 0
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (structure === "detailed") {
|
|
112
|
+
return this.parseDetailedSchema(inputSchema);
|
|
113
|
+
} else {
|
|
114
|
+
return this.parseCompactSchema(inputSchema, method, httpPath);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
parseDetailedSchema(inputSchema) {
|
|
118
|
+
if (!this.schemaUtils.isObjectSchema(inputSchema)) {
|
|
119
|
+
throw new OpenAPIError(`When input structure is 'detailed', input schema must be an object.`);
|
|
120
|
+
}
|
|
121
|
+
if (inputSchema.properties && Object.keys(inputSchema.properties).some((key) => !["params", "query", "headers", "body"].includes(key))) {
|
|
122
|
+
throw new OpenAPIError(`When input structure is 'detailed', input schema must be only can contain 'params', 'query', 'headers' and 'body' properties.`);
|
|
123
|
+
}
|
|
124
|
+
let paramsSchema = inputSchema.properties?.params;
|
|
125
|
+
let querySchema = inputSchema.properties?.query;
|
|
126
|
+
let headersSchema = inputSchema.properties?.headers;
|
|
127
|
+
const bodySchema = inputSchema.properties?.body;
|
|
128
|
+
if (paramsSchema !== void 0 && this.schemaUtils.isAnySchema(paramsSchema)) {
|
|
129
|
+
paramsSchema = void 0;
|
|
130
|
+
}
|
|
131
|
+
if (paramsSchema !== void 0 && !this.schemaUtils.isObjectSchema(paramsSchema)) {
|
|
132
|
+
throw new OpenAPIError(`When input structure is 'detailed', params schema in input schema must be an object.`);
|
|
133
|
+
}
|
|
134
|
+
if (querySchema !== void 0 && this.schemaUtils.isAnySchema(querySchema)) {
|
|
135
|
+
querySchema = void 0;
|
|
136
|
+
}
|
|
137
|
+
if (querySchema !== void 0 && !this.schemaUtils.isObjectSchema(querySchema)) {
|
|
138
|
+
throw new OpenAPIError(`When input structure is 'detailed', query schema in input schema must be an object.`);
|
|
139
|
+
}
|
|
140
|
+
if (headersSchema !== void 0 && this.schemaUtils.isAnySchema(headersSchema)) {
|
|
141
|
+
headersSchema = void 0;
|
|
142
|
+
}
|
|
143
|
+
if (headersSchema !== void 0 && !this.schemaUtils.isObjectSchema(headersSchema)) {
|
|
144
|
+
throw new OpenAPIError(`When input structure is 'detailed', headers schema in input schema must be an object.`);
|
|
145
|
+
}
|
|
146
|
+
return { paramsSchema, querySchema, headersSchema, bodySchema };
|
|
147
|
+
}
|
|
148
|
+
parseCompactSchema(inputSchema, method, httpPath) {
|
|
149
|
+
const dynamic = httpPath ? this.pathParser.parseDynamicParams(httpPath) : [];
|
|
150
|
+
if (dynamic.length === 0) {
|
|
151
|
+
if (method === "GET") {
|
|
152
|
+
let querySchema = inputSchema;
|
|
153
|
+
if (querySchema !== void 0 && this.schemaUtils.isAnySchema(querySchema)) {
|
|
154
|
+
querySchema = void 0;
|
|
155
|
+
}
|
|
156
|
+
if (querySchema !== void 0 && !this.schemaUtils.isObjectSchema(querySchema)) {
|
|
157
|
+
throw new OpenAPIError(`When input structure is 'compact' and method is 'GET', input schema must be an object.`);
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
paramsSchema: void 0,
|
|
161
|
+
querySchema,
|
|
162
|
+
headersSchema: void 0,
|
|
163
|
+
bodySchema: void 0
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
paramsSchema: void 0,
|
|
168
|
+
querySchema: void 0,
|
|
169
|
+
headersSchema: void 0,
|
|
170
|
+
bodySchema: inputSchema
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
if (!this.schemaUtils.isObjectSchema(inputSchema)) {
|
|
174
|
+
throw new OpenAPIError(`When input structure is 'compact' and path has dynamic parameters, input schema must be an object.`);
|
|
175
|
+
}
|
|
176
|
+
const [params, rest] = this.schemaUtils.separateObjectSchema(inputSchema, dynamic.map((v) => v.name));
|
|
177
|
+
return {
|
|
178
|
+
paramsSchema: params,
|
|
179
|
+
querySchema: method === "GET" ? rest : void 0,
|
|
180
|
+
headersSchema: void 0,
|
|
181
|
+
bodySchema: method !== "GET" ? rest : void 0
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// src/openapi-output-structure-parser.ts
|
|
187
|
+
var OpenAPIOutputStructureParser = class {
|
|
188
|
+
constructor(schemaConverter, schemaUtils) {
|
|
189
|
+
this.schemaConverter = schemaConverter;
|
|
190
|
+
this.schemaUtils = schemaUtils;
|
|
191
|
+
}
|
|
192
|
+
parse(contract, structure) {
|
|
193
|
+
const outputSchema = this.schemaConverter.convert(contract["~orpc"].outputSchema, { strategy: "output" });
|
|
194
|
+
if (this.schemaUtils.isAnySchema(outputSchema)) {
|
|
195
|
+
return {
|
|
196
|
+
headersSchema: void 0,
|
|
197
|
+
bodySchema: void 0
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (structure === "detailed") {
|
|
201
|
+
return this.parseDetailedSchema(outputSchema);
|
|
202
|
+
} else {
|
|
203
|
+
return this.parseCompactSchema(outputSchema);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
parseDetailedSchema(outputSchema) {
|
|
207
|
+
if (!this.schemaUtils.isObjectSchema(outputSchema)) {
|
|
208
|
+
throw new OpenAPIError(`When output structure is 'detailed', output schema must be an object.`);
|
|
209
|
+
}
|
|
210
|
+
if (outputSchema.properties && Object.keys(outputSchema.properties).some((key) => !["headers", "body"].includes(key))) {
|
|
211
|
+
throw new OpenAPIError(`When output structure is 'detailed', output schema must be only can contain 'headers' and 'body' properties.`);
|
|
212
|
+
}
|
|
213
|
+
let headersSchema = outputSchema.properties?.headers;
|
|
214
|
+
const bodySchema = outputSchema.properties?.body;
|
|
215
|
+
if (headersSchema !== void 0 && this.schemaUtils.isAnySchema(headersSchema)) {
|
|
216
|
+
headersSchema = void 0;
|
|
217
|
+
}
|
|
218
|
+
if (headersSchema !== void 0 && !this.schemaUtils.isObjectSchema(headersSchema)) {
|
|
219
|
+
throw new OpenAPIError(`When output structure is 'detailed', headers schema in output schema must be an object.`);
|
|
220
|
+
}
|
|
221
|
+
return { headersSchema, bodySchema };
|
|
222
|
+
}
|
|
223
|
+
parseCompactSchema(outputSchema) {
|
|
224
|
+
return {
|
|
225
|
+
headersSchema: void 0,
|
|
226
|
+
bodySchema: outputSchema
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
38
231
|
// src/openapi-parameters-builder.ts
|
|
39
|
-
import { get,
|
|
232
|
+
import { get, isObject, omit } from "@orpc/shared";
|
|
40
233
|
var OpenAPIParametersBuilder = class {
|
|
41
234
|
build(paramIn, jsonSchema, options) {
|
|
42
235
|
const parameters = [];
|
|
43
236
|
for (const name in jsonSchema.properties) {
|
|
44
237
|
const schema = jsonSchema.properties[name];
|
|
45
238
|
const paramExamples = jsonSchema.examples?.filter((example) => {
|
|
46
|
-
return
|
|
239
|
+
return isObject(example) && name in example;
|
|
47
240
|
}).map((example) => {
|
|
48
241
|
return example[name];
|
|
49
242
|
});
|
|
@@ -63,6 +256,14 @@ var OpenAPIParametersBuilder = class {
|
|
|
63
256
|
}
|
|
64
257
|
return parameters;
|
|
65
258
|
}
|
|
259
|
+
buildHeadersObject(jsonSchema, options) {
|
|
260
|
+
const parameters = this.build("header", jsonSchema, options);
|
|
261
|
+
const headersObject = {};
|
|
262
|
+
for (const param of parameters) {
|
|
263
|
+
headersObject[param.name] = omit(param, ["name", "in"]);
|
|
264
|
+
}
|
|
265
|
+
return headersObject;
|
|
266
|
+
}
|
|
66
267
|
};
|
|
67
268
|
|
|
68
269
|
// src/openapi-path-parser.ts
|
|
@@ -96,7 +297,7 @@ var CompositeSchemaConverter = class {
|
|
|
96
297
|
};
|
|
97
298
|
|
|
98
299
|
// src/schema-utils.ts
|
|
99
|
-
import {
|
|
300
|
+
import { isObject as isObject2 } from "@orpc/shared";
|
|
100
301
|
|
|
101
302
|
// src/schema.ts
|
|
102
303
|
import * as JSONSchema from "json-schema-typed/draft-2020-12";
|
|
@@ -138,14 +339,14 @@ var SchemaUtils = class {
|
|
|
138
339
|
return typeof schema === "object" && schema.type === "object";
|
|
139
340
|
}
|
|
140
341
|
isAnySchema(schema) {
|
|
141
|
-
return schema === true || Object.keys(schema).length === 0;
|
|
342
|
+
return schema === true || Object.keys(schema).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
|
|
142
343
|
}
|
|
143
344
|
isUndefinableSchema(schema) {
|
|
144
345
|
const [matches] = this.filterSchemaBranches(schema, (schema2) => {
|
|
145
346
|
if (typeof schema2 === "boolean") {
|
|
146
347
|
return schema2;
|
|
147
348
|
}
|
|
148
|
-
return Object.keys(schema2).length === 0;
|
|
349
|
+
return Object.keys(schema2).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
|
|
149
350
|
});
|
|
150
351
|
return matches.length > 0;
|
|
151
352
|
}
|
|
@@ -158,7 +359,7 @@ var SchemaUtils = class {
|
|
|
158
359
|
}, {});
|
|
159
360
|
matched.required = schema.required?.filter((key) => separatedProperties.includes(key));
|
|
160
361
|
matched.examples = schema.examples?.map((example) => {
|
|
161
|
-
if (!
|
|
362
|
+
if (!isObject2(example)) {
|
|
162
363
|
return example;
|
|
163
364
|
}
|
|
164
365
|
return Object.entries(example).reduce((acc, [key, value]) => {
|
|
@@ -174,7 +375,7 @@ var SchemaUtils = class {
|
|
|
174
375
|
}, {});
|
|
175
376
|
rest.required = schema.required?.filter((key) => !separatedProperties.includes(key));
|
|
176
377
|
rest.examples = schema.examples?.map((example) => {
|
|
177
|
-
if (!
|
|
378
|
+
if (!isObject2(example)) {
|
|
178
379
|
return example;
|
|
179
380
|
}
|
|
180
381
|
return Object.entries(example).reduce((acc, [key, value]) => {
|
|
@@ -218,130 +419,167 @@ var SchemaUtils = class {
|
|
|
218
419
|
|
|
219
420
|
// src/openapi-generator.ts
|
|
220
421
|
var OpenAPIGenerator = class {
|
|
422
|
+
contentBuilder;
|
|
423
|
+
parametersBuilder;
|
|
424
|
+
schemaConverter;
|
|
425
|
+
schemaUtils;
|
|
426
|
+
jsonSerializer;
|
|
427
|
+
pathParser;
|
|
428
|
+
inputStructureParser;
|
|
429
|
+
outputStructureParser;
|
|
430
|
+
errorHandlerStrategy;
|
|
431
|
+
ignoreUndefinedPathProcedures;
|
|
432
|
+
considerMissingTagDefinitionAsError;
|
|
433
|
+
strictErrorResponses;
|
|
221
434
|
constructor(options) {
|
|
222
|
-
this.options = options;
|
|
223
435
|
this.parametersBuilder = options?.parametersBuilder ?? new OpenAPIParametersBuilder();
|
|
224
436
|
this.schemaConverter = new CompositeSchemaConverter(options?.schemaConverters ?? []);
|
|
225
437
|
this.schemaUtils = options?.schemaUtils ?? new SchemaUtils();
|
|
226
438
|
this.jsonSerializer = options?.jsonSerializer ?? new JSONSerializer();
|
|
227
439
|
this.contentBuilder = options?.contentBuilder ?? new OpenAPIContentBuilder(this.schemaUtils);
|
|
228
440
|
this.pathParser = new OpenAPIPathParser();
|
|
441
|
+
this.inputStructureParser = options?.inputStructureParser ?? new OpenAPIInputStructureParser(this.schemaConverter, this.schemaUtils, this.pathParser);
|
|
442
|
+
this.outputStructureParser = options?.outputStructureParser ?? new OpenAPIOutputStructureParser(this.schemaConverter, this.schemaUtils);
|
|
443
|
+
this.errorHandlerStrategy = options?.errorHandlerStrategy ?? "throw";
|
|
444
|
+
this.ignoreUndefinedPathProcedures = options?.ignoreUndefinedPathProcedures ?? false;
|
|
445
|
+
this.considerMissingTagDefinitionAsError = options?.considerMissingTagDefinitionAsError ?? false;
|
|
446
|
+
this.strictErrorResponses = options?.strictErrorResponses ?? true;
|
|
229
447
|
}
|
|
230
|
-
contentBuilder;
|
|
231
|
-
parametersBuilder;
|
|
232
|
-
schemaConverter;
|
|
233
|
-
schemaUtils;
|
|
234
|
-
jsonSerializer;
|
|
235
|
-
pathParser;
|
|
236
448
|
async generate(router, doc) {
|
|
237
449
|
const builder = new OpenApiBuilder({
|
|
238
450
|
...doc,
|
|
239
451
|
openapi: "3.1.1"
|
|
240
452
|
});
|
|
241
453
|
const rootTags = doc.tags?.map((tag) => tag.name) ?? [];
|
|
242
|
-
await
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const outputSchema = this.schemaConverter.convert(def.OutputSchema, { strategy: "output" });
|
|
251
|
-
const params = (() => {
|
|
252
|
-
const dynamic = this.pathParser.parseDynamicParams(httpPath);
|
|
253
|
-
if (!dynamic.length) {
|
|
254
|
-
return void 0;
|
|
255
|
-
}
|
|
256
|
-
if (this.schemaUtils.isAnySchema(inputSchema)) {
|
|
257
|
-
return void 0;
|
|
258
|
-
}
|
|
259
|
-
if (!this.schemaUtils.isObjectSchema(inputSchema)) {
|
|
260
|
-
this.handleError(
|
|
261
|
-
new Error(
|
|
262
|
-
`When path has parameters, input schema must be an object [${path.join(".")}]`
|
|
263
|
-
)
|
|
264
|
-
);
|
|
265
|
-
return void 0;
|
|
454
|
+
await eachAllContractProcedure({
|
|
455
|
+
path: [],
|
|
456
|
+
router
|
|
457
|
+
}, ({ contract, path }) => {
|
|
458
|
+
try {
|
|
459
|
+
const def = contract["~orpc"];
|
|
460
|
+
if (this.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
|
|
461
|
+
return;
|
|
266
462
|
}
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
463
|
+
const method = fallbackContractConfig2("defaultMethod", def.route?.method);
|
|
464
|
+
const httpPath = def.route?.path ? standardizeHTTPPath(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
|
|
465
|
+
const inputStructure = fallbackContractConfig2("defaultInputStructure", def.route?.inputStructure);
|
|
466
|
+
const outputStructure = fallbackContractConfig2("defaultOutputStructure", def.route?.outputStructure);
|
|
467
|
+
const { paramsSchema, querySchema, headersSchema, bodySchema } = this.inputStructureParser.parse(contract, inputStructure);
|
|
468
|
+
const { headersSchema: resHeadersSchema, bodySchema: resBodySchema } = this.outputStructureParser.parse(contract, outputStructure);
|
|
469
|
+
const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
|
|
271
470
|
required: true
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
471
|
+
}) : [];
|
|
472
|
+
const query = querySchema ? this.parametersBuilder.build("query", querySchema) : [];
|
|
473
|
+
const headers = headersSchema ? this.parametersBuilder.build("header", headersSchema) : [];
|
|
474
|
+
const parameters = [...params, ...query, ...headers];
|
|
475
|
+
const requestBody = bodySchema !== void 0 ? {
|
|
476
|
+
required: this.schemaUtils.isUndefinableSchema(bodySchema),
|
|
477
|
+
content: this.contentBuilder.build(bodySchema)
|
|
478
|
+
} : void 0;
|
|
479
|
+
const responses = {};
|
|
480
|
+
responses[fallbackContractConfig2("defaultSuccessStatus", def.route?.successStatus)] = {
|
|
481
|
+
description: fallbackContractConfig2("defaultSuccessDescription", def.route?.successDescription),
|
|
482
|
+
content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema) : void 0,
|
|
483
|
+
headers: resHeadersSchema !== void 0 ? this.parametersBuilder.buildHeadersObject(resHeadersSchema) : void 0
|
|
484
|
+
};
|
|
485
|
+
const errors = group(Object.entries(def.errorMap ?? {}).filter(([_, config]) => config).map(([code, config]) => ({
|
|
486
|
+
...config,
|
|
487
|
+
code,
|
|
488
|
+
status: fallbackORPCErrorStatus(code, config?.status)
|
|
489
|
+
})), (error) => error.status);
|
|
490
|
+
for (const status in errors) {
|
|
491
|
+
const configs = errors[status];
|
|
492
|
+
if (!configs || configs.length === 0) {
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
const schemas = configs.map(({ data, code, message }) => {
|
|
496
|
+
const json = {
|
|
497
|
+
type: "object",
|
|
498
|
+
properties: {
|
|
499
|
+
defined: { const: true },
|
|
500
|
+
code: { const: code },
|
|
501
|
+
status: { const: Number(status) },
|
|
502
|
+
message: { type: "string", default: message },
|
|
503
|
+
data: {}
|
|
504
|
+
},
|
|
505
|
+
required: ["defined", "code", "status", "message"]
|
|
506
|
+
};
|
|
507
|
+
if (data) {
|
|
508
|
+
const dataJson = this.schemaConverter.convert(data, { strategy: "output" });
|
|
509
|
+
json.properties.data = dataJson;
|
|
510
|
+
if (!this.schemaUtils.isUndefinableSchema(dataJson)) {
|
|
511
|
+
json.required.push("data");
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
return json;
|
|
515
|
+
});
|
|
516
|
+
if (this.strictErrorResponses) {
|
|
517
|
+
schemas.push({
|
|
518
|
+
type: "object",
|
|
519
|
+
properties: {
|
|
520
|
+
defined: { const: false },
|
|
521
|
+
code: { type: "string" },
|
|
522
|
+
status: { type: "number" },
|
|
523
|
+
message: { type: "string" },
|
|
524
|
+
data: {}
|
|
525
|
+
},
|
|
526
|
+
required: ["defined", "code", "status", "message"]
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
const contentSchema = schemas.length === 1 ? schemas[0] : {
|
|
530
|
+
oneOf: schemas
|
|
531
|
+
};
|
|
532
|
+
responses[status] = {
|
|
533
|
+
description: status,
|
|
534
|
+
content: this.contentBuilder.build(contentSchema)
|
|
535
|
+
};
|
|
288
536
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return void 0;
|
|
537
|
+
if (this.considerMissingTagDefinitionAsError && def.route?.tags) {
|
|
538
|
+
const missingTag = def.route?.tags.find((tag) => !rootTags.includes(tag));
|
|
539
|
+
if (missingTag !== void 0) {
|
|
540
|
+
throw new OpenAPIError(
|
|
541
|
+
`Tag "${missingTag}" is missing definition. Please define it in OpenAPI root tags object`
|
|
542
|
+
);
|
|
543
|
+
}
|
|
297
544
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
545
|
+
const operation = {
|
|
546
|
+
summary: def.route?.summary,
|
|
547
|
+
description: def.route?.description,
|
|
548
|
+
deprecated: def.route?.deprecated,
|
|
549
|
+
tags: def.route?.tags ? [...def.route.tags] : void 0,
|
|
550
|
+
operationId: path.join("."),
|
|
551
|
+
parameters: parameters.length ? parameters : void 0,
|
|
552
|
+
requestBody,
|
|
553
|
+
responses
|
|
303
554
|
};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
this.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
555
|
+
const extendedOperation = extendOperation(operation, contract);
|
|
556
|
+
builder.addPath(httpPath, {
|
|
557
|
+
[method.toLocaleLowerCase()]: extendedOperation
|
|
558
|
+
});
|
|
559
|
+
} catch (e) {
|
|
560
|
+
if (e instanceof OpenAPIError) {
|
|
561
|
+
const error = new OpenAPIError(`
|
|
562
|
+
Generate OpenAPI Error: ${e.message}
|
|
563
|
+
Happened at path: ${path.join(".")}
|
|
564
|
+
`, { cause: e });
|
|
565
|
+
if (this.errorHandlerStrategy === "throw") {
|
|
566
|
+
throw error;
|
|
567
|
+
}
|
|
568
|
+
if (this.errorHandlerStrategy === "log") {
|
|
569
|
+
console.error(error);
|
|
570
|
+
}
|
|
571
|
+
} else {
|
|
572
|
+
throw e;
|
|
319
573
|
}
|
|
320
574
|
}
|
|
321
|
-
const operation = {
|
|
322
|
-
summary: def.route?.summary,
|
|
323
|
-
description: def.route?.description,
|
|
324
|
-
deprecated: def.route?.deprecated,
|
|
325
|
-
tags: def.route?.tags ? [...def.route.tags] : void 0,
|
|
326
|
-
operationId: path.join("."),
|
|
327
|
-
parameters: parameters.length ? parameters : void 0,
|
|
328
|
-
requestBody,
|
|
329
|
-
responses: {
|
|
330
|
-
200: successResponse
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
builder.addPath(httpPath, {
|
|
334
|
-
[method.toLocaleLowerCase()]: operation
|
|
335
|
-
});
|
|
336
575
|
});
|
|
337
576
|
return this.jsonSerializer.serialize(builder.getSpec());
|
|
338
577
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
// src/index.ts
|
|
581
|
+
var oo = {
|
|
582
|
+
spec: setOperationExtender
|
|
345
583
|
};
|
|
346
584
|
export {
|
|
347
585
|
CompositeSchemaConverter,
|
|
@@ -355,8 +593,10 @@ export {
|
|
|
355
593
|
OpenAPIPathParser,
|
|
356
594
|
OpenApiBuilder,
|
|
357
595
|
SchemaUtils,
|
|
358
|
-
|
|
359
|
-
|
|
596
|
+
extendOperation,
|
|
597
|
+
getOperationExtender,
|
|
598
|
+
oo,
|
|
599
|
+
setOperationExtender,
|
|
360
600
|
standardizeHTTPPath
|
|
361
601
|
};
|
|
362
602
|
//# sourceMappingURL=index.js.map
|
package/dist/next.js
ADDED
package/dist/node.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenAPICodec,
|
|
3
|
+
OpenAPIMatcher
|
|
4
|
+
} from "./chunk-DRV7KYES.js";
|
|
5
|
+
import "./chunk-HC5PVG4R.js";
|
|
6
|
+
|
|
7
|
+
// src/adapters/node/openapi-handler.ts
|
|
8
|
+
import { nodeHttpResponseSendStandardResponse, nodeHttpToStandardRequest } from "@orpc/server/node";
|
|
9
|
+
import { StandardHandler } from "@orpc/server/standard";
|
|
10
|
+
var OpenAPIHandler = class {
|
|
11
|
+
standardHandler;
|
|
12
|
+
constructor(router, options) {
|
|
13
|
+
const matcher = options?.matcher ?? new OpenAPIMatcher(options);
|
|
14
|
+
const codec = options?.codec ?? new OpenAPICodec(options);
|
|
15
|
+
this.standardHandler = new StandardHandler(router, matcher, codec, { ...options });
|
|
16
|
+
}
|
|
17
|
+
async handle(req, res, ...rest) {
|
|
18
|
+
const standardRequest = nodeHttpToStandardRequest(req, res);
|
|
19
|
+
const result = await this.standardHandler.handle(standardRequest, ...rest);
|
|
20
|
+
if (!result.matched) {
|
|
21
|
+
return { matched: false };
|
|
22
|
+
}
|
|
23
|
+
await nodeHttpResponseSendStandardResponse(res, result.response);
|
|
24
|
+
return { matched: true };
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
OpenAPIHandler
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context, Router } from '@orpc/server';
|
|
2
|
+
import type { FetchHandler, FetchHandleResult } from '@orpc/server/fetch';
|
|
3
|
+
import type { StandardHandleOptions } from '@orpc/server/standard';
|
|
4
|
+
import type { MaybeOptionalOptions } from '@orpc/shared';
|
|
5
|
+
import type { OpenAPIHandlerOptions } from '../standard';
|
|
6
|
+
export declare class OpenAPIHandler<T extends Context> implements FetchHandler<T> {
|
|
7
|
+
private readonly standardHandler;
|
|
8
|
+
constructor(router: Router<T, any>, options?: NoInfer<OpenAPIHandlerOptions<T>>);
|
|
9
|
+
handle(request: Request, ...rest: MaybeOptionalOptions<StandardHandleOptions<T>>): Promise<FetchHandleResult>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=openapi-handler.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Context, Router } from '@orpc/server';
|
|
2
|
+
import type { NodeHttpHandler, NodeHttpHandleResult, NodeHttpRequest, NodeHttpResponse } from '@orpc/server/node';
|
|
3
|
+
import type { StandardHandleOptions } from '@orpc/server/standard';
|
|
4
|
+
import type { MaybeOptionalOptions } from '@orpc/shared';
|
|
5
|
+
import type { OpenAPIHandlerOptions } from '../standard';
|
|
6
|
+
export declare class OpenAPIHandler<T extends Context> implements NodeHttpHandler<T> {
|
|
7
|
+
private readonly standardHandler;
|
|
8
|
+
constructor(router: Router<T, any>, options?: NoInfer<OpenAPIHandlerOptions<T>>);
|
|
9
|
+
handle(req: NodeHttpRequest, res: NodeHttpResponse, ...rest: MaybeOptionalOptions<StandardHandleOptions<T>>): Promise<NodeHttpHandleResult>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=openapi-handler.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AnyProcedure } from '@orpc/server';
|
|
2
|
+
import type { StandardCodec, StandardParams, StandardRequest, StandardResponse } from '@orpc/server/standard';
|
|
3
|
+
import { type ORPCError } from '@orpc/contract';
|
|
4
|
+
import { OpenAPISerializer } from './openapi-serializer';
|
|
5
|
+
export interface OpenAPICodecOptions {
|
|
6
|
+
serializer?: OpenAPISerializer;
|
|
7
|
+
}
|
|
8
|
+
export declare class OpenAPICodec implements StandardCodec {
|
|
9
|
+
private readonly serializer;
|
|
10
|
+
constructor(options?: OpenAPICodecOptions);
|
|
11
|
+
decode(request: StandardRequest, params: StandardParams | undefined, procedure: AnyProcedure): Promise<unknown>;
|
|
12
|
+
encode(output: unknown, procedure: AnyProcedure): StandardResponse;
|
|
13
|
+
encodeError(error: ORPCError<any, any>): StandardResponse;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=openapi-codec.d.ts.map
|