@orpc/openapi 0.0.0-next.00a3135 → 0.0.0-next.0165ee0

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 (58) hide show
  1. package/README.md +91 -0
  2. package/dist/adapters/fetch/index.d.mts +14 -0
  3. package/dist/adapters/fetch/index.d.ts +14 -0
  4. package/dist/adapters/fetch/index.mjs +10 -0
  5. package/dist/adapters/hono/index.d.mts +7 -0
  6. package/dist/adapters/hono/index.d.ts +7 -0
  7. package/dist/adapters/hono/index.mjs +10 -0
  8. package/dist/adapters/next/index.d.mts +7 -0
  9. package/dist/adapters/next/index.d.ts +7 -0
  10. package/dist/adapters/next/index.mjs +10 -0
  11. package/dist/adapters/node/index.d.mts +14 -0
  12. package/dist/adapters/node/index.d.ts +14 -0
  13. package/dist/adapters/node/index.mjs +29 -0
  14. package/dist/adapters/standard/index.d.mts +24 -0
  15. package/dist/adapters/standard/index.d.ts +24 -0
  16. package/dist/adapters/standard/index.mjs +7 -0
  17. package/dist/index.d.mts +169 -0
  18. package/dist/index.d.ts +169 -0
  19. package/dist/{index.js → index.mjs} +271 -106
  20. package/dist/shared/openapi.BHG_gu5Z.mjs +8 -0
  21. package/dist/shared/openapi.CDsfPHgw.mjs +148 -0
  22. package/dist/shared/openapi.D0VMNR6V.mjs +25 -0
  23. package/dist/shared/openapi.Dz_6xooR.d.mts +7 -0
  24. package/dist/shared/openapi.Dz_6xooR.d.ts +7 -0
  25. package/package.json +35 -28
  26. package/dist/chunk-KNYXLM77.js +0 -107
  27. package/dist/chunk-WNX6GP4X.js +0 -652
  28. package/dist/fetch.js +0 -46
  29. package/dist/node.js +0 -46
  30. package/dist/src/adapters/fetch/bracket-notation.d.ts +0 -84
  31. package/dist/src/adapters/fetch/index.d.ts +0 -10
  32. package/dist/src/adapters/fetch/input-structure-compact.d.ts +0 -6
  33. package/dist/src/adapters/fetch/input-structure-detailed.d.ts +0 -11
  34. package/dist/src/adapters/fetch/openapi-handler-server.d.ts +0 -7
  35. package/dist/src/adapters/fetch/openapi-handler-serverless.d.ts +0 -7
  36. package/dist/src/adapters/fetch/openapi-handler.d.ts +0 -33
  37. package/dist/src/adapters/fetch/openapi-payload-codec.d.ts +0 -15
  38. package/dist/src/adapters/fetch/openapi-procedure-matcher.d.ts +0 -19
  39. package/dist/src/adapters/fetch/schema-coercer.d.ts +0 -10
  40. package/dist/src/adapters/node/index.d.ts +0 -5
  41. package/dist/src/adapters/node/openapi-handler-server.d.ts +0 -7
  42. package/dist/src/adapters/node/openapi-handler-serverless.d.ts +0 -7
  43. package/dist/src/adapters/node/openapi-handler.d.ts +0 -12
  44. package/dist/src/adapters/node/types.d.ts +0 -2
  45. package/dist/src/index.d.ts +0 -12
  46. package/dist/src/json-serializer.d.ts +0 -5
  47. package/dist/src/openapi-content-builder.d.ts +0 -10
  48. package/dist/src/openapi-error.d.ts +0 -3
  49. package/dist/src/openapi-generator.d.ts +0 -60
  50. package/dist/src/openapi-input-structure-parser.d.ts +0 -22
  51. package/dist/src/openapi-output-structure-parser.d.ts +0 -18
  52. package/dist/src/openapi-parameters-builder.d.ts +0 -12
  53. package/dist/src/openapi-path-parser.d.ts +0 -8
  54. package/dist/src/openapi.d.ts +0 -3
  55. package/dist/src/schema-converter.d.ts +0 -16
  56. package/dist/src/schema-utils.d.ts +0 -11
  57. package/dist/src/schema.d.ts +0 -12
  58. package/dist/src/utils.d.ts +0 -18
