@orpc/openapi 0.0.0-next.af8ac85 → 0.0.0-next.b2e67f7

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 (43) hide show
  1. package/README.md +91 -0
  2. package/dist/chunk-LTTK3H5J.js +157 -0
  3. package/dist/chunk-PW7RAFQQ.js +32 -0
  4. package/dist/chunk-XGHV4TH3.js +13 -0
  5. package/dist/fetch.js +5 -590
  6. package/dist/hono.js +9 -0
  7. package/dist/index.js +460 -121
  8. package/dist/next.js +9 -0
  9. package/dist/node.js +30 -0
  10. package/dist/src/adapters/fetch/index.d.ts +2 -0
  11. package/dist/src/adapters/fetch/openapi-handler.d.ts +11 -0
  12. package/dist/src/adapters/hono/index.d.ts +2 -0
  13. package/dist/src/adapters/next/index.d.ts +2 -0
  14. package/dist/src/adapters/node/index.d.ts +2 -0
  15. package/dist/src/adapters/node/openapi-handler.d.ts +11 -0
  16. package/dist/src/adapters/standard/index.d.ts +4 -0
  17. package/dist/src/adapters/standard/openapi-codec.d.ts +13 -0
  18. package/dist/src/adapters/standard/openapi-handler.d.ts +5 -0
  19. package/dist/src/adapters/standard/openapi-matcher.d.ts +10 -0
  20. package/dist/src/index.d.ts +5 -1
  21. package/dist/src/openapi-error.d.ts +3 -0
  22. package/dist/src/openapi-generator.d.ts +27 -11
  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 +2 -16
  30. package/dist/standard.js +10 -0
  31. package/package.json +31 -14
  32. package/dist/chunk-KNYXLM77.js +0 -107
  33. package/dist/src/fetch/bracket-notation.d.ts +0 -84
  34. package/dist/src/fetch/index.d.ts +0 -10
  35. package/dist/src/fetch/input-builder-full.d.ts +0 -11
  36. package/dist/src/fetch/input-builder-simple.d.ts +0 -6
  37. package/dist/src/fetch/openapi-handler-server.d.ts +0 -7
  38. package/dist/src/fetch/openapi-handler-serverless.d.ts +0 -7
  39. package/dist/src/fetch/openapi-handler.d.ts +0 -30
  40. package/dist/src/fetch/openapi-payload-codec.d.ts +0 -15
  41. package/dist/src/fetch/openapi-procedure-matcher.d.ts +0 -19
  42. package/dist/src/fetch/schema-coercer.d.ts +0 -10
  43. package/dist/src/json-serializer.d.ts +0 -5
package/dist/index.js CHANGED
@@ -1,9 +1,53 @@
1
1
  import {
2
- JSONSerializer,
3
- forEachAllContractProcedure,
4
- forEachContractProcedure,
5
- standardizeHTTPPath
6
- } from "./chunk-KNYXLM77.js";
2
+ standardizeHTTPPath,
3
+ toOpenAPI31RoutePattern
4
+ } from "./chunk-XGHV4TH3.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,166 @@ var OpenAPIContentBuilder = class {
35
79
  }
36
80
  };
37
81
 
