@orpc/openapi 0.0.0-next.011bc88 → 0.0.0-next.0361c32
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-HC5PVG4R.js +52 -0
- package/dist/chunk-ICLAXOVR.js +32 -0
- package/dist/chunk-PWOV66X6.js +421 -0
- package/dist/fetch.js +5 -590
- package/dist/hono.js +9 -0
- package/dist/index.js +296 -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 +10 -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 +10 -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/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-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,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
JSONSerializer,
|
|
3
|
-
forEachAllContractProcedure,
|
|
4
|
-
forEachContractProcedure,
|
|
5
3
|
standardizeHTTPPath
|
|
6
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HC5PVG4R.js";
|
|
7
5
|
|
|
8
6
|
// src/openapi.ts
|
|
9
7
|
import { OpenApiBuilder } from "openapi3-ts/oas31";
|
|
@@ -35,15 +33,164 @@ var OpenAPIContentBuilder = class {
|
|
|
35
33
|
}
|
|
36
34
|
};
|
|
37
35
|
|
|
36
|
+
// src/openapi-generator.ts
|
|
37
|
+
import { fallbackContractConfig as fallbackContractConfig2, fallbackORPCErrorStatus } from "@orpc/contract";
|
|
38
|
+
import { eachAllContractProcedure } from "@orpc/server";
|
|
39
|
+
import { group } from "@orpc/shared";
|
|
40
|
+
|
|
41
|
+
// src/openapi-error.ts
|
|
42
|
+
var OpenAPIError = class extends Error {
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/openapi-input-structure-parser.ts
|
|
46
|
+
import { fallbackContractConfig } from "@orpc/contract";
|
|
47
|
+
var OpenAPIInputStructureParser = class {
|
|
48
|
+
constructor(schemaConverter, schemaUtils, pathParser) {
|
|
49
|
+
this.schemaConverter = schemaConverter;
|
|
50
|
+
this.schemaUtils = schemaUtils;
|
|
51
|
+
this.pathParser = pathParser;
|
|
52
|
+
}
|
|
53
|
+
parse(contract, structure) {
|
|
54
|
+
const inputSchema = this.schemaConverter.convert(contract["~orpc"].inputSchema, { strategy: "input" });
|
|
55
|
+
const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route?.method);
|
|
56
|
+
const httpPath = contract["~orpc"].route?.path;
|
|
57
|
+
if (this.schemaUtils.isAnySchema(inputSchema)) {
|
|
58
|
+
return {
|
|
59
|
+
paramsSchema: void 0,
|
|
60
|
+
querySchema: void 0,
|
|
61
|
+
headersSchema: void 0,
|
|
62
|
+
bodySchema: void 0
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (structure === "detailed") {
|
|
66
|
+
return this.parseDetailedSchema(inputSchema);
|
|
67
|
+
} else {
|
|
68
|
+
return this.parseCompactSchema(inputSchema, method, httpPath);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
parseDetailedSchema(inputSchema) {
|
|
72
|
+
if (!this.schemaUtils.isObjectSchema(inputSchema)) {
|
|
73
|
+
throw new OpenAPIError(`When input structure is 'detailed', input schema must be an object.`);
|
|
74
|
+
}
|
|
75
|
+
if (inputSchema.properties && Object.keys(inputSchema.properties).some((key) => !["params", "query", "headers", "body"].includes(key))) {
|
|
76
|
+
throw new OpenAPIError(`When input structure is 'detailed', input schema must be only can contain 'params', 'query', 'headers' and 'body' properties.`);
|
|
77
|
+
}
|
|
78
|
+
let paramsSchema = inputSchema.properties?.params;
|
|
79
|
+
let querySchema = inputSchema.properties?.query;
|
|
80
|
+
let headersSchema = inputSchema.properties?.headers;
|
|
81
|
+
const bodySchema = inputSchema.properties?.body;
|
|
82
|
+
if (paramsSchema !== void 0 && this.schemaUtils.isAnySchema(paramsSchema)) {
|
|
83
|
+
paramsSchema = void 0;
|
|
84
|
+
}
|
|
85
|
+
if (paramsSchema !== void 0 && !this.schemaUtils.isObjectSchema(paramsSchema)) {
|
|
86
|
+
throw new OpenAPIError(`When input structure is 'detailed', params schema in input schema must be an object.`);
|
|
87
|
+
}
|
|
88
|
+
if (querySchema !== void 0 && this.schemaUtils.isAnySchema(querySchema)) {
|
|
89
|
+
querySchema = void 0;
|
|
90
|
+
}
|
|
91
|
+
if (querySchema !== void 0 && !this.schemaUtils.isObjectSchema(querySchema)) {
|
|
92
|
+
throw new OpenAPIError(`When input structure is 'detailed', query schema in input schema must be an object.`);
|
|
93
|
+
}
|
|
94
|
+
if (headersSchema !== void 0 && this.schemaUtils.isAnySchema(headersSchema)) {
|
|
95
|
+
headersSchema = void 0;
|
|
96
|
+
}
|
|
97
|
+
if (headersSchema !== void 0 && !this.schemaUtils.isObjectSchema(headersSchema)) {
|
|
98
|
+
throw new OpenAPIError(`When input structure is 'detailed', headers schema in input schema must be an object.`);
|
|
99
|
+
}
|
|
100
|
+
return { paramsSchema, querySchema, headersSchema, bodySchema };
|
|
101
|
+
}
|
|
102
|
+
parseCompactSchema(inputSchema, method, httpPath) {
|
|
103
|
+
const dynamic = httpPath ? this.pathParser.parseDynamicParams(httpPath) : [];
|
|
104
|
+
if (dynamic.length === 0) {
|
|
105
|
+
if (method === "GET") {
|
|
106
|
+
let querySchema = inputSchema;
|
|
107
|
+
if (querySchema !== void 0 && this.schemaUtils.isAnySchema(querySchema)) {
|
|
108
|
+
querySchema = void 0;
|
|
109
|
+
}
|
|
110
|
+
if (querySchema !== void 0 && !this.schemaUtils.isObjectSchema(querySchema)) {
|
|
111
|
+
throw new OpenAPIError(`When input structure is 'compact' and method is 'GET', input schema must be an object.`);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
paramsSchema: void 0,
|
|
115
|
+
querySchema,
|
|
116
|
+
headersSchema: void 0,
|
|
117
|
+
bodySchema: void 0
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
paramsSchema: void 0,
|
|
122
|
+
querySchema: void 0,
|
|
123
|
+
headersSchema: void 0,
|
|
124
|
+
bodySchema: inputSchema
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (!this.schemaUtils.isObjectSchema(inputSchema)) {
|
|
128
|
+
throw new OpenAPIError(`When input structure is 'compact' and path has dynamic parameters, input schema must be an object.`);
|
|
129
|
+
}
|
|
130
|
+
const [params, rest] = this.schemaUtils.separateObjectSchema(inputSchema, dynamic.map((v) => v.name));
|
|
131
|
+
return {
|
|
132
|
+
paramsSchema: params,
|
|
133
|
+
querySchema: method === "GET" ? rest : void 0,
|
|
134
|
+
headersSchema: void 0,
|
|
135
|
+
bodySchema: method !== "GET" ? rest : void 0
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// src/openapi-output-structure-parser.ts
|
|
141
|
+
var OpenAPIOutputStructureParser = class {
|
|
142
|
+
constructor(schemaConverter, schemaUtils) {
|
|
143
|
+
this.schemaConverter = schemaConverter;
|
|
144
|
+
this.schemaUtils = schemaUtils;
|
|
145
|
+
}
|
|
146
|
+
parse(contract, structure) {
|
|
147
|
+
const outputSchema = this.schemaConverter.convert(contract["~orpc"].outputSchema, { strategy: "output" });
|
|
148
|
+
if (this.schemaUtils.isAnySchema(outputSchema)) {
|
|
149
|
+
return {
|
|
150
|
+
headersSchema: void 0,
|
|
151
|
+
bodySchema: void 0
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
if (structure === "detailed") {
|
|
155
|
+
return this.parseDetailedSchema(outputSchema);
|
|
156
|
+
} else {
|
|
157
|
+
return this.parseCompactSchema(outputSchema);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
parseDetailedSchema(outputSchema) {
|
|
161
|
+
if (!this.schemaUtils.isObjectSchema(outputSchema)) {
|
|
162
|
+
throw new OpenAPIError(`When output structure is 'detailed', output schema must be an object.`);
|
|
163
|
+
}
|
|
164
|
+
if (outputSchema.properties && Object.keys(outputSchema.properties).some((key) => !["headers", "body"].includes(key))) {
|
|
165
|
+
throw new OpenAPIError(`When output structure is 'detailed', output schema must be only can contain 'headers' and 'body' properties.`);
|
|
166
|
+
}
|
|
167
|
+
let headersSchema = outputSchema.properties?.headers;
|
|
168
|
+
const bodySchema = outputSchema.properties?.body;
|
|
169
|
+
if (headersSchema !== void 0 && this.schemaUtils.isAnySchema(headersSchema)) {
|
|
170
|
+
headersSchema = void 0;
|
|
171
|
+
}
|
|
172
|
+
if (headersSchema !== void 0 && !this.schemaUtils.isObjectSchema(headersSchema)) {
|
|
173
|
+
throw new OpenAPIError(`When output structure is 'detailed', headers schema in output schema must be an object.`);
|
|
174
|
+
}
|
|
175
|
+
return { headersSchema, bodySchema };
|
|
176
|
+
}
|
|
177
|
+
parseCompactSchema(outputSchema) {
|
|
178
|
+
return {
|
|
179
|
+
headersSchema: void 0,
|
|
180
|
+
bodySchema: outputSchema
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
38
185
|
// src/openapi-parameters-builder.ts
|
|
39
|
-
import { get,
|
|
186
|
+
import { get, isObject, omit } from "@orpc/shared";
|
|
40
187
|
var OpenAPIParametersBuilder = class {
|
|
41
188
|
build(paramIn, jsonSchema, options) {
|
|
42
189
|
const parameters = [];
|
|
43
190
|
for (const name in jsonSchema.properties) {
|
|
44
191
|
const schema = jsonSchema.properties[name];
|
|
45
192
|
const paramExamples = jsonSchema.examples?.filter((example) => {
|
|
46
|
-
return
|
|
193
|
+
return isObject(example) && name in example;
|
|
47
194
|
}).map((example) => {
|
|
48
195
|
return example[name];
|
|
49
196
|
});
|
|
@@ -63,6 +210,14 @@ var OpenAPIParametersBuilder = class {
|
|
|
63
210
|
}
|
|
64
211
|
return parameters;
|
|
65
212
|
}
|
|
213
|
+
buildHeadersObject(jsonSchema, options) {
|
|
214
|
+
const parameters = this.build("header", jsonSchema, options);
|
|
215
|
+
const headersObject = {};
|
|
216
|
+
for (const param of parameters) {
|
|
217
|
+
headersObject[param.name] = omit(param, ["name", "in"]);
|
|
218
|
+
}
|
|
219
|
+
return headersObject;
|
|
220
|
+
}
|
|
66
221
|
};
|
|
67
222
|
|
|
68
223
|
// src/openapi-path-parser.ts
|
|
@@ -96,7 +251,7 @@ var CompositeSchemaConverter = class {
|
|
|
96
251
|
};
|
|
97
252
|
|
|
98
253
|
// src/schema-utils.ts
|
|
99
|
-
import {
|
|
254
|
+
import { isObject as isObject2 } from "@orpc/shared";
|
|
100
255
|
|
|
101
256
|
// src/schema.ts
|
|
102
257
|
import * as JSONSchema from "json-schema-typed/draft-2020-12";
|
|
@@ -138,14 +293,14 @@ var SchemaUtils = class {
|
|
|
138
293
|
return typeof schema === "object" && schema.type === "object";
|
|
139
294
|
}
|
|
140
295
|
isAnySchema(schema) {
|
|
141
|
-
return schema === true || Object.keys(schema).length === 0;
|
|
296
|
+
return schema === true || Object.keys(schema).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
|
|
142
297
|
}
|
|
143
298
|
isUndefinableSchema(schema) {
|
|
144
299
|
const [matches] = this.filterSchemaBranches(schema, (schema2) => {
|
|
145
300
|
if (typeof schema2 === "boolean") {
|
|
146
301
|
return schema2;
|
|
147
302
|
}
|
|
148
|
-
return Object.keys(schema2).length === 0;
|
|
303
|
+
return Object.keys(schema2).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
|
|
149
304
|
});
|
|
150
305
|
return matches.length > 0;
|
|
151
306
|
}
|
|
@@ -158,7 +313,7 @@ var SchemaUtils = class {
|
|
|
158
313
|
}, {});
|
|
159
314
|
matched.required = schema.required?.filter((key) => separatedProperties.includes(key));
|
|
160
315
|
matched.examples = schema.examples?.map((example) => {
|
|
161
|
-
if (!
|
|
316
|
+
if (!isObject2(example)) {
|
|
162
317
|
return example;
|
|
163
318
|
}
|
|
164
319
|
return Object.entries(example).reduce((acc, [key, value]) => {
|
|
@@ -174,7 +329,7 @@ var SchemaUtils = class {
|
|
|
174
329
|
}, {});
|
|
175
330
|
rest.required = schema.required?.filter((key) => !separatedProperties.includes(key));
|
|
176
331
|
rest.examples = schema.examples?.map((example) => {
|
|
177
|
-
if (!
|
|
332
|
+
if (!isObject2(example)) {
|
|
178
333
|
return example;
|
|
179
334
|
}
|
|
180
335
|
return Object.entries(example).reduce((acc, [key, value]) => {
|
|
@@ -218,130 +373,161 @@ var SchemaUtils = class {
|
|
|
218
373
|
|
|
219
374
|
// src/openapi-generator.ts
|
|
220
375
|
var OpenAPIGenerator = class {
|
|
376
|
+
contentBuilder;
|
|
377
|
+
parametersBuilder;
|
|
378
|
+
schemaConverter;
|
|
379
|
+
schemaUtils;
|
|
380
|
+
jsonSerializer;
|
|
381
|
+
pathParser;
|
|
382
|
+
inputStructureParser;
|
|
383
|
+
outputStructureParser;
|
|
384
|
+
errorHandlerStrategy;
|
|
385
|
+
ignoreUndefinedPathProcedures;
|
|
386
|
+
considerMissingTagDefinitionAsError;
|
|
387
|
+
strictErrorResponses;
|
|
221
388
|
constructor(options) {
|
|
222
|
-
this.options = options;
|
|
223
389
|
this.parametersBuilder = options?.parametersBuilder ?? new OpenAPIParametersBuilder();
|
|
224
390
|
this.schemaConverter = new CompositeSchemaConverter(options?.schemaConverters ?? []);
|
|
225
391
|
this.schemaUtils = options?.schemaUtils ?? new SchemaUtils();
|
|
226
392
|
this.jsonSerializer = options?.jsonSerializer ?? new JSONSerializer();
|
|
227
393
|
this.contentBuilder = options?.contentBuilder ?? new OpenAPIContentBuilder(this.schemaUtils);
|
|
228
394
|
this.pathParser = new OpenAPIPathParser();
|
|
395
|
+
this.inputStructureParser = options?.inputStructureParser ?? new OpenAPIInputStructureParser(this.schemaConverter, this.schemaUtils, this.pathParser);
|
|
396
|
+
this.outputStructureParser = options?.outputStructureParser ?? new OpenAPIOutputStructureParser(this.schemaConverter, this.schemaUtils);
|
|
397
|
+
this.errorHandlerStrategy = options?.errorHandlerStrategy ?? "throw";
|
|
398
|
+
this.ignoreUndefinedPathProcedures = options?.ignoreUndefinedPathProcedures ?? false;
|
|
399
|
+
this.considerMissingTagDefinitionAsError = options?.considerMissingTagDefinitionAsError ?? false;
|
|
400
|
+
this.strictErrorResponses = options?.strictErrorResponses ?? true;
|
|
229
401
|
}
|
|
230
|
-
contentBuilder;
|
|
231
|
-
parametersBuilder;
|
|
232
|
-
schemaConverter;
|
|
233
|
-
schemaUtils;
|
|
234
|
-
jsonSerializer;
|
|
235
|
-
pathParser;
|
|
236
402
|
async generate(router, doc) {
|
|
237
403
|
const builder = new OpenApiBuilder({
|
|
238
404
|
...doc,
|
|
239
405
|
openapi: "3.1.1"
|
|
240
406
|
});
|
|
241
407
|
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;
|
|
408
|
+
await eachAllContractProcedure({
|
|
409
|
+
path: [],
|
|
410
|
+
router
|
|
411
|
+
}, ({ contract, path }) => {
|
|
412
|
+
try {
|
|
413
|
+
const def = contract["~orpc"];
|
|
414
|
+
if (this.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
|
|
415
|
+
return;
|
|
266
416
|
}
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
417
|
+
const method = fallbackContractConfig2("defaultMethod", def.route?.method);
|
|
418
|
+
const httpPath = def.route?.path ? standardizeHTTPPath(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
|
|
419
|
+
const inputStructure = fallbackContractConfig2("defaultInputStructure", def.route?.inputStructure);
|
|
420
|
+
const outputStructure = fallbackContractConfig2("defaultOutputStructure", def.route?.outputStructure);
|
|
421
|
+
const { paramsSchema, querySchema, headersSchema, bodySchema } = this.inputStructureParser.parse(contract, inputStructure);
|
|
422
|
+
const { headersSchema: resHeadersSchema, bodySchema: resBodySchema } = this.outputStructureParser.parse(contract, outputStructure);
|
|
423
|
+
const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
|
|
271
424
|
required: true
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
425
|
+
}) : [];
|
|
426
|
+
const query = querySchema ? this.parametersBuilder.build("query", querySchema) : [];
|
|
427
|
+
const headers = headersSchema ? this.parametersBuilder.build("header", headersSchema) : [];
|
|
428
|
+
const parameters = [...params, ...query, ...headers];
|
|
429
|
+
const requestBody = bodySchema !== void 0 ? {
|
|
430
|
+
required: this.schemaUtils.isUndefinableSchema(bodySchema),
|
|
431
|
+
content: this.contentBuilder.build(bodySchema)
|
|
432
|
+
} : void 0;
|
|
433
|
+
const responses = {};
|
|
434
|
+
responses[fallbackContractConfig2("defaultSuccessStatus", def.route?.successStatus)] = {
|
|
435
|
+
description: fallbackContractConfig2("defaultSuccessDescription", def.route?.successDescription),
|
|
436
|
+
content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema) : void 0,
|
|
437
|
+
headers: resHeadersSchema !== void 0 ? this.parametersBuilder.buildHeadersObject(resHeadersSchema) : void 0
|
|
438
|
+
};
|
|
439
|
+
const errors = group(Object.entries(def.errorMap ?? {}).filter(([_, config]) => config).map(([code, config]) => ({
|
|
440
|
+
...config,
|
|
441
|
+
code,
|
|
442
|
+
status: fallbackORPCErrorStatus(code, config?.status)
|
|
443
|
+
})), (error) => error.status);
|
|
444
|
+
for (const status in errors) {
|
|
445
|
+
const configs = errors[status];
|
|
446
|
+
if (!configs || configs.length === 0) {
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
const schemas = configs.map(({ data, code, message }) => {
|
|
450
|
+
const json = {
|
|
451
|
+
type: "object",
|
|
452
|
+
properties: {
|
|
453
|
+
defined: { const: true },
|
|
454
|
+
code: { const: code },
|
|
455
|
+
status: { const: Number(status) },
|
|
456
|
+
message: { type: "string", default: message },
|
|
457
|
+
data: {}
|
|
458
|
+
},
|
|
459
|
+
required: ["defined", "code", "status", "message"]
|
|
460
|
+
};
|
|
461
|
+
if (data) {
|
|
462
|
+
const dataJson = this.schemaConverter.convert(data, { strategy: "output" });
|
|
463
|
+
json.properties.data = dataJson;
|
|
464
|
+
if (!this.schemaUtils.isUndefinableSchema(dataJson)) {
|
|
465
|
+
json.required.push("data");
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return json;
|
|
469
|
+
});
|
|
470
|
+
if (this.strictErrorResponses) {
|
|
471
|
+
schemas.push({
|
|
472
|
+
type: "object",
|
|
473
|
+
properties: {
|
|
474
|
+
defined: { const: false },
|
|
475
|
+
code: { type: "string" },
|
|
476
|
+
status: { type: "number" },
|
|
477
|
+
message: { type: "string" },
|
|
478
|
+
data: {}
|
|
479
|
+
},
|
|
480
|
+
required: ["defined", "code", "status", "message"]
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
const contentSchema = schemas.length === 1 ? schemas[0] : {
|
|
484
|
+
oneOf: schemas
|
|
485
|
+
};
|
|
486
|
+
responses[status] = {
|
|
487
|
+
description: status,
|
|
488
|
+
content: this.contentBuilder.build(contentSchema)
|
|
489
|
+
};
|
|
288
490
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
return void 0;
|
|
491
|
+
if (this.considerMissingTagDefinitionAsError && def.route?.tags) {
|
|
492
|
+
const missingTag = def.route?.tags.find((tag) => !rootTags.includes(tag));
|
|
493
|
+
if (missingTag !== void 0) {
|
|
494
|
+
throw new OpenAPIError(
|
|
495
|
+
`Tag "${missingTag}" is missing definition. Please define it in OpenAPI root tags object`
|
|
496
|
+
);
|
|
497
|
+
}
|
|
297
498
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
499
|
+
const operation = {
|
|
500
|
+
summary: def.route?.summary,
|
|
501
|
+
description: def.route?.description,
|
|
502
|
+
deprecated: def.route?.deprecated,
|
|
503
|
+
tags: def.route?.tags ? [...def.route.tags] : void 0,
|
|
504
|
+
operationId: path.join("."),
|
|
505
|
+
parameters: parameters.length ? parameters : void 0,
|
|
506
|
+
requestBody,
|
|
507
|
+
responses
|
|
303
508
|
};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
)
|
|
318
|
-
|
|
509
|
+
builder.addPath(httpPath, {
|
|
510
|
+
[method.toLocaleLowerCase()]: operation
|
|
511
|
+
});
|
|
512
|
+
} catch (e) {
|
|
513
|
+
if (e instanceof OpenAPIError) {
|
|
514
|
+
const error = new OpenAPIError(`
|
|
515
|
+
Generate OpenAPI Error: ${e.message}
|
|
516
|
+
Happened at path: ${path.join(".")}
|
|
517
|
+
`, { cause: e });
|
|
518
|
+
if (this.errorHandlerStrategy === "throw") {
|
|
519
|
+
throw error;
|
|
520
|
+
}
|
|
521
|
+
if (this.errorHandlerStrategy === "log") {
|
|
522
|
+
console.error(error);
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
throw e;
|
|
319
526
|
}
|
|
320
527
|
}
|
|
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
|
-
[def.route?.successStatus ?? 200]: successResponse
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
builder.addPath(httpPath, {
|
|
334
|
-
[method.toLocaleLowerCase()]: operation
|
|
335
|
-
});
|
|
336
528
|
});
|
|
337
529
|
return this.jsonSerializer.serialize(builder.getSpec());
|
|
338
530
|
}
|
|
339
|
-
handleError(error) {
|
|
340
|
-
if (this.options?.throwOnError) {
|
|
341
|
-
throw error;
|
|
342
|
-
}
|
|
343
|
-
console.error(error);
|
|
344
|
-
}
|
|
345
531
|
};
|
|
346
532
|
export {
|
|
347
533
|
CompositeSchemaConverter,
|
|
@@ -355,8 +541,6 @@ export {
|
|
|
355
541
|
OpenAPIPathParser,
|
|
356
542
|
OpenApiBuilder,
|
|
357
543
|
SchemaUtils,
|
|
358
|
-
forEachAllContractProcedure,
|
|
359
|
-
forEachContractProcedure,
|
|
360
544
|
standardizeHTTPPath
|
|
361
545
|
};
|
|
362
546
|
//# 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-PWOV66X6.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,10 @@
|
|
|
1
|
+
import type { Context, Router } from '@orpc/server';
|
|
2
|
+
import type { FetchHandler, FetchHandleResult } from '@orpc/server/fetch';
|
|
3
|
+
import type { StandardHandleRest } from '@orpc/server/standard';
|
|
4
|
+
import type { OpenAPIHandlerOptions } from '../standard';
|
|
5
|
+
export declare class OpenAPIHandler<T extends Context> implements FetchHandler<T> {
|
|
6
|
+
private readonly standardHandler;
|
|
7
|
+
constructor(router: Router<T, any>, options?: NoInfer<OpenAPIHandlerOptions<T>>);
|
|
8
|
+
handle(request: Request, ...rest: StandardHandleRest<T>): Promise<FetchHandleResult>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=openapi-handler.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Context, Router } from '@orpc/server';
|
|
2
|
+
import type { NodeHttpHandler, NodeHttpHandleResult, NodeHttpRequest, NodeHttpResponse } from '@orpc/server/node';
|
|
3
|
+
import type { StandardHandleRest } from '@orpc/server/standard';
|
|
4
|
+
import type { OpenAPIHandlerOptions } from '../standard';
|
|
5
|
+
export declare class OpenAPIHandler<T extends Context> implements NodeHttpHandler<T> {
|
|
6
|
+
private readonly standardHandler;
|
|
7
|
+
constructor(router: Router<T, any>, options?: NoInfer<OpenAPIHandlerOptions<T>>);
|
|
8
|
+
handle(req: NodeHttpRequest, res: NodeHttpResponse, ...rest: StandardHandleRest<T>): Promise<NodeHttpHandleResult>;
|
|
9
|
+
}
|
|
10
|
+
//# 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
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context } from '@orpc/server';
|
|
2
|
+
import type { RPCHandlerOptions } from '@orpc/server/standard';
|
|
3
|
+
import type { OpenAPICodecOptions } from './openapi-codec';
|
|
4
|
+
import type { OpenAPIMatcherOptions } from './openapi-matcher';
|
|
5
|
+
export interface OpenAPIHandlerOptions<T extends Context> extends RPCHandlerOptions<T>, OpenAPIMatcherOptions, OpenAPICodecOptions {
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=openapi-handler.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AnyRouter } from '@orpc/server';
|
|
2
|
+
import type { StandardMatcher, StandardMatchResult } from '@orpc/server/standard';
|
|
3
|
+
import { type HTTPPath } from '@orpc/contract';
|
|
4
|
+
export interface OpenAPIMatcherOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Ignore procedure that does not have a method defined in the contract.
|
|
7
|
+
*
|
|
8
|
+
* @default false
|
|
9
|
+
*/
|
|
10
|
+
ignoreUndefinedMethod?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare class OpenAPIMatcher implements StandardMatcher {
|
|
13
|
+
private readonly tree;
|
|
14
|
+
private readonly ignoreUndefinedMethod;
|
|
15
|
+
constructor(options?: OpenAPIMatcherOptions);
|
|
16
|
+
private pendingRouters;
|
|
17
|
+
init(router: AnyRouter, path?: string[]): void;
|
|
18
|
+
match(method: string, pathname: HTTPPath): Promise<StandardMatchResult>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=openapi-matcher.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PublicJSONSerializer } from '../../json-serializer';
|
|
2
|
+
export interface OpenAPISerializerOptions {
|
|
3
|
+
jsonSerializer?: PublicJSONSerializer;
|
|
4
|
+
}
|
|
5
|
+
export declare class OpenAPISerializer {
|
|
6
|
+
private readonly jsonSerializer;
|
|
7
|
+
constructor(options?: OpenAPISerializerOptions);
|
|
8
|
+
serialize(data: unknown): unknown;
|
|
9
|
+
deserialize(serialized: unknown): unknown;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=openapi-serializer.d.ts.map
|