@orpc/openapi 0.0.0-next.3636544 → 0.0.0-next.36cf381

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 (31) hide show
  1. package/README.md +134 -14
  2. package/dist/adapters/aws-lambda/index.d.mts +4 -3
  3. package/dist/adapters/aws-lambda/index.d.ts +4 -3
  4. package/dist/adapters/aws-lambda/index.mjs +3 -3
  5. package/dist/adapters/fastify/index.d.mts +23 -0
  6. package/dist/adapters/fastify/index.d.ts +23 -0
  7. package/dist/adapters/fastify/index.mjs +18 -0
  8. package/dist/adapters/fetch/index.d.mts +9 -5
  9. package/dist/adapters/fetch/index.d.ts +9 -5
  10. package/dist/adapters/fetch/index.mjs +3 -3
  11. package/dist/adapters/node/index.d.mts +9 -5
  12. package/dist/adapters/node/index.d.ts +9 -5
  13. package/dist/adapters/node/index.mjs +3 -3
  14. package/dist/adapters/standard/index.d.mts +7 -16
  15. package/dist/adapters/standard/index.d.ts +7 -16
  16. package/dist/adapters/standard/index.mjs +1 -1
  17. package/dist/index.d.mts +10 -3
  18. package/dist/index.d.ts +10 -3
  19. package/dist/index.mjs +2 -2
  20. package/dist/plugins/index.d.mts +20 -3
  21. package/dist/plugins/index.d.ts +20 -3
  22. package/dist/plugins/index.mjs +69 -20
  23. package/dist/shared/{openapi.BkBlt1Qf.mjs → openapi.BB-W-NKv.mjs} +22 -5
  24. package/dist/shared/{openapi.DPAN3GVs.d.mts → openapi.BGy4N6eR.d.mts} +15 -3
  25. package/dist/shared/{openapi.DPAN3GVs.d.ts → openapi.BGy4N6eR.d.ts} +15 -3
  26. package/dist/shared/{openapi.BtoY8ZFF.mjs → openapi.BwdtJjDu.mjs} +185 -49
  27. package/dist/shared/openapi.DwaweYRb.d.mts +54 -0
  28. package/dist/shared/openapi.DwaweYRb.d.ts +54 -0
  29. package/package.json +20 -13
  30. package/dist/shared/openapi.CQmjvnb0.d.mts +0 -31
  31. package/dist/shared/openapi.CQmjvnb0.d.ts +0 -31