@@ -1,16 +1,61 @@
1
- import {
2
- JSONSerializer,
3
- forEachAllContractProcedure,
4
- forEachContractProcedure,
5
- standardizeHTTPPath
6
- } from "./chunk-KNYXLM77.js";
1
+ import { isProcedure, eachAllContractProcedure } from '@orpc/server';
2
+ import { OpenApiBuilder } from 'openapi3-ts/oas31';
3
+ export { OpenApiBuilder } from 'openapi3-ts/oas31';
4
+ import { findDeepMatches, isObject, get, omit, group } from '@orpc/shared';
5
+ import { fallbackORPCErrorStatus } from '@orpc/client';
6
+ import { fallbackContractConfig, getEventIteratorSchemaDetails } from '@orpc/contract';
7
+ import { OpenAPIJsonSerializer } from '@orpc/openapi-client/standard';
8
+ import * as draft202012 from 'json-schema-typed/draft-2020-12';
9
+ export { draft202012 as JSONSchema };
10
+ export { Format as JSONSchemaFormat } from 'json-schema-typed/draft-2020-12';
11
+ import { t as toOpenAPI31RoutePattern } from './shared/openapi.BHG_gu5Z.mjs';
12
+ export { s as standardizeHTTPPath } from './shared/openapi.BHG_gu5Z.mjs';
7
13
 
8
- // src/openapi.ts
9
- import { OpenApiBuilder } from "openapi3-ts/oas31";
14
+ const OPERATION_EXTENDER_SYMBOL = Symbol("ORPC_OPERATION_EXTENDER");
15
+ function setOperationExtender(o, extend) {
16
+ return new Proxy(o, {
17
+ get(target, prop, receiver) {
18
+ if (prop === OPERATION_EXTENDER_SYMBOL) {
19
+ return extend;
20
+ }
21
+ return Reflect.get(target, prop, receiver);
22
+ }
23
+ });
24
+ }
25
+ function getOperationExtender(o) {
26
+ return o[OPERATION_EXTENDER_SYMBOL];
27
+ }
28
+ function extendOperation(operation, procedure) {
29
+ const operationExtenders = [];
30
+ for (const errorItem of Object.values(procedure["~orpc"].errorMap)) {
31
+ const maybeExtender = getOperationExtender(errorItem);
32
+ if (maybeExtender) {
33
+ operationExtenders.push(maybeExtender);
34
+ }
35
+ }
36
+ if (isProcedure(procedure)) {
37
+ for (const middleware of procedure["~orpc"].middlewares) {
38
+ const maybeExtender = getOperationExtender(middleware);
39
+ if (maybeExtender) {
40
+ operationExtenders.push(maybeExtender);
41
+ }
42
+ }
43
+ }
44
+ let currentOperation = operation;
45
+ for (const extender of operationExtenders) {
46
+ if (typeof extender === "function") {
47
+ currentOperation = extender(currentOperation, procedure);
48
+ } else {
49
+ currentOperation = {
50
+ ...currentOperation,
51
+ ...extender
52
+ };
53
+ }
54
+ }
55
+ return currentOperation;
56
+ }
10
57
 
11
- // src/openapi-content-builder.ts
12
- import { findDeepMatches } from "@orpc/shared";
13
- var OpenAPIContentBuilder = class {
58
+ class OpenAPIContentBuilder {
14
59
  constructor(schemaUtils) {
15
60
  this.schemaUtils = schemaUtils;
16
61
  }
@@ -33,26 +78,20 @@ var OpenAPIContentBuilder = class {
33
78
  }
34
79
  return content;
35
80
  }
36
- };
81
+ }
37
82
 
38
- // src/openapi-generator.ts
39
- import { fallbackToGlobalConfig as fallbackToGlobalConfig2 } from "@orpc/contract";
83
+ class OpenAPIError extends Error {
84
+ }
40
85
 