82
+ // src/openapi-generator.ts
83
+ import { fallbackORPCErrorStatus } from "@orpc/client";
84
+ import { OpenAPIJsonSerializer } from "@orpc/client/openapi";
85
+ import { fallbackContractConfig as fallbackContractConfig2, getEventIteratorSchemaDetails } from "@orpc/contract";
86
+ import { eachAllContractProcedure } from "@orpc/server";
87
+ import { group } from "@orpc/shared";
88
+
89
+ // src/openapi-error.ts
90
+ var OpenAPIError = class extends Error {
91
+ };
92
+
93
+ // src/openapi-input-structure-parser.ts
94
+ import { fallbackContractConfig } from "@orpc/contract";
95
+ var OpenAPIInputStructureParser = class {
96
+ constructor(schemaConverter, schemaUtils, pathParser) {
97
+ this.schemaConverter = schemaConverter;
98
+ this.schemaUtils = schemaUtils;
99
+ this.pathParser = pathParser;
100
+ }
101
+ parse(contract, structure) {
102
+ const inputSchema = this.schemaConverter.convert(contract["~orpc"].inputSchema, { strategy: "input" });
103
+ const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route?.method);
104
+ const httpPath = contract["~orpc"].route?.path;
105
+ if (this.schemaUtils.isAnySchema(inputSchema)) {
106
+ return {
107
+ paramsSchema: void 0,
108
+ querySchema: void 0,
109
+ headersSchema: void 0,
110
+ bodySchema: void 0
111
+ };
112
+ }
113
+ if (structure === "detailed") {
114
+ return this.parseDetailedSchema(inputSchema);
115
+ } else {
116
+ return this.parseCompactSchema(inputSchema, method, httpPath);
117
+ }
118
+ }
119
+ parseDetailedSchema(inputSchema) {
120
+ if (!this.schemaUtils.isObjectSchema(inputSchema)) {
121
+ throw new OpenAPIError(`When input structure is 'detailed', input schema must be an object.`);
122
+ }
123
+ if (inputSchema.properties && Object.keys(inputSchema.properties).some((key) => !["params", "query", "headers", "body"].includes(key))) {
124
+ throw new OpenAPIError(`When input structure is 'detailed', input schema must be only can contain 'params', 'query', 'headers' and 'body' properties.`);
125
+ }
126
+ let paramsSchema = inputSchema.properties?.params;
127
+ let querySchema = inputSchema.properties?.query;
128
+ let headersSchema = inputSchema.properties?.headers;
129
+ const bodySchema = inputSchema.properties?.body;
130
+ if (paramsSchema !== void 0 && this.schemaUtils.isAnySchema(paramsSchema)) {
131
+ paramsSchema = void 0;
132
+ }
133
+ if (paramsSchema !== void 0 && !this.schemaUtils.isObjectSchema(paramsSchema)) {
134
+ throw new OpenAPIError(`When input structure is 'detailed', params schema in input schema must be an object.`);
135
+ }
136
+ if (querySchema !== void 0 && this.schemaUtils.isAnySchema(querySchema)) {
137
+ querySchema = void 0;
138
+ }
139
+ if (querySchema !== void 0 && !this.schemaUtils.isObjectSchema(querySchema)) {
140
+ throw new OpenAPIError(`When input structure is 'detailed', query schema in input schema must be an object.`);
141
+ }
142
+ if (headersSchema !== void 0 && this.schemaUtils.isAnySchema(headersSchema)) {
143
+ headersSchema = void 0;
144
+ }
145
+ if (headersSchema !== void 0 && !this.schemaUtils.isObjectSchema(headersSchema)) {
146
+ throw new OpenAPIError(`When input structure is 'detailed', headers schema in input schema must be an object.`);
147
+ }
148
+ return { paramsSchema, querySchema, headersSchema, bodySchema };
149
+ }
150
+ parseCompactSchema(inputSchema, method, httpPath) {
151
+ const dynamic = httpPath ? this.pathParser.parseDynamicParams(httpPath) : [];
152
+ if (dynamic.length === 0) {
153
+ if (method === "GET") {
154
+ let querySchema = inputSchema;
155
+ if (querySchema !== void 0 && this.schemaUtils.isAnySchema(querySchema)) {
156
+ querySchema = void 0;
157
+ }
158
+ if (querySchema !== void 0 && !this.schemaUtils.isObjectSchema(querySchema)) {
159
+ throw new OpenAPIError(`When input structure is 'compact' and method is 'GET', input schema must be an object.`);
160
+ }
161
+ return {
162
+ paramsSchema: void 0,
163
+ querySchema,
164
+ headersSchema: void 0,
165
+ bodySchema: void 0
166
+ };
167
+ }
168
+ return {
169
+ paramsSchema: void 0,
170
+ querySchema: void 0,
171
+ headersSchema: void 0,
172
+ bodySchema: inputSchema
173
+ };
174
+ }
175
+ if (!this.schemaUtils.isObjectSchema(inputSchema)) {
176
+ throw new OpenAPIError(`When input structure is 'compact' and path has dynamic parameters, input schema must be an object.`);
177
+ }
178
+ const [params, rest] = this.schemaUtils.separateObjectSchema(inputSchema, dynamic.map((v) => v.name));
179
+ return {
180
+ paramsSchema: params,
181
+ querySchema: method === "GET" ? rest : void 0,
182
+ headersSchema: void 0,
183
+ bodySchema: method !== "GET" ? rest : void 0
184
+ };
185
+ }
186
+ };
187
+
188
+ // src/openapi-output-structure-parser.ts
189
+ var OpenAPIOutputStructureParser = class {
190
+ constructor(schemaConverter, schemaUtils) {
191
+ this.schemaConverter = schemaConverter;
192
+ this.schemaUtils = schemaUtils;
193
+ }
194
+ parse(contract, structure) {
195
+ const outputSchema = this.schemaConverter.convert(contract["~orpc"].outputSchema, { strategy: "output" });
196
+ if (this.schemaUtils.isAnySchema(outputSchema)) {
197
+ return {
198
+ headersSchema: void 0,
199
+ bodySchema: void 0
200
+ };
201
+ }
202
+ if (structure === "detailed") {
203
+ return this.parseDetailedSchema(outputSchema);
204
+ } else {
205
+ return this.parseCompactSchema(outputSchema);
206
+ }
207
+ }
208
+ parseDetailedSchema(outputSchema) {
209
+ if (!this.schemaUtils.isObjectSchema(outputSchema)) {
210
+ throw new OpenAPIError(`When output structure is 'detailed', output schema must be an object.`);
211
+ }
212
+ if (outputSchema.properties && Object.keys(outputSchema.properties).some((key) => !["headers", "body"].includes(key))) {
213
+ throw new OpenAPIError(`When output structure is 'detailed', output schema must be only can contain 'headers' and 'body' properties.`);
214
+ }
215
+ let headersSchema = outputSchema.properties?.headers;
216
+ const bodySchema = outputSchema.properties?.body;
217
+ if (headersSchema !== void 0 && this.schemaUtils.isAnySchema(headersSchema)) {
218
+ headersSchema = void 0;
219
+ }
220
+ if (headersSchema !== void 0 && !this.schemaUtils.isObjectSchema(headersSchema)) {
221
+ throw new OpenAPIError(`When output structure is 'detailed', headers schema in output schema must be an object.`);
222
+ }
223
+ return { headersSchema, bodySchema };
224
+ }
225
+ parseCompactSchema(outputSchema) {
226
+ return {
227
+ headersSchema: void 0,
228
+ bodySchema: outputSchema
229
+ };
230
+ }
231
+ };
232
+
38
233
  // src/openapi-parameters-builder.ts