@@ -108,22 +108,47 @@ function isAnySchema(schema) {
108
108
  if (schema === true) {
109
109
  return true;
110
110
  }
111
- if (Object.keys(schema).every((k) => !LOGIC_KEYWORDS.includes(k))) {
111
+ if (Object.keys(schema).filter((v) => schema[v] !== void 0).every((k) => !LOGIC_KEYWORDS.includes(k))) {
112
112
  return true;
113
113
  }
114
114
  return false;
115
115
  }
116
+ function isNeverSchema(schema) {
117
+ if (schema === false) {
118
+ return true;
119
+ }
120
+ if (typeof schema === "object" && schema.not !== void 0) {
121
+ if (schema.not === true) {
122
+ return true;
123
+ }
124
+ if (typeof schema.not === "object" && Object.keys(schema.not).length === 0) {
125
+ return true;
126
+ }
127
+ }
128
+ return false;
129
+ }
116
130
  function separateObjectSchema(schema, separatedProperties) {
117
- if (Object.keys(schema).some((k) => k !== "type" && k !== "properties" && k !== "required" && LOGIC_KEYWORDS.includes(k))) {
131
+ if (Object.keys(schema).some(
132
+ (k) => !["type", "properties", "required", "additionalProperties"].includes(k) && LOGIC_KEYWORDS.includes(k) && schema[k] !== void 0
133
+ )) {
118
134
  return [{ type: "object" }, schema];
119
135
  }
120
136
  const matched = { ...schema };
121
137
  const rest = { ...schema };
122
- matched.properties = schema.properties && Object.entries(schema.properties).filter(([key]) => separatedProperties.includes(key)).reduce((acc, [key, value]) => {
123
- acc[key] = value;
138
+ matched.properties = separatedProperties.reduce((acc, key) => {
139
+ const keySchema = schema.properties?.[key] ?? schema.additionalProperties;
140
+ if (keySchema !== void 0) {
141
+ acc[key] = keySchema;
142
+ }
124
143
  return acc;
125
144
  }, {});
145
+ if (Object.keys(matched.properties).length === 0) {
146
+ matched.properties = void 0;
147
+ }
126
148
  matched.required = schema.required?.filter((key) => separatedProperties.includes(key));
149
+ if (matched.required?.length === 0) {
150
+ matched.required = void 0;
151
+ }
127
152
  matched.examples = schema.examples?.map((example) => {
128
153
  if (!isObject(example)) {
129
154
  return example;
@@ -135,11 +160,14 @@ function separateObjectSchema(schema, separatedProperties) {
135
160
  return acc;
136
161
  }, {});
137
162
  });
138
- rest.properties = schema.properties && Object.entries(schema.properties).filter(([key]) => !separatedProperties.includes(key)).reduce((acc, [key, value]) => {
163
+ rest.properties = schema.properties && Object.entries(schema.properties).filter(([key]) => !separatedProperties.includes(key)).reduce((acc = {}, [key, value]) => {
139
164
  acc[key] = value;
140
165
  return acc;
141
- }, {});
166
+ }, void 0);
142
167
  rest.required = schema.required?.filter((key) => !separatedProperties.includes(key));
168
+ if (rest.required?.length === 0) {
169
+ rest.required = void 0;
170
+ }
143
171
  rest.examples = schema.examples?.map((example) => {
144
172
  if (!isObject(example)) {
145
173
  return example;
@@ -250,7 +278,7 @@ function toOpenAPIContent(schema) {
250
278
  schema: toOpenAPISchema(file)
251
279
  };
252
280
  }
253
- if (restSchema !== void 0) {
281
+ if (restSchema !== void 0 && !isAnySchema(restSchema) && !isNeverSchema(restSchema)) {
254
282
  content["application/json"] = {
255
283
  schema: toOpenAPISchema(restSchema)
256
284
  };
@@ -354,6 +382,107 @@ function resolveOpenAPIJsonSchemaRef(doc, schema) {
354
382
  const resolved = doc.components?.schemas?.[name];
355
383
  return resolved ?? schema;
356
384
  }
385
+ function simplifyComposedObjectJsonSchemasAndRefs(schema, doc) {
386
+ if (doc) {
387
+ schema = resolveOpenAPIJsonSchemaRef(doc, schema);
388
+ }
389
+ if (typeof schema !== "object" || !schema.anyOf && !schema.oneOf && !schema.allOf) {
390
+ return schema;
391
+ }
392
+ const unionSchemas = [
393
+ ...toArray(schema.anyOf?.map((s) => simplifyComposedObjectJsonSchemasAndRefs(s, doc))),
394
+ ...toArray(schema.oneOf?.map((s) => simplifyComposedObjectJsonSchemasAndRefs(s, doc)))
395
+ ];
396
+ const objectUnionSchemas = [];
397
+ for (const u of unionSchemas) {
398
+ if (!isObjectSchema(u)) {
399
+ return schema;
400
+ }
401
+ objectUnionSchemas.push(u);
402
+ }
403
+ const mergedUnionPropertyMap = /* @__PURE__ */ new Map();
404
+ for (const u of objectUnionSchemas) {
405
+ if (u.properties) {
406
+ for (const [key, value] of Object.entries(u.properties)) {
407
+ let entry = mergedUnionPropertyMap.get(key);
408
+ if (!entry) {
409
+ const required = objectUnionSchemas.every((s) => s.required?.includes(key));
410
+ entry = { required, schemas: [] };
411
+ mergedUnionPropertyMap.set(key, entry);
412
+ }
413
+ entry.schemas.push(value);
414
+ }
415
+ }
416
+ }
417
+ const intersectionSchemas = toArray(schema.allOf?.map((s) => simplifyComposedObjectJsonSchemasAndRefs(s, doc)));
418
+ const objectIntersectionSchemas = [];
419
+ for (const u of intersectionSchemas) {
420
+ if (!isObjectSchema(u)) {
421
+ return schema;
422
+ }
423
+ objectIntersectionSchemas.push(u);
424
+ }
425
+ if (isObjectSchema(schema)) {
426
+ objectIntersectionSchemas.push(schema);
427
+ }
428
+ const mergedInteractionPropertyMap = /* @__PURE__ */ new Map();
429
+ for (const u of objectIntersectionSchemas) {
430
+ if (u.properties) {
431
+ for (const [key, value] of Object.entries(u.properties)) {
432
+ let entry = mergedInteractionPropertyMap.get(key);
433
+ if (!entry) {
434
+ const required = objectIntersectionSchemas.some((s) => s.required?.includes(key));
435
+ entry = { required, schemas: [] };
436
+ mergedInteractionPropertyMap.set(key, entry);
437
+ }
438
+ entry.schemas.push(value);
439
+ }
440
+ }
441
+ }
442
+ const resultObjectSchema = { type: "object", properties: {}, required: [] };
443
+ const keys = /* @__PURE__ */ new Set([
444
+ ...mergedUnionPropertyMap.keys(),
445
+ ...mergedInteractionPropertyMap.keys()
446
+ ]);
447
+ if (keys.size === 0) {
448
+ return schema;
449
+ }
450
+ const deduplicateSchemas = (schemas) => {
451
+ const seen = /* @__PURE__ */ new Set();
452
+ const result = [];
453
+ for (const schema2 of schemas) {
454
+ const key = stringifyJSON(schema2);
455
+ if (!seen.has(key)) {
456
+ seen.add(key);
457
+ result.push(schema2);
458
+ }
459
+ }
460
+ return result;
461
+ };
462
+ for (const key of keys) {
463
+ const unionEntry = mergedUnionPropertyMap.get(key);
464
+ const intersectionEntry = mergedInteractionPropertyMap.get(key);
465
+ resultObjectSchema.properties[key] = (() => {
466
+ const dedupedUnionSchemas = unionEntry ? deduplicateSchemas(unionEntry.schemas) : [];
467
+ const dedupedIntersectionSchemas = intersectionEntry ? deduplicateSchemas(intersectionEntry.schemas) : [];
468
+ if (!dedupedUnionSchemas.length) {
469
+ return dedupedIntersectionSchemas.length === 1 ? dedupedIntersectionSchemas[0] : { allOf: dedupedIntersectionSchemas };
470
+ }
471
+ if (!dedupedIntersectionSchemas.length) {
472
+ return dedupedUnionSchemas.length === 1 ? dedupedUnionSchemas[0] : { anyOf: dedupedUnionSchemas };
473
+ }
474
+ const allOf = deduplicateSchemas([
475
+ ...dedupedIntersectionSchemas,
476
+ dedupedUnionSchemas.length === 1 ? dedupedUnionSchemas[0] : { anyOf: dedupedUnionSchemas }
477
+ ]);
478
+ return allOf.length === 1 ? allOf[0] : { allOf };
479
+ })();
480
+ if (unionEntry?.required || intersectionEntry?.required) {
481
+ resultObjectSchema.required.push(key);
482
+ }
483
+ }
484
+ return resultObjectSchema;
485
+ }
357
486
 
358
487
  class CompositeSchemaConverter {
359
488
  converters;
@@ -382,21 +511,18 @@ class OpenAPIGenerator {
382
511
  /**
383
512
  * Generates OpenAPI specifications from oRPC routers/contracts.
384
513
  *
385
- * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
514
+ * @see {@link https://orpc.dev/docs/openapi/openapi-specification OpenAPI Specification Docs}
386
515
  */
387
- async generate(router, options = {}) {
388
- const filter = options.filter ?? (({ contract, path }) => {
389
- return !(options.exclude?.(contract, path) ?? false);
516
+ async generate(router, { customErrorResponseBodySchema, commonSchemas, filter: baseFilter, exclude, ...baseDoc } = {}) {
517
+ const filter = baseFilter ?? (({ contract, path }) => {
518
+ return !(exclude?.(contract, path) ?? false);
390
519
  });
391
520
  const doc = {
392
- ...clone(options),
393
- info: options.info ?? { title: "API Reference", version: "0.0.0" },
394
- openapi: "3.1.1",
395
- exclude: void 0,
396
- filter: void 0,
397
- commonSchemas: void 0
521
+ ...clone(baseDoc),
522
+ info: baseDoc.info ?? { title: "API Reference", version: "0.0.0" },
523
+ openapi: "3.1.1"
398
524
  };
399
- const { baseSchemaConvertOptions, undefinedErrorJsonSchema } = await this.#resolveCommonSchemas(doc, options.commonSchemas);
525
+ const { baseSchemaConvertOptions, undefinedErrorJsonSchema } = await this.#resolveCommonSchemas(doc, commonSchemas);
400
526
  const contracts = [];
401
527
  await resolveContractProcedures({ path: [], router }, (traverseOptions) => {
402
528
  if (!value(filter, traverseOptions)) {
@@ -406,17 +532,17 @@ class OpenAPIGenerator {
406
532
  });
407
533
  const errors = [];
408
534
  for (const { contract, path } of contracts) {
409
- const operationId = path.join(".");
535
+ const stringPath = path.join(".");
410
536
  try {
411
537
  const def = contract["~orpc"];
412
538
  const method = toOpenAPIMethod(fallbackContractConfig("defaultMethod", def.route.method));
413
539
  const httpPath = toOpenAPIPath(def.route.path ?? toHttpPath(path));
414
540
  let operationObjectRef;
415
- if (def.route.spec !== void 0) {
541
+ if (def.route.spec !== void 0 && typeof def.route.spec !== "function") {
416
542
  operationObjectRef = def.route.spec;
417
543
  } else {
418
544
  operationObjectRef = {
419
- operationId,
545
+ operationId: def.route.operationId ?? stringPath,
420
546
  summary: def.route.summary,
421
547
  description: def.route.description,
422
548
  deprecated: def.route.deprecated,
@@ -424,7 +550,10 @@ class OpenAPIGenerator {
424
550
  };
425
551
  await this.#request(doc, operationObjectRef, def, baseSchemaConvertOptions);
426
552
  await this.#successResponse(doc, operationObjectRef, def, baseSchemaConvertOptions);
427
- await this.#errorResponse(operationObjectRef, def, baseSchemaConvertOptions, undefinedErrorJsonSchema);
553
+ await this.#errorResponse(operationObjectRef, def, baseSchemaConvertOptions, undefinedErrorJsonSchema, customErrorResponseBodySchema);
554
+ }
555
+ if (typeof def.route.spec === "function") {
556
+ operationObjectRef = def.route.spec(operationObjectRef);
428
557
  }
429
558
  doc.paths ??= {};
430
559
  doc.paths[httpPath] ??= {};
@@ -434,7 +563,7 @@ class OpenAPIGenerator {
434
563
  throw e;
435
564
  }
436
565
  errors.push(
437
- `[OpenAPIGenerator] Error occurred while generating OpenAPI for procedure at path: ${operationId}
566
+ `[OpenAPIGenerator] Error occurred while generating OpenAPI for procedure at path: ${stringPath}
438
567
  ${e.message}`
439
568
  );
440
569
  }
@@ -534,13 +663,16 @@ ${errors.join("\n\n")}`
534
663
  def.inputSchema,
535
664
  {
536
665
  ...baseSchemaConvertOptions,
537
- strategy: "input",
538
- minStructureDepthForRef: dynamicParams?.length || inputStructure === "detailed" ? 1 : 0
666
+ strategy: "input"
539
667
  }
540
668
  );
669
+ let omitResponseBody = false;
541
670
  if (isAnySchema(schema) && !dynamicParams?.length) {
542
671
  return;
543
672
  }
673
+ if (inputStructure === "detailed" || inputStructure === "compact" && (dynamicParams?.length || method === "GET")) {
674
+ schema = simplifyComposedObjectJsonSchemasAndRefs(schema, doc);
675
+ }
544
676
  if (inputStructure === "compact") {
545
677
  if (dynamicParams?.length) {
546
678
  const error2 = new OpenAPIGeneratorError(
@@ -552,6 +684,7 @@ ${errors.join("\n\n")}`
552
684
  const [paramsSchema, rest] = separateObjectSchema(schema, dynamicParams);
553
685
  schema = rest;
554
686
  required = rest.required ? rest.required.length !== 0 : false;
687
+ omitResponseBody = !required && !rest.properties;
555
688
  if (!checkParamsSchema(paramsSchema, dynamicParams)) {
556
689
  throw error2;
557
690
  }
@@ -566,7 +699,7 @@ ${errors.join("\n\n")}`
566
699
  }
567
700
  ref.parameters ??= [];
568
701
  ref.parameters.push(...toOpenAPIParameters(schema, "query"));
569
- } else {
702
+ } else if (!omitResponseBody) {
570
703
  ref.requestBody = {
571
704
  required,
572
705
  content: toOpenAPIContent(schema)
@@ -580,7 +713,7 @@ ${errors.join("\n\n")}`
580
713
  if (!isObjectSchema(schema)) {
581
714
  throw error;
582
715
  }
583
- const resolvedParamSchema = schema.properties?.params !== void 0 ? resolveOpenAPIJsonSchemaRef(doc, schema.properties.params) : void 0;
716
+ const resolvedParamSchema = schema.properties?.params !== void 0 ? simplifyComposedObjectJsonSchemasAndRefs(schema.properties.params, doc) : void 0;
584
717
  if (dynamicParams?.length && (resolvedParamSchema === void 0 || !isObjectSchema(resolvedParamSchema) || !checkParamsSchema(resolvedParamSchema, dynamicParams))) {
585
718
  throw new OpenAPIGeneratorError(
586
719
  'When input structure is "detailed" and path has dynamic params, the "params" schema must be an object with all dynamic params as required.'
@@ -589,7 +722,7 @@ ${errors.join("\n\n")}`
589
722
  for (const from of ["params", "query", "headers"]) {
590
723
  const fromSchema = schema.properties?.[from];
591
724
  if (fromSchema !== void 0) {
592
- const resolvedSchema = resolveOpenAPIJsonSchemaRef(doc, fromSchema);
725
+ const resolvedSchema = simplifyComposedObjectJsonSchemasAndRefs(fromSchema, doc);
593
726
  if (!isObjectSchema(resolvedSchema)) {
594
727
  throw error;
595
728
  }
@@ -650,13 +783,14 @@ ${errors.join("\n\n")}`
650
783
 
651
784
  But got: ${stringifyJSON(item)}
652
785
  `);
653
- if (!isObjectSchema(item)) {
786
+ const simplifiedItem = simplifyComposedObjectJsonSchemasAndRefs(item, doc);
787
+ if (!isObjectSchema(simplifiedItem)) {
654
788
  throw error;
655
789
  }
656
790
  let schemaStatus;
657
791
  let schemaDescription;
658
- if (item.properties?.status !== void 0) {
659
- const statusSchema = resolveOpenAPIJsonSchemaRef(doc, item.properties.status);
792
+ if (simplifiedItem.properties?.status !== void 0) {
793
+ const statusSchema = resolveOpenAPIJsonSchemaRef(doc, simplifiedItem.properties.status);
660
794
  if (typeof statusSchema !== "object" || statusSchema.const === void 0 || typeof statusSchema.const !== "number" || !Number.isInteger(statusSchema.const) || isORPCErrorStatus(statusSchema.const)) {
661
795
  throw error;
662
796
  }
@@ -676,8 +810,8 @@ ${errors.join("\n\n")}`
676
810
  ref.responses[itemStatus] = {
677
811
  description: itemDescription
678
812
  };
679
- if (item.properties?.headers !== void 0) {
680
- const headersSchema = resolveOpenAPIJsonSchemaRef(doc, item.properties.headers);
813
+ if (simplifiedItem.properties?.headers !== void 0) {
814
+ const headersSchema = simplifyComposedObjectJsonSchemasAndRefs(simplifiedItem.properties.headers, doc);
681
815
  if (!isObjectSchema(headersSchema)) {
682
816
  throw error;
683
817
  }
@@ -687,50 +821,52 @@ ${errors.join("\n\n")}`
687
821
  ref.responses[itemStatus].headers ??= {};
688
822
  ref.responses[itemStatus].headers[key] = {
689
823
  schema: toOpenAPISchema(headerSchema),
690
- required: item.required?.includes("headers") && headersSchema.required?.includes(key)
824
+ required: simplifiedItem.required?.includes("headers") && headersSchema.required?.includes(key)
691
825
  };
692
826
  }
693
827
  }
694
828
  }
695
- if (item.properties?.body !== void 0) {
829
+ if (simplifiedItem.properties?.body !== void 0) {
696
830
  ref.responses[itemStatus].content = toOpenAPIContent(
697
- applySchemaOptionality(item.required?.includes("body") ?? false, item.properties.body)
831
+ applySchemaOptionality(simplifiedItem.required?.includes("body") ?? false, simplifiedItem.properties.body)
698
832
  );
699
833
  }
700
834
  }
701
835
  }
702
- async #errorResponse(ref, def, baseSchemaConvertOptions, undefinedErrorSchema) {
836
+ async #errorResponse(ref, def, baseSchemaConvertOptions, undefinedErrorSchema, customErrorResponseBodySchema) {
703
837
  const errorMap = def.errorMap;
704
- const errors = {};
838
+ const errorResponsesByStatus = {};
705
839
  for (const code in errorMap) {
706
840
  const config = errorMap[code];
707
841
  if (!config) {
708
842
  continue;
709
843
  }
710
844
  const status = fallbackORPCErrorStatus(code, config.status);
711
- const message = fallbackORPCErrorMessage(code, config.message);
845
+ const defaultMessage = fallbackORPCErrorMessage(code, config.message);
846
+ errorResponsesByStatus[status] ??= { status, definedErrorDefinitions: [], errorSchemaVariants: [] };
712
847
  const [dataRequired, dataSchema] = await this.converter.convert(config.data, { ...baseSchemaConvertOptions, strategy: "output" });
713
- errors[status] ??= [];
714
- errors[status].push({
848
+ errorResponsesByStatus[status].definedErrorDefinitions.push([code, defaultMessage, dataRequired, dataSchema]);
849
+ errorResponsesByStatus[status].errorSchemaVariants.push({
715
850
  type: "object",
716
851
  properties: {
717
852
  defined: { const: true },
718
853
  code: { const: code },
719
854
  status: { const: status },
720
- message: { type: "string", default: message },
855
+ message: { type: "string", default: defaultMessage },
721
856
  data: dataSchema
722
857
  },
723
858
  required: dataRequired ? ["defined", "code", "status", "message", "data"] : ["defined", "code", "status", "message"]
724
859
  });
725
860
  }
726
861
  ref.responses ??= {};
727
- for (const status in errors) {
728
- const schemas = errors[status];
729
- ref.responses[status] = {
730
- description: status,
731
- content: toOpenAPIContent({
862
+ for (const statusString in errorResponsesByStatus) {
863
+ const errorResponse = errorResponsesByStatus[statusString];
864
+ const customBodySchema = value(customErrorResponseBodySchema, errorResponse.definedErrorDefinitions, errorResponse.status);
865
+ ref.responses[statusString] = {
866
+ description: statusString,
867
+ content: toOpenAPIContent(customBodySchema ?? {
732
868
  oneOf: [
733
- ...schemas,
869
+ ...errorResponse.errorSchemaVariants,
734
870
  undefinedErrorSchema
735
871
  ]
736
872
  })
@@ -739,4 +875,4 @@ ${errors.join("\n\n")}`
739
875
  }
740
876
  }
741
877
 
742
- export { CompositeSchemaConverter as C, LOGIC_KEYWORDS as L, OpenAPIGenerator as O, applyCustomOpenAPIOperation as a, toOpenAPIMethod as b, customOpenAPIOperation as c, toOpenAPIContent as d, toOpenAPIEventIteratorContent as e, toOpenAPIParameters as f, getCustomOpenAPIOperation as g, checkParamsSchema as h, toOpenAPISchema as i, isFileSchema as j, isObjectSchema as k, isAnySchema as l, filterSchemaBranches as m, applySchemaOptionality as n, expandUnionSchema as o, expandArrayableSchema as p, isPrimitiveSchema as q, resolveOpenAPIJsonSchemaRef as r, separateObjectSchema as s, toOpenAPIPath as t };
878
+ export { CompositeSchemaConverter as C, LOGIC_KEYWORDS as L, OpenAPIGenerator as O, applyCustomOpenAPIOperation as a, toOpenAPIMethod as b, customOpenAPIOperation as c, toOpenAPIContent as d, toOpenAPIEventIteratorContent as e, toOpenAPIParameters as f, getCustomOpenAPIOperation as g, checkParamsSchema as h, toOpenAPISchema as i, isFileSchema as j, isObjectSchema as k, isAnySchema as l, isNeverSchema as m, separateObjectSchema as n, filterSchemaBranches as o, applySchemaOptionality as p, expandUnionSchema as q, resolveOpenAPIJsonSchemaRef as r, simplifyComposedObjectJsonSchemasAndRefs as s, toOpenAPIPath as t, expandArrayableSchema as u, isPrimitiveSchema as v };
@@ -0,0 +1,54 @@
1
+ import { StandardOpenAPISerializer, StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions } from '@orpc/openapi-client/standard';
2
+ import { AnyProcedure, TraverseContractProcedureCallbackOptions, AnyRouter, Context, Router } from '@orpc/server';
3
+ import { StandardCodec, StandardParams, StandardMatcher, StandardMatchResult, StandardHandlerOptions, StandardHandler } from '@orpc/server/standard';
4
+ import { ORPCError, HTTPPath } from '@orpc/client';
5
+ import { StandardLazyRequest, StandardResponse } from '@orpc/standard-server';
6
+ import { Value } from '@orpc/shared';
7
+
8
+ interface StandardOpenAPICodecOptions {
9
+ /**
10
+ * Customize how an ORPC error is encoded into a response body.
11
+ * Use this if your API needs a different error output structure.
12
+ *
13
+ * @remarks
14
+ * - Return `null | undefined` to fallback to default behavior
15
+ *
16
+ * @default ((e) => e.toJSON())
17
+ */
18
+ customErrorResponseBodyEncoder?: (error: ORPCError<any, any>) => unknown;
19
+ }
20
+ declare class StandardOpenAPICodec implements StandardCodec {
21
+ #private;
22
+ private readonly serializer;
23
+ private readonly customErrorResponseBodyEncoder;
24
+ constructor(serializer: StandardOpenAPISerializer, options?: StandardOpenAPICodecOptions);
25
+ decode(request: StandardLazyRequest, params: StandardParams | undefined, procedure: AnyProcedure): Promise<unknown>;
26
+ encode(output: unknown, procedure: AnyProcedure): StandardResponse;
27
+ encodeError(error: ORPCError<any, any>): StandardResponse;
28
+ }
29
+
30
+ interface StandardOpenAPIMatcherOptions {
31
+ /**
32
+ * Filter procedures. Return `false` to exclude a procedure from matching.
33
+ *
34
+ * @default true
35
+ */
36
+ filter?: Value<boolean, [options: TraverseContractProcedureCallbackOptions]>;
37
+ }
38
+ declare class StandardOpenAPIMatcher implements StandardMatcher {
39
+ private readonly filter;
40
+ private readonly tree;
41
+ private pendingRouters;
42
+ constructor(options?: StandardOpenAPIMatcherOptions);
43
+ init(router: AnyRouter, path?: readonly string[]): void;
44
+ match(method: string, pathname: HTTPPath): Promise<StandardMatchResult>;
45
+ }
46
+
47
+ interface StandardOpenAPIHandlerOptions<T extends Context> extends StandardHandlerOptions<T>, StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions, StandardOpenAPIMatcherOptions, StandardOpenAPICodecOptions {
48
+ }
49
+ declare class StandardOpenAPIHandler<T extends Context> extends StandardHandler<T> {
50
+ constructor(router: Router<any, T>, options: NoInfer<StandardOpenAPIHandlerOptions<T>>);
51
+ }
52
+
53
+ export { StandardOpenAPICodec as a, StandardOpenAPIHandler as c, StandardOpenAPIMatcher as e };
54
+ export type { StandardOpenAPICodecOptions as S, StandardOpenAPIHandlerOptions as b, StandardOpenAPIMatcherOptions as d };
@@ -0,0 +1,54 @@
1
+ import { StandardOpenAPISerializer, StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions } from '@orpc/openapi-client/standard';
2
+ import { AnyProcedure, TraverseContractProcedureCallbackOptions, AnyRouter, Context, Router } from '@orpc/server';
3
+ import { StandardCodec, StandardParams, StandardMatcher, StandardMatchResult, StandardHandlerOptions, StandardHandler } from '@orpc/server/standard';
4
+ import { ORPCError, HTTPPath } from '@orpc/client';
5
+ import { StandardLazyRequest, StandardResponse } from '@orpc/standard-server';
6
+ import { Value } from '@orpc/shared';
7
+
8
+ interface StandardOpenAPICodecOptions {
9
+ /**
10
+ * Customize how an ORPC error is encoded into a response body.
11
+ * Use this if your API needs a different error output structure.
12
+ *
13
+ * @remarks
14
+ * - Return `null | undefined` to fallback to default behavior
15
+ *
16
+ * @default ((e) => e.toJSON())
17
+ */
18
+ customErrorResponseBodyEncoder?: (error: ORPCError<any, any>) => unknown;
19
+ }
20
+ declare class StandardOpenAPICodec implements StandardCodec {
21
+ #private;
22
+ private readonly serializer;
23
+ private readonly customErrorResponseBodyEncoder;
24
+ constructor(serializer: StandardOpenAPISerializer, options?: StandardOpenAPICodecOptions);
25
+ decode(request: StandardLazyRequest, params: StandardParams | undefined, procedure: AnyProcedure): Promise<unknown>;
26
+ encode(output: unknown, procedure: AnyProcedure): StandardResponse;
27
+ encodeError(error: ORPCError<any, any>): StandardResponse;
28
+ }
29
+
30
+ interface StandardOpenAPIMatcherOptions {
31
+ /**
32
+ * Filter procedures. Return `false` to exclude a procedure from matching.
33
+ *
34
+ * @default true
35
+ */
36
+ filter?: Value<boolean, [options: TraverseContractProcedureCallbackOptions]>;
37
+ }
38
+ declare class StandardOpenAPIMatcher implements StandardMatcher {
39
+ private readonly filter;
40
+ private readonly tree;
41
+ private pendingRouters;
42
+ constructor(options?: StandardOpenAPIMatcherOptions);
43
+ init(router: AnyRouter, path?: readonly string[]): void;
44
+ match(method: string, pathname: HTTPPath): Promise<StandardMatchResult>;
45
+ }
46
+
47
+ interface StandardOpenAPIHandlerOptions<T extends Context> extends StandardHandlerOptions<T>, StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions, StandardOpenAPIMatcherOptions, StandardOpenAPICodecOptions {
48
+ }
49
+ declare class StandardOpenAPIHandler<T extends Context> extends StandardHandler<T> {
50
+ constructor(router: Router<any, T>, options: NoInfer<StandardOpenAPIHandlerOptions<T>>);
51
+ }
52
+
53
+ export { StandardOpenAPICodec as a, StandardOpenAPIHandler as c, StandardOpenAPIMatcher as e };
54
+ export type { StandardOpenAPICodecOptions as S, StandardOpenAPIHandlerOptions as b, StandardOpenAPIMatcherOptions as d };
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@orpc/openapi",
3
3
  "type": "module",
4
- "version": "0.0.0-next.3636544",
4
+ "version": "0.0.0-next.36cf381",
5
5
  "license": "MIT",
6
- "homepage": "https://orpc.unnoq.com",
6
+ "homepage": "https://orpc.dev",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "git+https://github.com/unnoq/orpc.git",
9
+ "url": "git+https://github.com/middleapi/orpc.git",
10
10
  "directory": "packages/openapi"
11
11
  },
12
12
  "keywords": [
13
- "unnoq",
14
13
  "orpc"
15
14
  ],
15
+ "sideEffects": false,
16
16
  "exports": {
17
17
  ".": {
18
18
  "types": "./dist/index.d.mts",
@@ -39,6 +39,11 @@
39
39
  "import": "./dist/adapters/node/index.mjs",
40
40
  "default": "./dist/adapters/node/index.mjs"
41
41
  },
42
+ "./fastify": {
43
+ "types": "./dist/adapters/fastify/index.d.mts",
44
+ "import": "./dist/adapters/fastify/index.mjs",
45
+ "default": "./dist/adapters/fastify/index.mjs"
46
+ },
42
47
  "./aws-lambda": {
43
48
  "types": "./dist/adapters/aws-lambda/index.d.mts",
44
49
  "import": "./dist/adapters/aws-lambda/index.mjs",
@@ -49,17 +54,19 @@
49
54
  "dist"
50
55
  ],
51
56
  "dependencies": {
52
- "json-schema-typed": "^8.0.1",
53
- "rou3": "^0.7.3",
54
- "@orpc/contract": "0.0.0-next.3636544",
55
- "@orpc/openapi-client": "0.0.0-next.3636544",
56
- "@orpc/server": "0.0.0-next.3636544",
57
- "@orpc/client": "0.0.0-next.3636544",
58
- "@orpc/standard-server": "0.0.0-next.3636544",
59
- "@orpc/shared": "0.0.0-next.3636544"
57
+ "json-schema-typed": "^8.0.2",
58
+ "rou3": "^0.7.12",
59
+ "@orpc/client": "0.0.0-next.36cf381",
60
+ "@orpc/interop": "0.0.0-next.36cf381",
61
+ "@orpc/contract": "0.0.0-next.36cf381",
62
+ "@orpc/openapi-client": "0.0.0-next.36cf381",
63
+ "@orpc/server": "0.0.0-next.36cf381",
64
+ "@orpc/shared": "0.0.0-next.36cf381",
65
+ "@orpc/standard-server": "0.0.0-next.36cf381"
60
66
  },
61
67
  "devDependencies": {
62
- "zod": "^4.0.5"
68
+ "fastify": "^5.8.3",
69
+ "zod": "^4.3.6"
63
70
  },
64
71
  "scripts": {
65
72
  "build": "unbuild",
@@ -1,31 +0,0 @@
1
- import { StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions } from '@orpc/openapi-client/standard';
2
- import { TraverseContractProcedureCallbackOptions, AnyRouter, Context, Router } from '@orpc/server';
3
- import { StandardMatcher, StandardMatchResult, StandardHandlerOptions, StandardHandler } from '@orpc/server/standard';
4
- import { HTTPPath } from '@orpc/client';
5
- import { Value } from '@orpc/shared';
6
-
7
- interface StandardOpenAPIMatcherOptions {
8
- /**
9
- * Filter procedures. Return `false` to exclude a procedure from matching.
10
- *
11
- * @default true
12
- */
13
- filter?: Value<boolean, [options: TraverseContractProcedureCallbackOptions]>;
14
- }
15
- declare class StandardOpenAPIMatcher implements StandardMatcher {
16
- private readonly filter;
17
- private readonly tree;
18
- private pendingRouters;
19
- constructor(options?: StandardOpenAPIMatcherOptions);
20
- init(router: AnyRouter, path?: readonly string[]): void;
21
- match(method: string, pathname: HTTPPath): Promise<StandardMatchResult>;
22
- }
23
-
24
- interface StandardOpenAPIHandlerOptions<T extends Context> extends StandardHandlerOptions<T>, StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions, StandardOpenAPIMatcherOptions {
25
- }
26
- declare class StandardOpenAPIHandler<T extends Context> extends StandardHandler<T> {
27
- constructor(router: Router<any, T>, options: NoInfer<StandardOpenAPIHandlerOptions<T>>);
28
- }
29
-
30
- export { StandardOpenAPIHandler as a, StandardOpenAPIMatcher as c };
31
- export type { StandardOpenAPIHandlerOptions as S, StandardOpenAPIMatcherOptions as b };
@@ -1,31 +0,0 @@
1
- import { StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions } from '@orpc/openapi-client/standard';
2
- import { TraverseContractProcedureCallbackOptions, AnyRouter, Context, Router } from '@orpc/server';
3
- import { StandardMatcher, StandardMatchResult, StandardHandlerOptions, StandardHandler } from '@orpc/server/standard';
4
- import { HTTPPath } from '@orpc/client';
5
- import { Value } from '@orpc/shared';
6
-
7
- interface StandardOpenAPIMatcherOptions {
8
- /**
9
- * Filter procedures. Return `false` to exclude a procedure from matching.
10
- *
11
- * @default true
12
- */
13
- filter?: Value<boolean, [options: TraverseContractProcedureCallbackOptions]>;
14
- }
15
- declare class StandardOpenAPIMatcher implements StandardMatcher {
16
- private readonly filter;
17
- private readonly tree;
18
- private pendingRouters;
19
- constructor(options?: StandardOpenAPIMatcherOptions);
20
- init(router: AnyRouter, path?: readonly string[]): void;
21
- match(method: string, pathname: HTTPPath): Promise<StandardMatchResult>;
22
- }
23
-
24
- interface StandardOpenAPIHandlerOptions<T extends Context> extends StandardHandlerOptions<T>, StandardOpenAPIJsonSerializerOptions, StandardBracketNotationSerializerOptions, StandardOpenAPIMatcherOptions {
25
- }
26
- declare class StandardOpenAPIHandler<T extends Context> extends StandardHandler<T> {
27
- constructor(router: Router<any, T>, options: NoInfer<StandardOpenAPIHandlerOptions<T>>);
28
- }
29
-
30
- export { StandardOpenAPIHandler as a, StandardOpenAPIMatcher as c };
31
- export type { StandardOpenAPIHandlerOptions as S, StandardOpenAPIMatcherOptions as b };