41
- // src/openapi-error.ts
42
- var OpenAPIError = class extends Error {
43
- };
44
-
45
- // src/openapi-input-structure-parser.ts
46
- import { fallbackToGlobalConfig } from "@orpc/contract";
47
- var OpenAPIInputStructureParser = class {
86
+ class OpenAPIInputStructureParser {
48
87
  constructor(schemaConverter, schemaUtils, pathParser) {
49
88
  this.schemaConverter = schemaConverter;
50
89
  this.schemaUtils = schemaUtils;
51
90
  this.pathParser = pathParser;
52
91
  }
53
92
  parse(contract, structure) {
54
- const inputSchema = this.schemaConverter.convert(contract["~orpc"].InputSchema, { strategy: "input" });
55
- const method = fallbackToGlobalConfig("defaultMethod", contract["~orpc"].route?.method);
93
+ const inputSchema = this.schemaConverter.convert(contract["~orpc"].inputSchema, { strategy: "input" });
94
+ const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route?.method);
56
95
  const httpPath = contract["~orpc"].route?.path;
57
96
  if (this.schemaUtils.isAnySchema(inputSchema)) {
58
97
  return {
@@ -135,16 +174,15 @@ var OpenAPIInputStructureParser = class {
135
174
  bodySchema: method !== "GET" ? rest : void 0
136
175
  };
137
176
  }
138
- };
177
+ }
139
178
 
140
- // src/openapi-output-structure-parser.ts
141
- var OpenAPIOutputStructureParser = class {
179
+ class OpenAPIOutputStructureParser {
142
180
  constructor(schemaConverter, schemaUtils) {
143
181
  this.schemaConverter = schemaConverter;
144
182
  this.schemaUtils = schemaUtils;
145
183
  }
146
184
  parse(contract, structure) {
147
- const outputSchema = this.schemaConverter.convert(contract["~orpc"].OutputSchema, { strategy: "output" });
185
+ const outputSchema = this.schemaConverter.convert(contract["~orpc"].outputSchema, { strategy: "output" });
148
186
  if (this.schemaUtils.isAnySchema(outputSchema)) {
149
187
  return {
150
188
  headersSchema: void 0,
@@ -180,17 +218,15 @@ var OpenAPIOutputStructureParser = class {
180
218
  bodySchema: outputSchema
181
219
  };
182
220
  }
183
- };
221
+ }
184
222
 
185
- // src/openapi-parameters-builder.ts
186
- import { get, isPlainObject, omit } from "@orpc/shared";
187
- var OpenAPIParametersBuilder = class {
223
+ class OpenAPIParametersBuilder {
188
224
  build(paramIn, jsonSchema, options) {
189
225
  const parameters = [];
190
226
  for (const name in jsonSchema.properties) {
191
227
  const schema = jsonSchema.properties[name];
192
228
  const paramExamples = jsonSchema.examples?.filter((example) => {
193
- return isPlainObject(example) && name in example;
229
+ return isObject(example) && name in example;
194
230
  }).map((example) => {
195
231
  return example[name];
196
232
  });
@@ -218,10 +254,9 @@ var OpenAPIParametersBuilder = class {
218
254
  }
219
255
  return headersObject;
220
256
  }
221
- };
257
+ }
222
258
 
223
- // src/openapi-path-parser.ts
224
- var OpenAPIPathParser = class {
259
+ class OpenAPIPathParser {
225
260
  parseDynamicParams(path) {
226
261
  const raws = path.match(/\{([^}]+)\}/g) ?? [];
227
262
  return raws.map((raw) => {
@@ -229,10 +264,9 @@ var OpenAPIPathParser = class {
229
264
  return { name, raw };
230
265
  });
231
266
  }
232
- };
267
+ }
233
268
 
234
- // src/schema-converter.ts
235
- var CompositeSchemaConverter = class {
269
+ class CompositeSchemaConverter {
236
270
  converters;
237
271
  constructor(converters) {
238
272
  this.converters = converters;
@@ -248,15 +282,9 @@ var CompositeSchemaConverter = class {
248
282
  }
249
283
  return {};
250
284
  }
251
- };
252
-
253
- // src/schema-utils.ts
254
- import { isPlainObject as isPlainObject2 } from "@orpc/shared";
285
+ }
255
286
 
256
- // src/schema.ts
257
- import * as JSONSchema from "json-schema-typed/draft-2020-12";
258
- import { Format } from "json-schema-typed/draft-2020-12";
259
- var NON_LOGIC_KEYWORDS = [
287
+ const NON_LOGIC_KEYWORDS = [
260
288
  // Core Documentation Keywords
261
289
  "$anchor",
262
290
  "$comment",
@@ -284,23 +312,22 @@ var NON_LOGIC_KEYWORDS = [
284
312
  "$dynamicRef"
285
313
  ];
286
314
 
287
- // src/schema-utils.ts
288
- var SchemaUtils = class {
315
+ class SchemaUtils {
289
316
  isFileSchema(schema) {
290
- return typeof schema === "object" && schema.type === "string" && typeof schema.contentMediaType === "string";
317
+ return isObject(schema) && schema.type === "string" && typeof schema.contentMediaType === "string";
291
318
  }
292
319
  isObjectSchema(schema) {
293
- return typeof schema === "object" && schema.type === "object";
320
+ return isObject(schema) && schema.type === "object";
294
321
  }
295
322
  isAnySchema(schema) {
296
- return schema === true || Object.keys(schema).length === 0;
323
+ return schema === true || Object.keys(schema).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
297
324
  }
298
325
  isUndefinableSchema(schema) {
299
326
  const [matches] = this.filterSchemaBranches(schema, (schema2) => {
300
327
  if (typeof schema2 === "boolean") {
301
328
  return schema2;
302
329
  }
303
- return Object.keys(schema2).length === 0;
330
+ return Object.keys(schema2).filter((key) => !NON_LOGIC_KEYWORDS.includes(key)).length === 0;
304
331
  });
305
332
  return matches.length > 0;
306
333
  }
@@ -313,7 +340,7 @@ var SchemaUtils = class {
313
340
  }, {});
314
341
  matched.required = schema.required?.filter((key) => separatedProperties.includes(key));
315
342
  matched.examples = schema.examples?.map((example) => {
316
- if (!isPlainObject2(example)) {
343
+ if (!isObject(example)) {
317
344
  return example;
318
345
  }
319
346
  return Object.entries(example).reduce((acc, [key, value]) => {
@@ -329,7 +356,7 @@ var SchemaUtils = class {
329
356
  }, {});
330
357
  rest.required = schema.required?.filter((key) => !separatedProperties.includes(key));
331
358
  rest.examples = schema.examples?.map((example) => {
332
- if (!isPlainObject2(example)) {
359
+ if (!isObject(example)) {
333
360
  return example;
334
361
  }
335
362
  return Object.entries(example).reduce((acc, [key, value]) => {
@@ -369,10 +396,9 @@ var SchemaUtils = class {
369
396
  }
370
397
  return [matches, schema];
371
398
  }
372
- };
399
+ }
373
400
 
374
- // src/openapi-generator.ts
375
- var OpenAPIGenerator = class {
401
+ class OpenAPIGenerator {
376
402
  contentBuilder;
377
403
  parametersBuilder;
378
404
  schemaConverter;
@@ -384,11 +410,12 @@ var OpenAPIGenerator = class {
384
410
  errorHandlerStrategy;
385
411
  ignoreUndefinedPathProcedures;
386
412
  considerMissingTagDefinitionAsError;
413
+ strictErrorResponses;
387
414
  constructor(options) {
388
415
  this.parametersBuilder = options?.parametersBuilder ?? new OpenAPIParametersBuilder();
389
416
  this.schemaConverter = new CompositeSchemaConverter(options?.schemaConverters ?? []);
390
417
  this.schemaUtils = options?.schemaUtils ?? new SchemaUtils();
391
- this.jsonSerializer = options?.jsonSerializer ?? new JSONSerializer();
418
+ this.jsonSerializer = options?.jsonSerializer ?? new OpenAPIJsonSerializer();
392
419
  this.contentBuilder = options?.contentBuilder ?? new OpenAPIContentBuilder(this.schemaUtils);
393
420
  this.pathParser = new OpenAPIPathParser();
394
421
  this.inputStructureParser = options?.inputStructureParser ?? new OpenAPIInputStructureParser(this.schemaConverter, this.schemaUtils, this.pathParser);
@@ -396,6 +423,7 @@ var OpenAPIGenerator = class {
396
423
  this.errorHandlerStrategy = options?.errorHandlerStrategy ?? "throw";
397
424
  this.ignoreUndefinedPathProcedures = options?.ignoreUndefinedPathProcedures ?? false;
398
425
  this.considerMissingTagDefinitionAsError = options?.considerMissingTagDefinitionAsError ?? false;
426
+ this.strictErrorResponses = options?.strictErrorResponses ?? true;
399
427
  }
400
428
  async generate(router, doc) {
401
429
  const builder = new OpenApiBuilder({
@@ -403,37 +431,186 @@ var OpenAPIGenerator = class {
403
431
  openapi: "3.1.1"
404
432
  });
405
433
  const rootTags = doc.tags?.map((tag) => tag.name) ?? [];
406
- await forEachAllContractProcedure(router, ({ contract, path }) => {
434
+ await eachAllContractProcedure({
435
+ path: [],
436
+ router
437
+ }, ({ contract, path }) => {
407
438
  try {
408
439
  const def = contract["~orpc"];
409
440
  if (this.ignoreUndefinedPathProcedures && def.route?.path === void 0) {
410
441
  return;
411
442
  }
412
- const method = fallbackToGlobalConfig2("defaultMethod", def.route?.method);
413
- const httpPath = def.route?.path ? standardizeHTTPPath(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
414
- const inputStructure = fallbackToGlobalConfig2("defaultInputStructure", def.route?.inputStructure);
415
- const outputStructure = fallbackToGlobalConfig2("defaultOutputStructure", def.route?.outputStructure);
416
- const { paramsSchema, querySchema, headersSchema, bodySchema } = this.inputStructureParser.parse(contract, inputStructure);
417
- const { headersSchema: resHeadersSchema, bodySchema: resBodySchema } = this.outputStructureParser.parse(contract, outputStructure);
418
- const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
419
- required: true
420
- }) : [];
421
- const query = querySchema ? this.parametersBuilder.build("query", querySchema) : [];
422
- const headers = headersSchema ? this.parametersBuilder.build("header", headersSchema) : [];
423
- const parameters = [...params, ...query, ...headers];
424
- const requestBody = bodySchema !== void 0 ? {
425
- required: this.schemaUtils.isUndefinableSchema(bodySchema),
426
- content: this.contentBuilder.build(bodySchema)
427
- } : void 0;
428
- const successResponse = {
429
- description: fallbackToGlobalConfig2("defaultSuccessDescription", def.route?.successDescription),
430
- content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema, {
431
- example: def.outputExample
432
- }) : void 0,
433
- headers: resHeadersSchema !== void 0 ? this.parametersBuilder.buildHeadersObject(resHeadersSchema, {
434
- example: def.outputExample
435
- }) : void 0
436
- };
443
+ const method = fallbackContractConfig("defaultMethod", def.route?.method);
444
+ const httpPath = def.route?.path ? toOpenAPI31RoutePattern(def.route?.path) : `/${path.map(encodeURIComponent).join("/")}`;
445
+ const { parameters, requestBody } = (() => {
446
+ const eventIteratorSchemaDetails = getEventIteratorSchemaDetails(def.inputSchema);
447
+ if (eventIteratorSchemaDetails) {
448
+ const requestBody3 = {
449
+ required: true,
450
+ content: {
451
+ "text/event-stream": {
452
+ schema: {
453
+ oneOf: [
454
+ {
455
+ type: "object",
456
+ properties: {
457
+ event: { type: "string", const: "message" },
458
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.yields, { strategy: "input" }),
459
+ id: { type: "string" },
460
+ retry: { type: "number" }
461
+ },
462
+ required: ["event", "data"]
463
+ },
464
+ {
465
+ type: "object",
466
+ properties: {
467
+ event: { type: "string", const: "done" },
468
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.returns, { strategy: "input" }),
469
+ id: { type: "string" },
470
+ retry: { type: "number" }
471
+ },
472
+ required: ["event", "data"]
473
+ },
474
+ {
475
+ type: "object",
476
+ properties: {
477
+ event: { type: "string", const: "error" },
478
+ data: {},
479
+ id: { type: "string" },
480
+ retry: { type: "number" }
481
+ },
482
+ required: ["event", "data"]
483
+ }
484
+ ]
485
+ }
486
+ }
487
+ }
488
+ };
489
+ return { requestBody: requestBody3, parameters: [] };
490
+ }
491
+ const inputStructure = fallbackContractConfig("defaultInputStructure", def.route?.inputStructure);
492
+ const { paramsSchema, querySchema, headersSchema, bodySchema } = this.inputStructureParser.parse(contract, inputStructure);
493
+ const params = paramsSchema ? this.parametersBuilder.build("path", paramsSchema, {
494
+ required: true
495
+ }) : [];
496
+ const query = querySchema ? this.parametersBuilder.build("query", querySchema) : [];
497
+ const headers = headersSchema ? this.parametersBuilder.build("header", headersSchema) : [];
498
+ const parameters2 = [...params, ...query, ...headers];
499
+ const requestBody2 = bodySchema !== void 0 ? {
500
+ required: this.schemaUtils.isUndefinableSchema(bodySchema),
501
+ content: this.contentBuilder.build(bodySchema)
502
+ } : void 0;
503
+ return { parameters: parameters2, requestBody: requestBody2 };
504
+ })();
505
+ const { responses } = (() => {
506
+ const eventIteratorSchemaDetails = getEventIteratorSchemaDetails(def.outputSchema);
507
+ if (eventIteratorSchemaDetails) {
508
+ const responses3 = {};
509
+ responses3[fallbackContractConfig("defaultSuccessStatus", def.route?.successStatus)] = {
510
+ description: fallbackContractConfig("defaultSuccessDescription", def.route?.successDescription),
511
+ content: {
512
+ "text/event-stream": {
513
+ schema: {
514
+ oneOf: [
515
+ {
516
+ type: "object",
517
+ properties: {
518
+ event: { type: "string", const: "message" },
519
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.yields, { strategy: "input" }),
520
+ id: { type: "string" },
521
+ retry: { type: "number" }
522
+ },
523
+ required: ["event", "data"]
524
+ },
525
+ {
526
+ type: "object",
527
+ properties: {
528
+ event: { type: "string", const: "done" },
529
+ data: this.schemaConverter.convert(eventIteratorSchemaDetails.returns, { strategy: "input" }),
530
+ id: { type: "string" },
531
+ retry: { type: "number" }
532
+ },
533
+ required: ["event", "data"]
534
+ },
535
+ {
536
+ type: "object",
537
+ properties: {
538
+ event: { type: "string", const: "error" },
539
+ data: {},
540
+ id: { type: "string" },
541
+ retry: { type: "number" }
542
+ },
543
+ required: ["event", "data"]
544
+ }
545
+ ]
546
+ }
547
+ }
548
+ }
549
+ };
550
+ return { responses: responses3 };
551
+ }
552
+ const outputStructure = fallbackContractConfig("defaultOutputStructure", def.route?.outputStructure);
553
+ const { headersSchema: resHeadersSchema, bodySchema: resBodySchema } = this.outputStructureParser.parse(contract, outputStructure);
554
+ const responses2 = {};
555
+ responses2[fallbackContractConfig("defaultSuccessStatus", def.route?.successStatus)] = {
556
+ description: fallbackContractConfig("defaultSuccessDescription", def.route?.successDescription),
557
+ content: resBodySchema !== void 0 ? this.contentBuilder.build(resBodySchema) : void 0,
558
+ headers: resHeadersSchema !== void 0 ? this.parametersBuilder.buildHeadersObject(resHeadersSchema) : void 0
559
+ };
560
+ return { responses: responses2 };
561
+ })();
562
+ const errors = group(Object.entries(def.errorMap ?? {}).filter(([_, config]) => config).map(([code, config]) => ({
563
+ ...config,
564
+ code,
565
+ status: fallbackORPCErrorStatus(code, config?.status)
566
+ })), (error) => error.status);
567
+ for (const status in errors) {
568
+ const configs = errors[status];
569
+ if (!configs || configs.length === 0) {
570
+ continue;
571
+ }
572
+ const schemas = configs.map(({ data, code, message }) => {
573
+ const json = {
574
+ type: "object",
575
+ properties: {
576
+ defined: { const: true },
577
+ code: { const: code },
578
+ status: { const: Number(status) },
579
+ message: { type: "string", default: message },
580
+ data: {}
581
+ },
582
+ required: ["defined", "code", "status", "message"]
583
+ };
584
+ if (data) {
585
+ const dataJson = this.schemaConverter.convert(data, { strategy: "output" });
586
+ json.properties.data = dataJson;
587
+ if (!this.schemaUtils.isUndefinableSchema(dataJson)) {
588
+ json.required.push("data");
589
+ }
590
+ }
591
+ return json;
592
+ });
593
+ if (this.strictErrorResponses) {
594
+ schemas.push({
595
+ type: "object",
596
+ properties: {
597
+ defined: { const: false },
598
+ code: { type: "string" },
599
+ status: { type: "number" },
600
+ message: { type: "string" },
601
+ data: {}
602
+ },
603
+ required: ["defined", "code", "status", "message"]
604
+ });
605
+ }
606
+ const contentSchema = schemas.length === 1 ? schemas[0] : {
607
+ oneOf: schemas
608
+ };
609
+ responses[status] = {
610
+ description: status,
611
+ content: this.contentBuilder.build(contentSchema)
612
+ };
613
+ }
437
614
  if (this.considerMissingTagDefinitionAsError && def.route?.tags) {
438
615
  const missingTag = def.route?.tags.find((tag) => !rootTags.includes(tag));
439
616
  if (missingTag !== void 0) {
@@ -450,12 +627,11 @@ var OpenAPIGenerator = class {
450
627
  operationId: path.join("."),
451
628
  parameters: parameters.length ? parameters : void 0,
452
629
  requestBody,
453
- responses: {
454
- [fallbackToGlobalConfig2("defaultSuccessStatus", def.route?.successStatus)]: successResponse
455
- }
630
+ responses
456
631
  };
632
+ const extendedOperation = extendOperation(operation, contract);
457
633
  builder.addPath(httpPath, {
458
- [method.toLocaleLowerCase()]: operation
634
+ [method.toLocaleLowerCase()]: extendedOperation
459
635
  });
460
636
  } catch (e) {
461
637
  if (e instanceof OpenAPIError) {
@@ -474,23 +650,12 @@ var OpenAPIGenerator = class {
474
650
  }
475
651
  }
476
652
  });
477
- return this.jsonSerializer.serialize(builder.getSpec());
653
+ return this.jsonSerializer.serialize(builder.getSpec())[0];
478
654
  }
655
+ }
656
+
657
+ const oo = {
658
+ spec: setOperationExtender
479
659
  };
480
- export {
481
- CompositeSchemaConverter,
482
- JSONSchema,
483
- Format as JSONSchemaFormat,
484
- JSONSerializer,
485
- NON_LOGIC_KEYWORDS,
486
- OpenAPIContentBuilder,
487
- OpenAPIGenerator,
488
- OpenAPIParametersBuilder,
489
- OpenAPIPathParser,
490
- OpenApiBuilder,
491
- SchemaUtils,
492
- forEachAllContractProcedure,
493
- forEachContractProcedure,
494
- standardizeHTTPPath
495
- };
496
- //# sourceMappingURL=index.js.map
660
+
661
+ export { CompositeSchemaConverter, NON_LOGIC_KEYWORDS, OpenAPIContentBuilder, OpenAPIGenerator, OpenAPIParametersBuilder, OpenAPIPathParser, SchemaUtils, extendOperation, getOperationExtender, oo, setOperationExtender, toOpenAPI31RoutePattern };
@@ -0,0 +1,8 @@
1
+ function standardizeHTTPPath(path) {
2
+ return `/${path.replace(/\/{2,}/g, "/").replace(/^\/|\/$/g, "")}`;
3
+ }
4
+ function toOpenAPI31RoutePattern(path) {
5
+ return standardizeHTTPPath(path).replace(/\{\+([^}]+)\}/g, "{$1}");
6
+ }
7
+
8
+ export { standardizeHTTPPath as s, toOpenAPI31RoutePattern as t };
@@ -0,0 +1,148 @@
1
+ import { fallbackContractConfig } from '@orpc/contract';
2
+ import { OpenAPISerializer } from '@orpc/openapi-client/standard';
3
+ import { isObject } from '@orpc/shared';
4
+ import { eachContractProcedure, convertPathToHttpPath, isProcedure, getLazyRouterPrefix, unlazy, getRouterChild, createContractedProcedure } from '@orpc/server';
5
+ import { createRouter, addRoute, findRoute } from 'rou3';
6
+ import { s as standardizeHTTPPath } from './openapi.BHG_gu5Z.mjs';
7
+
8
+ class OpenAPICodec {
9
+ constructor(serializer = new OpenAPISerializer()) {
10
+ this.serializer = serializer;
11
+ }
12
+ async decode(request, params, procedure) {
13
+ const inputStructure = fallbackContractConfig("defaultInputStructure", procedure["~orpc"].route.inputStructure);
14
+ if (inputStructure === "compact") {
15
+ const data = request.method === "GET" ? this.serializer.deserialize(request.url.searchParams) : this.serializer.deserialize(await request.body());
16
+ if (data === void 0) {
17
+ return params;
18
+ }
19
+ if (isObject(data)) {
20
+ return {
21
+ ...params,
22
+ ...data
23
+ };
24
+ }
25
+ return data;
26
+ }
27
+ const deserializeSearchParams = () => {
28
+ return this.serializer.deserialize(request.url.searchParams);
29
+ };
30
+ return {
31
+ params,
32
+ get query() {
33
+ const value = deserializeSearchParams();
34
+ Object.defineProperty(this, "query", { value, writable: true });
35
+ return value;
36
+ },
37
+ set query(value) {
38
+ Object.defineProperty(this, "query", { value, writable: true });
39
+ },
40
+ headers: request.headers,
41
+ body: this.serializer.deserialize(await request.body())
42
+ };
43
+ }
44
+ encode(output, procedure) {
45
+ const successStatus = fallbackContractConfig("defaultSuccessStatus", procedure["~orpc"].route.successStatus);
46
+ const outputStructure = fallbackContractConfig("defaultOutputStructure", procedure["~orpc"].route.outputStructure);
47
+ if (outputStructure === "compact") {
48
+ return {
49
+ status: successStatus,
50
+ headers: {},
51
+ body: this.serializer.serialize(output)
52
+ };
53
+ }
54
+ if (!isObject(output)) {
55
+ throw new Error(
56
+ 'Invalid output structure for "detailed" output. Expected format: { body: any, headers?: Record<string, string | string[] | undefined> }'
57
+ );
58
+ }
59
+ return {
60
+ status: successStatus,
61
+ headers: output.headers ?? {},
62
+ body: this.serializer.serialize(output.body)
63
+ };
64
+ }
65
+ encodeError(error) {
66
+ return {
67
+ status: error.status,
68
+ headers: {},
69
+ body: this.serializer.serialize(error.toJSON())
70
+ };
71
+ }
72
+ }
73
+
74
+ class OpenAPIMatcher {
75
+ tree = createRouter();
76
+ pendingRouters = [];
77
+ init(router, path = []) {
78
+ const laziedOptions = eachContractProcedure({
79
+ router,
80
+ path
81
+ }, ({ path: path2, contract }) => {
82
+ const method = fallbackContractConfig("defaultMethod", contract["~orpc"].route.method);
83
+ const httpPath = contract["~orpc"].route.path ? toRou3Pattern(contract["~orpc"].route.path) : convertPathToHttpPath(path2);
84
+ if (isProcedure(contract)) {
85
+ addRoute(this.tree, method, httpPath, {
86
+ path: path2,
87
+ contract,
88
+ procedure: contract,
89
+ // this mean dev not used contract-first so we can used contract as procedure directly
90
+ router
91
+ });
92
+ } else {
93
+ addRoute(this.tree, method, httpPath, {
94
+ path: path2,
95
+ contract,
96
+ procedure: void 0,
97
+ router
98
+ });
99
+ }
100
+ });
101
+ this.pendingRouters.push(...laziedOptions.map((option) => ({
102
+ ...option,
103
+ httpPathPrefix: convertPathToHttpPath(option.path),
104
+ laziedPrefix: getLazyRouterPrefix(option.lazied)
105
+ })));
106
+ }
107
+ async match(method, pathname) {
108
+ if (this.pendingRouters.length) {
109
+ const newPendingRouters = [];
110
+ for (const pendingRouter of this.pendingRouters) {
111
+ if (!pendingRouter.laziedPrefix || pathname.startsWith(pendingRouter.laziedPrefix) || pathname.startsWith(pendingRouter.httpPathPrefix)) {
112
+ const { default: router } = await unlazy(pendingRouter.lazied);
113
+ this.init(router, pendingRouter.path);
114
+ } else {
115
+ newPendingRouters.push(pendingRouter);
116
+ }
117
+ }
118
+ this.pendingRouters = newPendingRouters;
119
+ }
120
+ const match = findRoute(this.tree, method, pathname);
121
+ if (!match) {
122
+ return void 0;
123
+ }
124
+ if (!match.data.procedure) {
125
+ const { default: maybeProcedure } = await unlazy(getRouterChild(match.data.router, ...match.data.path));
126
+ if (!isProcedure(maybeProcedure)) {
127
+ throw new Error(`
128
+ [Contract-First] Missing or invalid implementation for procedure at path: ${convertPathToHttpPath(match.data.path)}.
129
+ Ensure that the procedure is correctly defined and matches the expected contract.
130
+ `);
131
+ }
132
+ match.data.procedure = createContractedProcedure(match.data.contract, maybeProcedure);
133
+ }
134
+ return {
135
+ path: match.data.path,
136
+ procedure: match.data.procedure,
137
+ params: match.params ? decodeParams(match.params) : void 0
138
+ };
139
+ }
140
+ }
141
+ function toRou3Pattern(path) {
142
+ return standardizeHTTPPath(path).replace(/\{\+([^}]+)\}/g, "**:$1").replace(/\{([^}]+)\}/g, ":$1");
143
+ }
144
+ function decodeParams(params) {
145
+ return Object.fromEntries(Object.entries(params).map(([key, value]) => [key, decodeURIComponent(value)]));
146
+ }
147
+
148
+ export { OpenAPICodec as O, OpenAPIMatcher as a };