39
- import { get, isPlainObject } from "@orpc/shared";
234
+ import { get, isObject, omit } from "@orpc/shared";
40
235
  var OpenAPIParametersBuilder = class {
41
236
  build(paramIn, jsonSchema, options) {
42
237
  const parameters = [];
43
238
  for (const name in jsonSchema.properties) {
44
239
  const schema = jsonSchema.properties[name];
45
240
  const paramExamples = jsonSchema.examples?.filter((example) => {
46
- return isPlainObject(example) && name in example;
241
+ return isObject(example) && name in example;
47
242
  }).map((example) => {
48
243
  return example[name];
49
244
  });
@@ -63,6 +258,14 @@ var OpenAPIParametersBuilder = class {
63
258
  }
64
259
  return parameters;
65
260
  }
261
+ buildHeadersObject(jsonSchema, options) {
262
+ const parameters = this.build("header", jsonSchema, options);
263
+ const headersObject = {};
264
+ for (const param of parameters) {
265
+ headersObject[param.name] = omit(param, ["name", "in"]);
266
+ }
267
+ return headersObject;
268
+ }
66
269
  };
67
270
 
68
271
  // src/openapi-path-parser.ts
@@ -96,7 +299,7 @@ var CompositeSchemaConverter = class {
96
299
  };
97
300
 
98
301
  // src/schema-utils.ts
99
- import { isPlainObject as isPlainObject2 } from "@orpc/shared";
302
+ import { isObject as isObject2 } from "@orpc/shared";
100
303
 
101
304
  // src/schema.ts
102
305
  import * as JSONSchema from "json-schema-typed/draft-2020-12";
@@ -132,20 +335,20 @@ var NON_LOGIC_KEYWORDS = [
132
335
  // src/schema-utils.ts
133
336
  var SchemaUtils = class {
134
337
  isFileSchema(schema) {
135
- return typeof schema === "object" && schema.type === "string" && typeof schema.contentMediaType === "string";
338
+ return isObject2(schema) && schema.type === "string" && typeof schema.contentMediaType === "string";
136
339
  }
137
340
  isObjectSchema(schema) {
138
- return typeof schema === "object" && schema.type === "object";
341
+ return isObject2(schema) && schema.type === "object";
139
342
  }
140
343
  isAnySchema(schema) {
141
- return schema === true || Object.keys(schema).length === 0;
344
+ return schema === true || Object.keys(schema).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
142
345
  }
143
346
  isUndefinableSchema(schema) {
144
347
  const [matches] = this.filterSchemaBranches(schema, (schema2) => {
145
348
  if (typeof schema2 === "boolean") {
146
349
  return schema2;
147
350
  }
148
- return Object.keys(schema2).length === 0;
351
+ return Object.keys(schema2).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
149
352
  });
150
353
  return matches.length > 0;
151
354
  }
@@ -158,7 +361,7 @@ var SchemaUtils = class {
158
361
  }, {});
159
362
  matched.required = schema.required?.filter((key) => separatedProperties.includes(key));
160
363
  matched.examples = schema.examples?.map((example) => {
161
- if (!isPlainObject2(example)) {
364
+ if (!isObject2(example)) {
162
365
  return example;
163
366
  }
164
367
  return Object.entries(example).reduce((acc, [key, value]) => {
@@ -174,7 +377,7 @@ var SchemaUtils = class {
174
377
  }, {});
175
378
  rest.required = schema.required?.filter((key) => !separatedProperties.includes(key));
176
379
  rest.examples = schema.examples?.map((example) => {
177
- if (!isPlainObject2(example)) {
380
+ if (!isObject2(example)) {
178
381
  return example;
179
382
  }
180
383
  return Object.entries(example).reduce((acc, [key, value]) => {
@@ -218,136 +421,269 @@ var SchemaUtils = class {
218
421
 
219
422
  // src/openapi-generator.ts
220
423
  var OpenAPIGenerator = class {
424
+ contentBuilder;
425
+ parametersBuilder;
426
+ schemaConverter;
427
+ schemaUtils;
428
+ jsonSerializer;
429
+ pathParser;
430
+ inputStructureParser;
431
+ outputStructureParser;
432
+ errorHandlerStrategy;
433
+ ignoreUndefinedPathProcedures;
434
+ considerMissingTagDefinitionAsError;
435
+ strictErrorResponses;
221
436
  constructor(options) {
222
- this.options = options;
223
437
  this.parametersBuilder = options?.parametersBuilder ?? new OpenAPIParametersBuilder();
224
438
  this.schemaConverter = new CompositeSchemaConverter(options?.schemaConverters ?? []);
225
439
  this.schemaUtils = options?.schemaUtils ?? new SchemaUtils();
226
- this.jsonSerializer = options?.jsonSerializer ?? new JSONSerializer();
440
+ this.jsonSerializer = options?.jsonSerializer ?? new OpenAPIJsonSerializer();
227
441
  this.contentBuilder = options?.contentBuilder ?? new OpenAPIContentBuilder(this.schemaUtils);
228
442
  this.pathParser = new OpenAPIPathParser();
443
+ this.inputStructureParser = options?.inputStructureParser ?? new OpenAPIInputStructureParser(this.schemaConverter, this.schemaUtils, this.pathParser);
444
+ this.outputStructureParser = options?.outputStructureParser ?? new OpenAPIOutputStructureParser(this.schemaConverter, this.schemaUtils);
445
+ this.errorHandlerStrategy = options?.errorHandlerStrategy ?? "throw";
446
+ this.ignoreUndefinedPathProcedures = options?.ignoreUndefinedPathProcedures ?? false;
447
+ this.considerMissingTagDefinitionAsError = options?.considerMissingTagDefinitionAsError ?? false;
448
+ this.strictErrorResponses = options?.strictErrorResponses ?? true;
229
449
  }
230
- contentBuilder;
231
- parametersBuilder;
232
- schemaConverter;
233
- schemaUtils;
234
- jsonSerializer;
235
- pathParser;
236
450
  async generate(router, doc) {
237
451
  const builder = new OpenApiBuilder({
238
452
  ...doc,
239
453
  openapi: "3.1.1"
240
454
  });
241
455
  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;
456
+ await eachAllContractProcedure({
457
+ path: [],
458
+ router
459
+ }, ({ contract, path }) => {
460
+ try {
461
+ const def = contract["~orpc"];
462
+ if (this.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
463
+ return;
258
464
  }
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;
465
+ const method = fallbackContractConfig2("defaultMethod", def.route?.method);
466
+ const httpPath = def.route?.path ? toOpenAPI31RoutePattern(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
467
+ const { parameters, requestBody } = (() => {
468
+ const eventIteratorSchemaDetails = getEventIteratorSchemaDetails(def.inputSchema);
469
+ if (eventIteratorSchemaDetails) {
470
+ const requestBody3 = {
471
+ required: true,
472
+ content: {
473
+ "text/event-stream": {
474
+ schema: {
475
+ oneOf: [
476
+ {
477
+ type: "object",
478
+ properties: {
479
+ event: { type: "string", const: "message" },
480
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.yields, { strategy: "input" }),
481
+ id: { type: "string" },
482
+ retry: { type: "number" }
483
+ },
484
+ required: ["event", "data"]
485
+ },
486
+ {
487
+ type: "object",
488
+ properties: {
489
+ event: { type: "string", const: "done" },
490
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.returns, { strategy: "input" }),
491
+ id: { type: "string" },
492
+ retry: { type: "number" }
493
+ },
494
+ required: ["event", "data"]
495
+ },
496
+ {
497
+ type: "object",
498
+ properties: {
499
+ event: { type: "string", const: "error" },
500
+ data: {},
501
+ id: { type: "string" },
502
+ retry: { type: "number" }
503
+ },
504
+ required: ["event", "data"]
505
+ }
506
+ ]
507
+ }
508
+ }
509
+ }
510
+ };
511
+ return { requestBody: requestBody3, parameters: [] };
512
+ }
513
+ const inputStructure = fallbackContractConfig2("defaultInputStructure", def.route?.inputStructure);
514
+ const { paramsSchema, querySchema, headersSchema, bodySchema } = this.inputStructureParser.parse(contract, inputStructure);
515
+ const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
516
+ required: true
517
+ }) : [];
518
+ const query = querySchema ? this.parametersBuilder.build("query", querySchema) : [];
519
+ const headers = headersSchema ? this.parametersBuilder.build("header", headersSchema) : [];
520
+ const parameters2 = [...params, ...query, ...headers];
521
+ const requestBody2 = bodySchema !== void 0 ? {
522
+ required: this.schemaUtils.isUndefinableSchema(bodySchema),
523
+ content: this.contentBuilder.build(bodySchema)
524
+ } : void 0;
525
+ return { parameters: parameters2, requestBody: requestBody2 };
526
+ })();
527
+ const { responses } = (() => {
528
+ const eventIteratorSchemaDetails = getEventIteratorSchemaDetails(def.outputSchema);
529
+ if (eventIteratorSchemaDetails) {
530
+ const responses3 = {};
531
+ responses3[fallbackContractConfig2("defaultSuccessStatus", def.route?.successStatus)] = {
532
+ description: fallbackContractConfig2("defaultSuccessDescription", def.route?.successDescription),
533
+ content: {
534
+ "text/event-stream": {
535
+ schema: {
536
+ oneOf: [
537
+ {
538
+ type: "object",
539
+ properties: {
540
+ event: { type: "string", const: "message" },
541
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.yields, { strategy: "input" }),
542
+ id: { type: "string" },
543
+ retry: { type: "number" }
544
+ },
545
+ required: ["event", "data"]
546
+ },
547
+ {
548
+ type: "object",
549
+ properties: {
550
+ event: { type: "string", const: "done" },
551
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.returns, { strategy: "input" }),
552
+ id: { type: "string" },
553
+ retry: { type: "number" }
554
+ },
555
+ required: ["event", "data"]
556
+ },
557
+ {
558
+ type: "object",
559
+ properties: {
560
+ event: { type: "string", const: "error" },
561
+ data: {},
562
+ id: { type: "string" },
563
+ retry: { type: "number" }
564
+ },
565
+ required: ["event", "data"]
566
+ }
567
+ ]
568
+ }
569
+ }
570
+ }
571
+ };
572
+ return { responses: responses3 };
573
+ }
574
+ const outputStructure = fallbackContractConfig2("defaultOutputStructure", def.route?.outputStructure);
575
+ const { headersSchema: resHeadersSchema, bodySchema: resBodySchema } = this.outputStructureParser.parse(contract, outputStructure);
576
+ const responses2 = {};
577
+ responses2[fallbackContractConfig2("defaultSuccessStatus", def.route?.successStatus)] = {
578
+ description: fallbackContractConfig2("defaultSuccessDescription", def.route?.successDescription),
579
+ content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema) : void 0,
580
+ headers: resHeadersSchema !== void 0 ? this.parametersBuilder.buildHeadersObject(resHeadersSchema) : void 0
581
+ };
582
+ return { responses: responses2 };
583
+ })();
584
+ const errors = group(Object.entries(def.errorMap ?? {}).filter(([_, config]) => config).map(([code, config]) => ({
585
+ ...config,
586
+ code,
587
+ status: fallbackORPCErrorStatus(code, config?.status)
588
+ })), (error) => error.status);
589
+ for (const status in errors) {
590
+ const configs = errors[status];
591
+ if (!configs || configs.length === 0) {
592
+ continue;
593
+ }
594
+ const schemas = configs.map(({ data, code, message }) => {
595
+ const json = {
596
+ type: "object",
597
+ properties: {
598
+ defined: { const: true },
599
+ code: { const: code },
600
+ status: { const: Number(status) },
601
+ message: { type: "string", default: message },
602
+ data: {}
603
+ },
604
+ required: ["defined", "code", "status", "message"]
605
+ };
606
+ if (data) {
607
+ const dataJson = this.schemaConverter.convert(data, { strategy: "output" });
608
+ json.properties.data = dataJson;
609
+ if (!this.schemaUtils.isUndefinableSchema(dataJson)) {
610
+ json.required.push("data");
611
+ }
612
+ }
613
+ return json;
614
+ });
615
+ if (this.strictErrorResponses) {
616
+ schemas.push({
617
+ type: "object",
618
+ properties: {
619
+ defined: { const: false },
620
+ code: { type: "string" },
621
+ status: { type: "number" },
622
+ message: { type: "string" },
623
+ data: {}
624
+ },
625
+ required: ["defined", "code", "status", "message"]
626
+ });
627
+ }
628
+ const contentSchema = schemas.length === 1 ? schemas[0] : {
629
+ oneOf: schemas
630
+ };
631
+ responses[status] = {
632
+ description: status,
633
+ content: this.contentBuilder.build(contentSchema)
634
+ };
266
635
  }
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,
271
- 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;
288
- }
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;
636
+ if (this.considerMissingTagDefinitionAsError && def.route?.tags) {
637
+ const missingTag = def.route?.tags.find((tag) => !rootTags.includes(tag));
638
+ if (missingTag !== void 0) {
639
+ throw new OpenAPIError(
640
+ `Tag "${missingTag}" is missing definition. Please define it in OpenAPI root tags object`
641
+ );
642
+ }
297
643
  }
298
- return {
299
- required: this.schemaUtils.isUndefinableSchema(inputSchema),
300
- content: this.contentBuilder.build(inputSchema, {
301
- example: def.inputExample
302
- })
644
+ const operation = {
645
+ summary: def.route?.summary,
646
+ description: def.route?.description,
647
+ deprecated: def.route?.deprecated,
648
+ tags: def.route?.tags ? [...def.route.tags] : void 0,
649
+ operationId: path.join("."),
650
+ parameters: parameters.length ? parameters : void 0,
651
+ requestBody,
652
+ responses
303
653
  };
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
- );
654
+ const extendedOperation = extendOperation(operation, contract);
655
+ builder.addPath(httpPath, {
656
+ [method.toLocaleLowerCase()]: extendedOperation
657
+ });
658
+ } catch (e) {
659
+ if (e instanceof OpenAPIError) {
660
+ const error = new OpenAPIError(`
661
+ Generate OpenAPI Error: ${e.message}
662
+ Happened at path: ${path.join(".")}
663
+ `, { cause: e });
664
+ if (this.errorHandlerStrategy === "throw") {
665
+ throw error;
666
+ }
667
+ if (this.errorHandlerStrategy === "log") {
668
+ console.error(error);
669
+ }
670
+ } else {
671
+ throw e;
319
672
  }
320
673
  }
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
674
  });
337
- return this.jsonSerializer.serialize(builder.getSpec());
338
- }
339
- handleError(error) {
340
- if (this.options?.throwOnError) {
341
- throw error;
342
- }
343
- console.error(error);
675
+ return this.jsonSerializer.serialize(builder.getSpec())[0];
344
676
  }
345
677
  };
678
+
679
+ // src/index.ts
680
+ var oo = {
681
+ spec: setOperationExtender
682
+ };
346
683
  export {
347
684
  CompositeSchemaConverter,
348
685
  JSONSchema,
349
686
  Format as JSONSchemaFormat,
350
- JSONSerializer,
351
687
  NON_LOGIC_KEYWORDS,
352
688
  OpenAPIContentBuilder,
353
689
  OpenAPIGenerator,
@@ -355,8 +691,11 @@ export {
355
691
  OpenAPIPathParser,
356
692
  OpenApiBuilder,
357
693
  SchemaUtils,
358
- forEachAllContractProcedure,
359
- forEachContractProcedure,
360
- standardizeHTTPPath
694
+ extendOperation,
695
+ getOperationExtender,
696
+ oo,
697
+ setOperationExtender,
698
+ standardizeHTTPPath,
699
+ toOpenAPI31RoutePattern
361
700
  };
362
701
  //# sourceMappingURL=index.js.map