@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.
Files changed (42) hide show
  1. package/dist/chunk-DRV7KYES.js +420 -0
  2. package/dist/chunk-HC5PVG4R.js +52 -0
  3. package/dist/chunk-NHYWV7BW.js +32 -0
  4. package/dist/fetch.js +5 -587
  5. package/dist/hono.js +9 -0
  6. package/dist/index.js +352 -112
  7. package/dist/next.js +9 -0
  8. package/dist/node.js +30 -0
  9. package/dist/src/adapters/fetch/index.d.ts +2 -0
  10. package/dist/src/adapters/fetch/openapi-handler.d.ts +11 -0
  11. package/dist/src/adapters/hono/index.d.ts +2 -0
  12. package/dist/src/adapters/next/index.d.ts +2 -0
  13. package/dist/src/adapters/node/index.d.ts +2 -0
  14. package/dist/src/adapters/node/openapi-handler.d.ts +11 -0
  15. package/dist/src/adapters/standard/index.d.ts +6 -0
  16. package/dist/src/adapters/standard/openapi-codec.d.ts +15 -0
  17. package/dist/src/adapters/standard/openapi-handler.d.ts +7 -0
  18. package/dist/src/adapters/standard/openapi-matcher.d.ts +20 -0
  19. package/dist/src/adapters/standard/openapi-serializer.d.ts +11 -0
  20. package/dist/src/index.d.ts +5 -0
  21. package/dist/src/openapi-error.d.ts +3 -0
  22. package/dist/src/openapi-generator.d.ts +25 -9
  23. package/dist/src/openapi-input-structure-parser.d.ts +22 -0
  24. package/dist/src/openapi-operation-extender.d.ts +7 -0
  25. package/dist/src/openapi-output-structure-parser.d.ts +18 -0
  26. package/dist/src/openapi-parameters-builder.d.ts +3 -0
  27. package/dist/src/schema-converter.d.ts +2 -2
  28. package/dist/src/schema.d.ts +1 -1
  29. package/dist/src/utils.d.ts +1 -16
  30. package/dist/standard.js +14 -0
  31. package/package.json +27 -10
  32. package/dist/chunk-KNYXLM77.js +0 -107
  33. package/dist/src/fetch/index.d.ts +0 -10
  34. package/dist/src/fetch/input-builder-full.d.ts +0 -11
  35. package/dist/src/fetch/input-builder-simple.d.ts +0 -6
  36. package/dist/src/fetch/openapi-handler-server.d.ts +0 -7
  37. package/dist/src/fetch/openapi-handler-serverless.d.ts +0 -7
  38. package/dist/src/fetch/openapi-handler.d.ts +0 -30
  39. package/dist/src/fetch/openapi-payload-codec.d.ts +0 -15
  40. package/dist/src/fetch/openapi-procedure-matcher.d.ts +0 -19
  41. package/dist/src/fetch/schema-coercer.d.ts +0 -10
  42. /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-KNYXLM77.js";
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, isPlainObject } from "@orpc/shared";
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 isPlainObject(example) && name in example;
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 { isPlainObject as isPlainObject2 } from "@orpc/shared";
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 (!isPlainObject2(example)) {
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 (!isPlainObject2(example)) {
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 forEachAllContractProcedure(router, ({ contract, path }) => {
243
- const def = contract["~orpc"];
244
- if (this.options?.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
245
- return;
246
- }
247
- const method = def.route?.method ?? "POST";
248
- const httpPath = def.route?.path ? standardizeHTTPPath(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
249
- let inputSchema = this.schemaConverter.convert(def.InputSchema, { strategy: "input" });
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 [matched, rest] = this.schemaUtils.separateObjectSchema(inputSchema, dynamic.map((v) => v.name));
268
- inputSchema = rest;
269
- return this.parametersBuilder.build("path", matched, {
270
- example: def.inputExample,
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
- const query = (() => {
275
- if (method !== "GET" || Object.keys(inputSchema).length === 0) {
276
- return void 0;
277
- }
278
- if (this.schemaUtils.isAnySchema(inputSchema)) {
279
- return void 0;
280
- }
281
- if (!this.schemaUtils.isObjectSchema(inputSchema)) {
282
- this.handleError(
283
- new Error(
284
- `When method is GET, input schema must be an object [${path.join(".")}]`
285
- )
286
- );
287
- return void 0;
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
- return this.parametersBuilder.build("query", inputSchema, {
290
- example: def.inputExample
291
- });
292
- })();
293
- const parameters = [...params ?? [], ...query ?? []];
294
- const requestBody = (() => {
295
- if (method === "GET") {
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
- return {
299
- required: this.schemaUtils.isUndefinableSchema(inputSchema),
300
- content: this.contentBuilder.build(inputSchema, {
301
- example: def.inputExample
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
- const successResponse = {
306
- description: "OK",
307
- content: this.contentBuilder.build(outputSchema, {
308
- example: def.outputExample
309
- })
310
- };
311
- if (this.options?.considerMissingTagDefinitionAsError && def.route?.tags) {
312
- const missingTag = def.route?.tags.find((tag) => !rootTags.includes(tag));
313
- if (missingTag !== void 0) {
314
- this.handleError(
315
- new Error(
316
- `Tag "${missingTag}" is missing definition. Please define it in OpenAPI root tags object. [${path.join(".")}]`
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
- handleError(error) {
340
- if (this.options?.throwOnError) {
341
- throw error;
342
- }
343
- console.error(error);
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
- forEachAllContractProcedure,
359
- forEachContractProcedure,
596
+ extendOperation,
597
+ getOperationExtender,
598
+ oo,
599
+ setOperationExtender,
360
600
  standardizeHTTPPath
361
601
  };
362
602
  //# sourceMappingURL=index.js.map
package/dist/next.js ADDED
@@ -0,0 +1,9 @@
1
+ import {
2
+ OpenAPIHandler
3
+ } from "./chunk-NHYWV7BW.js";
4
+ import "./chunk-DRV7KYES.js";
5
+ import "./chunk-HC5PVG4R.js";
6
+ export {
7
+ OpenAPIHandler
8
+ };
9
+ //# sourceMappingURL=next.js.map
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,2 @@
1
+ export * from './openapi-handler';
2
+ //# sourceMappingURL=index.d.ts.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,2 @@
1
+ export * from '../fetch';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export * from '../fetch';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export * from './openapi-handler';
2
+ //# sourceMappingURL=index.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,6 @@
1
+ export * as BracketNotation from './bracket-notation';
2
+ export * from './openapi-codec';
3
+ export * from './openapi-handler';
4
+ export * from './openapi-matcher';
5
+ export * from './openapi-serializer';
6
+ //# sourceMappingURL=index.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