@orpc/openapi 0.0.0-next.fb0d07c → 0.0.0-next.fc23c8d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,7 +30,7 @@
30
30
  - **🔗 End-to-End Type Safety**: Ensure type-safe inputs, outputs, and errors from client to server.
31
31
  - **📘 First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard.
32
32
  - **📝 Contract-First Development**: Optionally define your API contract before implementation.
33
- - **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte), Pinia Colada, and more.
33
+ - **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), Pinia Colada, and more.
34
34
  - **🚀 Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
35
35
  - **🔠 Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
36
36
  - **🗃️ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more.
@@ -49,14 +49,12 @@ You can find the full documentation [here](https://orpc.unnoq.com).
49
49
  - [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract.
50
50
  - [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract.
51
51
  - [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety.
52
- - [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with NestJS.
52
+ - [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
53
+ - [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with [NestJS](https://nestjs.com/).
53
54
  - [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
54
- - [@orpc/react-query](https://www.npmjs.com/package/@orpc/react-query): Integration with [React Query](https://tanstack.com/query/latest/docs/framework/react/overview).
55
- - [@orpc/vue-query](https://www.npmjs.com/package/@orpc/vue-query): Integration with [Vue Query](https://tanstack.com/query/latest/docs/framework/vue/overview).
56
- - [@orpc/solid-query](https://www.npmjs.com/package/@orpc/solid-query): Integration with [Solid Query](https://tanstack.com/query/latest/docs/framework/solid/overview).
57
- - [@orpc/svelte-query](https://www.npmjs.com/package/@orpc/svelte-query): Integration with [Svelte Query](https://tanstack.com/query/latest/docs/framework/svelte/overview).
55
+ - [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): [TanStack Query](https://tanstack.com/query/latest) integration.
58
56
  - [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
59
- - [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
57
+ - [@orpc/hey-api](https://www.npmjs.com/package/@orpc/hey-api): [Hey API](https://heyapi.dev/) integration.
60
58
  - [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
61
59
  - [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): OpenAPI spec generation from [Valibot](https://valibot.dev/).
62
60
  - [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): OpenAPI spec generation from [ArkType](https://arktype.io/).
@@ -0,0 +1,17 @@
1
+ import { Context, Router } from '@orpc/server';
2
+ import { AwsLambdaHandler, AwsLambdaHandlerOptions } from '@orpc/server/aws-lambda';
3
+ import { S as StandardOpenAPIHandlerOptions } from '../../shared/openapi.D3j94c9n.mjs';
4
+ import '@orpc/openapi-client/standard';
5
+ import '@orpc/server/standard';
6
+
7
+ /**
8
+ * OpenAPI Handler for AWS Lambda.
9
+ *
10
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-handler OpenAPI Handler Docs}
11
+ * @see {@link https://orpc.unnoq.com/docs/adapters/http HTTP Adapter Docs}
12
+ */
13
+ declare class experimental_OpenAPIHandler<T extends Context> extends AwsLambdaHandler<T> {
14
+ constructor(router: Router<any, T>, options?: NoInfer<StandardOpenAPIHandlerOptions<T> & AwsLambdaHandlerOptions>);
15
+ }
16
+
17
+ export { experimental_OpenAPIHandler };
@@ -0,0 +1,17 @@
1
+ import { Context, Router } from '@orpc/server';
2
+ import { AwsLambdaHandler, AwsLambdaHandlerOptions } from '@orpc/server/aws-lambda';
3
+ import { S as StandardOpenAPIHandlerOptions } from '../../shared/openapi.D3j94c9n.js';
4
+ import '@orpc/openapi-client/standard';
5
+ import '@orpc/server/standard';
6
+
7
+ /**
8
+ * OpenAPI Handler for AWS Lambda.
9
+ *
10
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-handler OpenAPI Handler Docs}
11
+ * @see {@link https://orpc.unnoq.com/docs/adapters/http HTTP Adapter Docs}
12
+ */
13
+ declare class experimental_OpenAPIHandler<T extends Context> extends AwsLambdaHandler<T> {
14
+ constructor(router: Router<any, T>, options?: NoInfer<StandardOpenAPIHandlerOptions<T> & AwsLambdaHandlerOptions>);
15
+ }
16
+
17
+ export { experimental_OpenAPIHandler };
@@ -0,0 +1,18 @@
1
+ import { AwsLambdaHandler } from '@orpc/server/aws-lambda';
2
+ import '@orpc/client';
3
+ import '@orpc/contract';
4
+ import '@orpc/shared';
5
+ import { a as StandardOpenAPIHandler } from '../../shared/openapi.C_UtQ8Us.mjs';
6
+ import '@orpc/client/standard';
7
+ import '@orpc/server';
8
+ import 'rou3';
9
+ import '@orpc/openapi-client/standard';
10
+ import '@orpc/server/standard';
11
+
12
+ class experimental_OpenAPIHandler extends AwsLambdaHandler {
13
+ constructor(router, options = {}) {
14
+ super(new StandardOpenAPIHandler(router, options), options);
15
+ }
16
+ }
17
+
18
+ export { experimental_OpenAPIHandler };
package/dist/index.d.mts CHANGED
@@ -1,16 +1,15 @@
1
- import { AnyContractProcedure } from '@orpc/contract';
2
- import { OpenAPIV3_1 } from 'openapi-types';
3
- export { OpenAPIV3_1 as OpenAPI } from 'openapi-types';
4
- export { d as CompositeSchemaConverter, C as ConditionalSchemaConverter, b as OpenAPIGenerator, a as OpenAPIGeneratorGenerateOptions, O as OpenAPIGeneratorOptions, S as SchemaConvertOptions, c as SchemaConverter } from './shared/openapi.CwdCLgSU.mjs';
1
+ import { OpenAPI, AnyContractProcedure } from '@orpc/contract';
2
+ export { OpenAPI } from '@orpc/contract';
3
+ export { e as CompositeSchemaConverter, C as ConditionalSchemaConverter, b as OpenAPIGenerator, a as OpenAPIGeneratorGenerateOptions, O as OpenAPIGeneratorOptions, c as SchemaConvertOptions, d as SchemaConverter, S as SchemaConverterComponent } from './shared/openapi.B3hexduL.mjs';
5
4
  import { HTTPPath, HTTPMethod } from '@orpc/client';
6
5
  import { JSONSchema } from 'json-schema-typed/draft-2020-12';
7
- export { JSONSchema, ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat } from 'json-schema-typed/draft-2020-12';
6
+ export { JSONSchema, ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat, TypeName as JSONSchemaTypeName } from 'json-schema-typed/draft-2020-12';
8
7
  import { JsonifiedClient } from '@orpc/openapi-client';
9
8
  import { AnyRouter, ClientContext, Lazyable, CreateProcedureClientOptions, InferRouterInitialContext, Schema, ErrorMap, Meta, RouterClient } from '@orpc/server';
10
9
  import { MaybeOptionalOptions } from '@orpc/shared';
11
10
  import '@orpc/openapi-client/standard';
12
11
 
13
- type OverrideOperationValue = Partial<OpenAPIV3_1.OperationObject> | ((current: OpenAPIV3_1.OperationObject, procedure: AnyContractProcedure) => OpenAPIV3_1.OperationObject);
12
+ type OverrideOperationValue = Partial<OpenAPI.OperationObject> | ((current: OpenAPI.OperationObject, procedure: AnyContractProcedure) => OpenAPI.OperationObject);
14
13
  /**
15
14
  * Customize The Operation Object by proxy an error map item or a middleware.
16
15
  *
@@ -18,7 +17,7 @@ type OverrideOperationValue = Partial<OpenAPIV3_1.OperationObject> | ((current:
18
17
  */
19
18
  declare function customOpenAPIOperation<T extends object>(o: T, extend: OverrideOperationValue): T;
20
19
  declare function getCustomOpenAPIOperation(o: object): OverrideOperationValue | undefined;
21
- declare function applyCustomOpenAPIOperation(operation: OpenAPIV3_1.OperationObject, contract: AnyContractProcedure): OpenAPIV3_1.OperationObject;
20
+ declare function applyCustomOpenAPIOperation(operation: OpenAPI.OperationObject, contract: AnyContractProcedure): OpenAPI.OperationObject;
22
21
 
23
22
  /**
24
23
  * @internal
@@ -49,15 +48,15 @@ declare function toOpenAPIMethod(method: HTTPMethod): Lowercase<HTTPMethod>;
49
48
  /**
50
49
  * @internal
51
50
  */
52
- declare function toOpenAPIContent(schema: JSONSchema): Record<string, OpenAPIV3_1.MediaTypeObject>;
51
+ declare function toOpenAPIContent(schema: JSONSchema): Record<string, OpenAPI.MediaTypeObject>;
53
52
  /**
54
53
  * @internal
55
54
  */
56
- declare function toOpenAPIEventIteratorContent([yieldsRequired, yieldsSchema]: [boolean, JSONSchema], [returnsRequired, returnsSchema]: [boolean, JSONSchema]): Record<string, OpenAPIV3_1.MediaTypeObject>;
55
+ declare function toOpenAPIEventIteratorContent([yieldsRequired, yieldsSchema]: [boolean, JSONSchema], [returnsRequired, returnsSchema]: [boolean, JSONSchema]): Record<string, OpenAPI.MediaTypeObject>;
57
56
  /**
58
57
  * @internal
59
58
  */
60
- declare function toOpenAPIParameters(schema: ObjectSchema, parameterIn: 'path' | 'query' | 'header' | 'cookie'): OpenAPIV3_1.ParameterObject[];
59
+ declare function toOpenAPIParameters(schema: ObjectSchema, parameterIn: 'path' | 'query' | 'header' | 'cookie'): OpenAPI.ParameterObject[];
61
60
  /**
62
61
  * @internal
63
62
  */
@@ -65,7 +64,8 @@ declare function checkParamsSchema(schema: ObjectSchema, params: string[]): bool
65
64
  /**
66
65
  * @internal
67
66
  */
68
- declare function toOpenAPISchema(schema: JSONSchema): OpenAPIV3_1.SchemaObject & object;
67
+ declare function toOpenAPISchema(schema: JSONSchema): OpenAPI.SchemaObject & object;
68
+ declare function resolveOpenAPIJsonSchemaRef(doc: OpenAPI.Document, schema: JSONSchema): JSONSchema;
69
69
 
70
70
  declare function createJsonifiedRouterClient<T extends AnyRouter, TClientContext extends ClientContext>(router: Lazyable<T | undefined>, ...rest: MaybeOptionalOptions<CreateProcedureClientOptions<InferRouterInitialContext<T>, Schema<unknown, unknown>, ErrorMap, Meta, TClientContext>>): JsonifiedClient<RouterClient<T, TClientContext>>;
71
71
 
@@ -96,10 +96,15 @@ declare function applySchemaOptionality(required: boolean, schema: JSONSchema):
96
96
  * If the schema is not a simple union or is a base type, it's returned as a single-element array.
97
97
  */
98
98
  declare function expandUnionSchema(schema: JSONSchema): JSONSchema[];
99
+ declare function expandArrayableSchema(schema: JSONSchema): undefined | [items: JSONSchema, array: JSONSchema & {
100
+ type: 'array';
101
+ items?: JSONSchema;
102
+ }];
103
+ declare function isPrimitiveSchema(schema: JSONSchema): boolean;
99
104
 
100
105
  declare const oo: {
101
106
  spec: typeof customOpenAPIOperation;
102
107
  };
103
108
 
104
- export { LOGIC_KEYWORDS, applyCustomOpenAPIOperation, applySchemaOptionality, checkParamsSchema, createJsonifiedRouterClient, customOpenAPIOperation, expandUnionSchema, filterSchemaBranches, getCustomOpenAPIOperation, isAnySchema, isFileSchema, isObjectSchema, oo, separateObjectSchema, toOpenAPIContent, toOpenAPIEventIteratorContent, toOpenAPIMethod, toOpenAPIParameters, toOpenAPIPath, toOpenAPISchema };
109
+ export { LOGIC_KEYWORDS, applyCustomOpenAPIOperation, applySchemaOptionality, checkParamsSchema, createJsonifiedRouterClient, customOpenAPIOperation, expandArrayableSchema, expandUnionSchema, filterSchemaBranches, getCustomOpenAPIOperation, isAnySchema, isFileSchema, isObjectSchema, isPrimitiveSchema, oo, resolveOpenAPIJsonSchemaRef, separateObjectSchema, toOpenAPIContent, toOpenAPIEventIteratorContent, toOpenAPIMethod, toOpenAPIParameters, toOpenAPIPath, toOpenAPISchema };
105
110
  export type { FileSchema, ObjectSchema, OverrideOperationValue };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,15 @@
1
- import { AnyContractProcedure } from '@orpc/contract';
2
- import { OpenAPIV3_1 } from 'openapi-types';
3
- export { OpenAPIV3_1 as OpenAPI } from 'openapi-types';
4
- export { d as CompositeSchemaConverter, C as ConditionalSchemaConverter, b as OpenAPIGenerator, a as OpenAPIGeneratorGenerateOptions, O as OpenAPIGeneratorOptions, S as SchemaConvertOptions, c as SchemaConverter } from './shared/openapi.CwdCLgSU.js';
1
+ import { OpenAPI, AnyContractProcedure } from '@orpc/contract';
2
+ export { OpenAPI } from '@orpc/contract';
3
+ export { e as CompositeSchemaConverter, C as ConditionalSchemaConverter, b as OpenAPIGenerator, a as OpenAPIGeneratorGenerateOptions, O as OpenAPIGeneratorOptions, c as SchemaConvertOptions, d as SchemaConverter, S as SchemaConverterComponent } from './shared/openapi.B3hexduL.js';
5
4
  import { HTTPPath, HTTPMethod } from '@orpc/client';
6
5
  import { JSONSchema } from 'json-schema-typed/draft-2020-12';
7
- export { JSONSchema, ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat } from 'json-schema-typed/draft-2020-12';
6
+ export { JSONSchema, ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat, TypeName as JSONSchemaTypeName } from 'json-schema-typed/draft-2020-12';
8
7
  import { JsonifiedClient } from '@orpc/openapi-client';
9
8
  import { AnyRouter, ClientContext, Lazyable, CreateProcedureClientOptions, InferRouterInitialContext, Schema, ErrorMap, Meta, RouterClient } from '@orpc/server';
10
9
  import { MaybeOptionalOptions } from '@orpc/shared';
11
10
  import '@orpc/openapi-client/standard';
12
11
 
13
- type OverrideOperationValue = Partial<OpenAPIV3_1.OperationObject> | ((current: OpenAPIV3_1.OperationObject, procedure: AnyContractProcedure) => OpenAPIV3_1.OperationObject);
12
+ type OverrideOperationValue = Partial<OpenAPI.OperationObject> | ((current: OpenAPI.OperationObject, procedure: AnyContractProcedure) => OpenAPI.OperationObject);
14
13
  /**
15
14
  * Customize The Operation Object by proxy an error map item or a middleware.
16
15
  *
@@ -18,7 +17,7 @@ type OverrideOperationValue = Partial<OpenAPIV3_1.OperationObject> | ((current:
18
17
  */
19
18
  declare function customOpenAPIOperation<T extends object>(o: T, extend: OverrideOperationValue): T;
20
19
  declare function getCustomOpenAPIOperation(o: object): OverrideOperationValue | undefined;
21
- declare function applyCustomOpenAPIOperation(operation: OpenAPIV3_1.OperationObject, contract: AnyContractProcedure): OpenAPIV3_1.OperationObject;
20
+ declare function applyCustomOpenAPIOperation(operation: OpenAPI.OperationObject, contract: AnyContractProcedure): OpenAPI.OperationObject;
22
21
 
23
22
  /**
24
23
  * @internal
@@ -49,15 +48,15 @@ declare function toOpenAPIMethod(method: HTTPMethod): Lowercase<HTTPMethod>;
49
48
  /**
50
49
  * @internal
51
50
  */
52
- declare function toOpenAPIContent(schema: JSONSchema): Record<string, OpenAPIV3_1.MediaTypeObject>;
51
+ declare function toOpenAPIContent(schema: JSONSchema): Record<string, OpenAPI.MediaTypeObject>;
53
52
  /**
54
53
  * @internal
55
54
  */
56
- declare function toOpenAPIEventIteratorContent([yieldsRequired, yieldsSchema]: [boolean, JSONSchema], [returnsRequired, returnsSchema]: [boolean, JSONSchema]): Record<string, OpenAPIV3_1.MediaTypeObject>;
55
+ declare function toOpenAPIEventIteratorContent([yieldsRequired, yieldsSchema]: [boolean, JSONSchema], [returnsRequired, returnsSchema]: [boolean, JSONSchema]): Record<string, OpenAPI.MediaTypeObject>;
57
56
  /**
58
57
  * @internal
59
58
  */
60
- declare function toOpenAPIParameters(schema: ObjectSchema, parameterIn: 'path' | 'query' | 'header' | 'cookie'): OpenAPIV3_1.ParameterObject[];
59
+ declare function toOpenAPIParameters(schema: ObjectSchema, parameterIn: 'path' | 'query' | 'header' | 'cookie'): OpenAPI.ParameterObject[];
61
60
  /**
62
61
  * @internal
63
62
  */
@@ -65,7 +64,8 @@ declare function checkParamsSchema(schema: ObjectSchema, params: string[]): bool
65
64
  /**
66
65
  * @internal
67
66
  */
68
- declare function toOpenAPISchema(schema: JSONSchema): OpenAPIV3_1.SchemaObject & object;
67
+ declare function toOpenAPISchema(schema: JSONSchema): OpenAPI.SchemaObject & object;
68
+ declare function resolveOpenAPIJsonSchemaRef(doc: OpenAPI.Document, schema: JSONSchema): JSONSchema;
69
69
 
70
70
  declare function createJsonifiedRouterClient<T extends AnyRouter, TClientContext extends ClientContext>(router: Lazyable<T | undefined>, ...rest: MaybeOptionalOptions<CreateProcedureClientOptions<InferRouterInitialContext<T>, Schema<unknown, unknown>, ErrorMap, Meta, TClientContext>>): JsonifiedClient<RouterClient<T, TClientContext>>;
71
71
 
@@ -96,10 +96,15 @@ declare function applySchemaOptionality(required: boolean, schema: JSONSchema):
96
96
  * If the schema is not a simple union or is a base type, it's returned as a single-element array.
97
97
  */
98
98
  declare function expandUnionSchema(schema: JSONSchema): JSONSchema[];
99
+ declare function expandArrayableSchema(schema: JSONSchema): undefined | [items: JSONSchema, array: JSONSchema & {
100
+ type: 'array';
101
+ items?: JSONSchema;
102
+ }];
103
+ declare function isPrimitiveSchema(schema: JSONSchema): boolean;
99
104
 
100
105
  declare const oo: {
101
106
  spec: typeof customOpenAPIOperation;
102
107
  };
103
108
 
104
- export { LOGIC_KEYWORDS, applyCustomOpenAPIOperation, applySchemaOptionality, checkParamsSchema, createJsonifiedRouterClient, customOpenAPIOperation, expandUnionSchema, filterSchemaBranches, getCustomOpenAPIOperation, isAnySchema, isFileSchema, isObjectSchema, oo, separateObjectSchema, toOpenAPIContent, toOpenAPIEventIteratorContent, toOpenAPIMethod, toOpenAPIParameters, toOpenAPIPath, toOpenAPISchema };
109
+ export { LOGIC_KEYWORDS, applyCustomOpenAPIOperation, applySchemaOptionality, checkParamsSchema, createJsonifiedRouterClient, customOpenAPIOperation, expandArrayableSchema, expandUnionSchema, filterSchemaBranches, getCustomOpenAPIOperation, isAnySchema, isFileSchema, isObjectSchema, isPrimitiveSchema, oo, resolveOpenAPIJsonSchemaRef, separateObjectSchema, toOpenAPIContent, toOpenAPIEventIteratorContent, toOpenAPIMethod, toOpenAPIParameters, toOpenAPIPath, toOpenAPISchema };
105
110
  export type { FileSchema, ObjectSchema, OverrideOperationValue };
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
- import { c as customOpenAPIOperation } from './shared/openapi.PDTdnRIU.mjs';
2
- export { C as CompositeSchemaConverter, L as LOGIC_KEYWORDS, O as OpenAPIGenerator, a as applyCustomOpenAPIOperation, n as applySchemaOptionality, h as checkParamsSchema, o as expandUnionSchema, m as filterSchemaBranches, g as getCustomOpenAPIOperation, l as isAnySchema, j as isFileSchema, k as isObjectSchema, s as separateObjectSchema, d as toOpenAPIContent, e as toOpenAPIEventIteratorContent, b as toOpenAPIMethod, f as toOpenAPIParameters, t as toOpenAPIPath, i as toOpenAPISchema } from './shared/openapi.PDTdnRIU.mjs';
1
+ import { c as customOpenAPIOperation } from './shared/openapi.DrrBsJ0w.mjs';
2
+ export { C as CompositeSchemaConverter, L as LOGIC_KEYWORDS, O as OpenAPIGenerator, a as applyCustomOpenAPIOperation, n as applySchemaOptionality, h as checkParamsSchema, p as expandArrayableSchema, o as expandUnionSchema, m as filterSchemaBranches, g as getCustomOpenAPIOperation, l as isAnySchema, j as isFileSchema, k as isObjectSchema, q as isPrimitiveSchema, r as resolveOpenAPIJsonSchemaRef, s as separateObjectSchema, d as toOpenAPIContent, e as toOpenAPIEventIteratorContent, b as toOpenAPIMethod, f as toOpenAPIParameters, t as toOpenAPIPath, i as toOpenAPISchema } from './shared/openapi.DrrBsJ0w.mjs';
3
3
  import { createORPCErrorFromJson } from '@orpc/client';
4
4
  import { StandardOpenAPISerializer, StandardOpenAPIJsonSerializer, StandardBracketNotationSerializer } from '@orpc/openapi-client/standard';
5
5
  import { ORPCError, createRouterClient } from '@orpc/server';
6
6
  import { resolveMaybeOptionalOptions } from '@orpc/shared';
7
- export { ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat } from 'json-schema-typed/draft-2020-12';
7
+ export { ContentEncoding as JSONSchemaContentEncoding, Format as JSONSchemaFormat, TypeName as JSONSchemaTypeName } from 'json-schema-typed/draft-2020-12';
8
8
  import '@orpc/client/standard';
9
9
  import '@orpc/contract';
10
10
 
@@ -1,9 +1,8 @@
1
+ import { OpenAPI } from '@orpc/contract';
1
2
  import { Context, HTTPPath, Router } from '@orpc/server';
2
3
  import { StandardHandlerInterceptorOptions, StandardHandlerPlugin, StandardHandlerOptions } from '@orpc/server/standard';
3
4
  import { Value, Promisable } from '@orpc/shared';
4
- import { OpenAPIV3_1 } from 'openapi-types';
5
- import { O as OpenAPIGeneratorOptions, a as OpenAPIGeneratorGenerateOptions } from '../shared/openapi.CwdCLgSU.mjs';
6
- import '@orpc/contract';
5
+ import { O as OpenAPIGeneratorOptions, a as OpenAPIGeneratorGenerateOptions } from '../shared/openapi.B3hexduL.mjs';
7
6
  import '@orpc/openapi-client/standard';
8
7
  import 'json-schema-typed/draft-2020-12';
9
8
 
@@ -50,7 +49,7 @@ interface OpenAPIReferencePluginOptions<T extends Context> extends OpenAPIGenera
50
49
  /**
51
50
  * Override function to generate the full HTML for the docs page.
52
51
  */
53
- renderDocsHtml?: (specUrl: string, title: string, head: string, scriptUrl: string, config: Record<string, unknown> | undefined, spec: OpenAPIV3_1.Document) => string;
52
+ renderDocsHtml?: (specUrl: string, title: string, head: string, scriptUrl: string, config: Record<string, unknown> | undefined, spec: OpenAPI.Document) => string;
54
53
  }
55
54
  declare class OpenAPIReferencePlugin<T extends Context> implements StandardHandlerPlugin<T> {
56
55
  private readonly generator;
@@ -1,9 +1,8 @@
1
+ import { OpenAPI } from '@orpc/contract';
1
2
  import { Context, HTTPPath, Router } from '@orpc/server';
2
3
  import { StandardHandlerInterceptorOptions, StandardHandlerPlugin, StandardHandlerOptions } from '@orpc/server/standard';
3
4
  import { Value, Promisable } from '@orpc/shared';
4
- import { OpenAPIV3_1 } from 'openapi-types';
5
- import { O as OpenAPIGeneratorOptions, a as OpenAPIGeneratorGenerateOptions } from '../shared/openapi.CwdCLgSU.js';
6
- import '@orpc/contract';
5
+ import { O as OpenAPIGeneratorOptions, a as OpenAPIGeneratorGenerateOptions } from '../shared/openapi.B3hexduL.js';
7
6
  import '@orpc/openapi-client/standard';
8
7
  import 'json-schema-typed/draft-2020-12';
9
8
 
@@ -50,7 +49,7 @@ interface OpenAPIReferencePluginOptions<T extends Context> extends OpenAPIGenera
50
49
  /**
51
50
  * Override function to generate the full HTML for the docs page.
52
51
  */
53
- renderDocsHtml?: (specUrl: string, title: string, head: string, scriptUrl: string, config: Record<string, unknown> | undefined, spec: OpenAPIV3_1.Document) => string;
52
+ renderDocsHtml?: (specUrl: string, title: string, head: string, scriptUrl: string, config: Record<string, unknown> | undefined, spec: OpenAPI.Document) => string;
54
53
  }
55
54
  declare class OpenAPIReferencePlugin<T extends Context> implements StandardHandlerPlugin<T> {
56
55
  private readonly generator;
@@ -1,5 +1,5 @@
1
1
  import { stringifyJSON, once, value } from '@orpc/shared';
2
- import { O as OpenAPIGenerator } from '../shared/openapi.PDTdnRIU.mjs';
2
+ import { O as OpenAPIGenerator } from '../shared/openapi.DrrBsJ0w.mjs';
3
3
  import '@orpc/client';
4
4
  import '@orpc/client/standard';
5
5
  import '@orpc/contract';
@@ -0,0 +1,101 @@
1
+ import { AnySchema, OpenAPI, AnyContractProcedure, AnyContractRouter } from '@orpc/contract';
2
+ import { StandardOpenAPIJsonSerializerOptions } from '@orpc/openapi-client/standard';
3
+ import { AnyProcedure, AnyRouter } from '@orpc/server';
4
+ import { Promisable } from '@orpc/shared';
5
+ import { JSONSchema } from 'json-schema-typed/draft-2020-12';
6
+
7
+ interface SchemaConverterComponent {
8
+ allowedStrategies: readonly SchemaConvertOptions['strategy'][];
9
+ schema: AnySchema;
10
+ required: boolean;
11
+ ref: string;
12
+ }
13
+ interface SchemaConvertOptions {
14
+ strategy: 'input' | 'output';
15
+ /**
16
+ * Common components should use `$ref` to represent themselves if matched.
17
+ */
18
+ components?: readonly SchemaConverterComponent[];
19
+ /**
20
+ * Minimum schema structure depth required before using `$ref` for components.
21
+ *
22
+ * For example, if set to 2, `$ref` will only be used for schemas nested at depth 2 or greater.
23
+ *
24
+ * @default 0 - No depth limit;
25
+ */
26
+ minStructureDepthForRef?: number;
27
+ }
28
+ interface SchemaConverter {
29
+ convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<[required: boolean, jsonSchema: JSONSchema]>;
30
+ }
31
+ interface ConditionalSchemaConverter extends SchemaConverter {
32
+ condition(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<boolean>;
33
+ }
34
+ declare class CompositeSchemaConverter implements SchemaConverter {
35
+ private readonly converters;
36
+ constructor(converters: ConditionalSchemaConverter[]);
37
+ convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promise<[required: boolean, jsonSchema: JSONSchema]>;
38
+ }
39
+
40
+ interface OpenAPIGeneratorOptions extends StandardOpenAPIJsonSerializerOptions {
41
+ schemaConverters?: ConditionalSchemaConverter[];
42
+ }
43
+ interface OpenAPIGeneratorGenerateOptions extends Partial<Omit<OpenAPI.Document, 'openapi'>> {
44
+ /**
45
+ * Exclude procedures from the OpenAPI specification.
46
+ *
47
+ * @default () => false
48
+ */
49
+ exclude?: (procedure: AnyProcedure | AnyContractProcedure, path: readonly string[]) => boolean;
50
+ /**
51
+ * Common schemas to be used for $ref resolution.
52
+ */
53
+ commonSchemas?: Record<string, {
54
+ /**
55
+ * Determines which schema definition to use when input and output schemas differ.
56
+ * This is needed because some schemas transform data differently between input and output,
57
+ * making it impossible to use a single $ref for both cases.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * // This schema transforms a string input into a number output
62
+ * const Schema = z.string()
63
+ * .transform(v => Number(v))
64
+ * .pipe(z.number())
65
+ *
66
+ * // Input schema: { type: 'string' }
67
+ * // Output schema: { type: 'number' }
68
+ * ```
69
+ *
70
+ * When schemas differ between input and output, you must explicitly choose
71
+ * which version to use for the OpenAPI specification.
72
+ *
73
+ * @default 'input' - Uses the input schema definition by default
74
+ */
75
+ strategy?: SchemaConvertOptions['strategy'];
76
+ schema: AnySchema;
77
+ } | {
78
+ error: 'UndefinedError';
79
+ schema?: never;
80
+ }>;
81
+ }
82
+ /**
83
+ * The generator that converts oRPC routers/contracts to OpenAPI specifications.
84
+ *
85
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
86
+ */
87
+ declare class OpenAPIGenerator {
88
+ #private;
89
+ private readonly serializer;
90
+ private readonly converter;
91
+ constructor(options?: OpenAPIGeneratorOptions);
92
+ /**
93
+ * Generates OpenAPI specifications from oRPC routers/contracts.
94
+ *
95
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
96
+ */
97
+ generate(router: AnyContractRouter | AnyRouter, options?: OpenAPIGeneratorGenerateOptions): Promise<OpenAPI.Document>;
98
+ }
99
+
100
+ export { OpenAPIGenerator as b, CompositeSchemaConverter as e };
101
+ export type { ConditionalSchemaConverter as C, OpenAPIGeneratorOptions as O, SchemaConverterComponent as S, OpenAPIGeneratorGenerateOptions as a, SchemaConvertOptions as c, SchemaConverter as d };
@@ -0,0 +1,101 @@
1
+ import { AnySchema, OpenAPI, AnyContractProcedure, AnyContractRouter } from '@orpc/contract';
2
+ import { StandardOpenAPIJsonSerializerOptions } from '@orpc/openapi-client/standard';
3
+ import { AnyProcedure, AnyRouter } from '@orpc/server';
4
+ import { Promisable } from '@orpc/shared';
5
+ import { JSONSchema } from 'json-schema-typed/draft-2020-12';
6
+
7
+ interface SchemaConverterComponent {
8
+ allowedStrategies: readonly SchemaConvertOptions['strategy'][];
9
+ schema: AnySchema;
10
+ required: boolean;
11
+ ref: string;
12
+ }
13
+ interface SchemaConvertOptions {
14
+ strategy: 'input' | 'output';
15
+ /**
16
+ * Common components should use `$ref` to represent themselves if matched.
17
+ */
18
+ components?: readonly SchemaConverterComponent[];
19
+ /**
20
+ * Minimum schema structure depth required before using `$ref` for components.
21
+ *
22
+ * For example, if set to 2, `$ref` will only be used for schemas nested at depth 2 or greater.
23
+ *
24
+ * @default 0 - No depth limit;
25
+ */
26
+ minStructureDepthForRef?: number;
27
+ }
28
+ interface SchemaConverter {
29
+ convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<[required: boolean, jsonSchema: JSONSchema]>;
30
+ }
31
+ interface ConditionalSchemaConverter extends SchemaConverter {
32
+ condition(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<boolean>;
33
+ }
34
+ declare class CompositeSchemaConverter implements SchemaConverter {
35
+ private readonly converters;
36
+ constructor(converters: ConditionalSchemaConverter[]);
37
+ convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promise<[required: boolean, jsonSchema: JSONSchema]>;
38
+ }
39
+
40
+ interface OpenAPIGeneratorOptions extends StandardOpenAPIJsonSerializerOptions {
41
+ schemaConverters?: ConditionalSchemaConverter[];
42
+ }
43
+ interface OpenAPIGeneratorGenerateOptions extends Partial<Omit<OpenAPI.Document, 'openapi'>> {
44
+ /**
45
+ * Exclude procedures from the OpenAPI specification.
46
+ *
47
+ * @default () => false
48
+ */
49
+ exclude?: (procedure: AnyProcedure | AnyContractProcedure, path: readonly string[]) => boolean;
50
+ /**
51
+ * Common schemas to be used for $ref resolution.
52
+ */
53
+ commonSchemas?: Record<string, {
54
+ /**
55
+ * Determines which schema definition to use when input and output schemas differ.
56
+ * This is needed because some schemas transform data differently between input and output,
57
+ * making it impossible to use a single $ref for both cases.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * // This schema transforms a string input into a number output
62
+ * const Schema = z.string()
63
+ * .transform(v => Number(v))
64
+ * .pipe(z.number())
65
+ *
66
+ * // Input schema: { type: 'string' }
67
+ * // Output schema: { type: 'number' }
68
+ * ```
69
+ *
70
+ * When schemas differ between input and output, you must explicitly choose
71
+ * which version to use for the OpenAPI specification.
72
+ *
73
+ * @default 'input' - Uses the input schema definition by default
74
+ */
75
+ strategy?: SchemaConvertOptions['strategy'];
76
+ schema: AnySchema;
77
+ } | {
78
+ error: 'UndefinedError';
79
+ schema?: never;
80
+ }>;
81
+ }
82
+ /**
83
+ * The generator that converts oRPC routers/contracts to OpenAPI specifications.
84
+ *
85
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
86
+ */
87
+ declare class OpenAPIGenerator {
88
+ #private;
89
+ private readonly serializer;
90
+ private readonly converter;
91
+ constructor(options?: OpenAPIGeneratorOptions);
92
+ /**
93
+ * Generates OpenAPI specifications from oRPC routers/contracts.
94
+ *
95
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
96
+ */
97
+ generate(router: AnyContractRouter | AnyRouter, options?: OpenAPIGeneratorGenerateOptions): Promise<OpenAPI.Document>;
98
+ }
99
+
100
+ export { OpenAPIGenerator as b, CompositeSchemaConverter as e };
101
+ export type { ConditionalSchemaConverter as C, OpenAPIGeneratorOptions as O, SchemaConverterComponent as S, OpenAPIGeneratorGenerateOptions as a, SchemaConvertOptions as c, SchemaConverter as d };
@@ -3,8 +3,8 @@ import { toHttpPath } from '@orpc/client/standard';
3
3
  import { fallbackContractConfig, getEventIteratorSchemaDetails } from '@orpc/contract';
4
4
  import { standardizeHTTPPath, StandardOpenAPIJsonSerializer, getDynamicParams } from '@orpc/openapi-client/standard';
5
5
  import { isProcedure, resolveContractProcedures } from '@orpc/server';
6
- import { isObject, findDeepMatches, toArray, clone, stringifyJSON } from '@orpc/shared';
7
- import 'json-schema-typed/draft-2020-12';
6
+ import { isObject, stringifyJSON, findDeepMatches, toArray, clone } from '@orpc/shared';
7
+ import { TypeName } from 'json-schema-typed/draft-2020-12';
8
8
 
9
9
  const OPERATION_EXTENDER_SYMBOL = Symbol("ORPC_OPERATION_EXTENDER");
10
10
  function customOpenAPIOperation(o, extend) {
@@ -196,6 +196,45 @@ function expandUnionSchema(schema) {
196
196
  }
197
197
  return [schema];
198
198
  }
199
+ function expandArrayableSchema(schema) {
200
+ const schemas = expandUnionSchema(schema);
201
+ if (schemas.length !== 2) {
202
+ return void 0;
203
+ }
204
+ const arraySchema = schemas.find(
205
+ (s) => typeof s === "object" && s.type === "array" && Object.keys(s).filter((k) => LOGIC_KEYWORDS.includes(k)).every((k) => k === "type" || k === "items")
206
+ );
207
+ if (arraySchema === void 0) {
208
+ return void 0;
209
+ }
210
+ const items1 = arraySchema.items;
211
+ const items2 = schemas.find((s) => s !== arraySchema);
212
+ if (stringifyJSON(items1) !== stringifyJSON(items2)) {
213
+ return void 0;
214
+ }
215
+ return [items2, arraySchema];
216
+ }
217
+ const PRIMITIVE_SCHEMA_TYPES = /* @__PURE__ */ new Set([
218
+ TypeName.String,
219
+ TypeName.Number,
220
+ TypeName.Integer,
221
+ TypeName.Boolean,
222
+ TypeName.Null
223
+ ]);
224
+ function isPrimitiveSchema(schema) {
225
+ return expandUnionSchema(schema).every((s) => {
226
+ if (typeof s === "boolean") {
227
+ return false;
228
+ }
229
+ if (typeof s.type === "string" && PRIMITIVE_SCHEMA_TYPES.has(s.type)) {
230
+ return true;
231
+ }
232
+ if (s.const !== void 0) {
233
+ return true;
234
+ }
235
+ return false;
236
+ });
237
+ }
199
238
 
200
239
  function toOpenAPIPath(path) {
201
240
  return standardizeHTTPPath(path).replace(/\/\{\+([^}]+)\}/g, "/{$1}");
@@ -268,13 +307,26 @@ function toOpenAPIParameters(schema, parameterIn) {
268
307
  const parameters = [];
269
308
  for (const key in schema.properties) {
270
309
  const keySchema = schema.properties[key];
310
+ let isDeepObjectStyle = true;
311
+ if (parameterIn !== "query") {
312
+ isDeepObjectStyle = false;
313
+ } else if (isPrimitiveSchema(keySchema)) {
314
+ isDeepObjectStyle = false;
315
+ } else {
316
+ const [item] = expandArrayableSchema(keySchema) ?? [];
317
+ if (item !== void 0 && isPrimitiveSchema(item)) {
318
+ isDeepObjectStyle = false;
319
+ }
320
+ }
271
321
  parameters.push({
272
322
  name: key,
273
323
  in: parameterIn,
274
324
  required: schema.required?.includes(key),
275
- style: parameterIn === "query" ? "deepObject" : void 0,
276
- explode: parameterIn === "query" ? true : void 0,
277
- schema: toOpenAPISchema(keySchema)
325
+ schema: toOpenAPISchema(keySchema),
326
+ style: isDeepObjectStyle ? "deepObject" : void 0,
327
+ explode: isDeepObjectStyle ? true : void 0,
328
+ allowEmptyValue: parameterIn === "query" ? true : void 0,
329
+ allowReserved: parameterIn === "query" ? true : void 0
278
330
  });
279
331
  }
280
332
  return parameters;
@@ -293,6 +345,15 @@ function checkParamsSchema(schema, params) {
293
345
  function toOpenAPISchema(schema) {
294
346
  return schema === true ? {} : schema === false ? { not: {} } : schema;
295
347
  }
348
+ const OPENAPI_JSON_SCHEMA_REF_PREFIX = "#/components/schemas/";
349
+ function resolveOpenAPIJsonSchemaRef(doc, schema) {
350
+ if (typeof schema !== "object" || !schema.$ref?.startsWith(OPENAPI_JSON_SCHEMA_REF_PREFIX)) {
351
+ return schema;
352
+ }
353
+ const name = schema.$ref.slice(OPENAPI_JSON_SCHEMA_REF_PREFIX.length);
354
+ const resolved = doc.components?.schemas?.[name];
355
+ return resolved ?? schema;
356
+ }
296
357
 
297
358
  class CompositeSchemaConverter {
298
359
  converters;
@@ -329,8 +390,10 @@ class OpenAPIGenerator {
329
390
  ...clone(options),
330
391
  info: options.info ?? { title: "API Reference", version: "0.0.0" },
331
392
  openapi: "3.1.1",
332
- exclude: void 0
393
+ exclude: void 0,
394
+ commonSchemas: void 0
333
395
  };
396
+ const { baseSchemaConvertOptions, undefinedErrorJsonSchema } = await this.#resolveCommonSchemas(doc, options.commonSchemas);
334
397
  const contracts = [];
335
398
  await resolveContractProcedures({ path: [], router }, ({ contract, path }) => {
336
399
  if (!exclude(contract, path)) {
@@ -344,16 +407,21 @@ class OpenAPIGenerator {
344
407
  const def = contract["~orpc"];
345
408
  const method = toOpenAPIMethod(fallbackContractConfig("defaultMethod", def.route.method));
346
409
  const httpPath = toOpenAPIPath(def.route.path ?? toHttpPath(path));
347
- const operationObjectRef = {
348
- operationId,
349
- summary: def.route.summary,
350
- description: def.route.description,
351
- deprecated: def.route.deprecated,
352
- tags: def.route.tags?.map((tag) => tag)
353
- };
354
- await this.#request(operationObjectRef, def);
355
- await this.#successResponse(operationObjectRef, def);
356
- await this.#errorResponse(operationObjectRef, def);
410
+ let operationObjectRef;
411
+ if (def.route.spec !== void 0) {
412
+ operationObjectRef = def.route.spec;
413
+ } else {
414
+ operationObjectRef = {
415
+ operationId,
416
+ summary: def.route.summary,
417
+ description: def.route.description,
418
+ deprecated: def.route.deprecated,
419
+ tags: def.route.tags?.map((tag) => tag)
420
+ };
421
+ await this.#request(doc, operationObjectRef, def, baseSchemaConvertOptions);
422
+ await this.#successResponse(doc, operationObjectRef, def, baseSchemaConvertOptions);
423
+ await this.#errorResponse(operationObjectRef, def, baseSchemaConvertOptions, undefinedErrorJsonSchema);
424
+ }
357
425
  doc.paths ??= {};
358
426
  doc.paths[httpPath] ??= {};
359
427
  doc.paths[httpPath][method] = applyCustomOpenAPIOperation(operationObjectRef, contract);
@@ -376,22 +444,96 @@ ${errors.join("\n\n")}`
376
444
  }
377
445
  return this.serializer.serialize(doc)[0];
378
446
  }
379
- async #request(ref, def) {
447
+ async #resolveCommonSchemas(doc, commonSchemas) {
448
+ let undefinedErrorJsonSchema = {
449
+ type: "object",
450
+ properties: {
451
+ defined: { const: false },
452
+ code: { type: "string" },
453
+ status: { type: "number" },
454
+ message: { type: "string" },
455
+ data: {}
456
+ },
457
+ required: ["defined", "code", "status", "message"]
458
+ };
459
+ const baseSchemaConvertOptions = {};
460
+ if (commonSchemas) {
461
+ baseSchemaConvertOptions.components = [];
462
+ for (const key in commonSchemas) {
463
+ const options = commonSchemas[key];
464
+ if (options.schema === void 0) {
465
+ continue;
466
+ }
467
+ const { schema, strategy = "input" } = options;
468
+ const [required, json] = await this.converter.convert(schema, { strategy });
469
+ const allowedStrategies = [strategy];
470
+ if (strategy === "input") {
471
+ const [outputRequired, outputJson] = await this.converter.convert(schema, { strategy: "output" });
472
+ if (outputRequired === required && stringifyJSON(outputJson) === stringifyJSON(json)) {
473
+ allowedStrategies.push("output");
474
+ }
475
+ } else if (strategy === "output") {
476
+ const [inputRequired, inputJson] = await this.converter.convert(schema, { strategy: "input" });
477
+ if (inputRequired === required && stringifyJSON(inputJson) === stringifyJSON(json)) {
478
+ allowedStrategies.push("input");
479
+ }
480
+ }
481
+ baseSchemaConvertOptions.components.push({
482
+ schema,
483
+ required,
484
+ ref: `#/components/schemas/${key}`,
485
+ allowedStrategies
486
+ });
487
+ }
488
+ doc.components ??= {};
489
+ doc.components.schemas ??= {};
490
+ for (const key in commonSchemas) {
491
+ const options = commonSchemas[key];
492
+ if (options.schema === void 0) {
493
+ if (options.error === "UndefinedError") {
494
+ doc.components.schemas[key] = toOpenAPISchema(undefinedErrorJsonSchema);
495
+ undefinedErrorJsonSchema = { $ref: `#/components/schemas/${key}` };
496
+ }
497
+ continue;
498
+ }
499
+ const { schema, strategy = "input" } = options;
500
+ const [, json] = await this.converter.convert(
501
+ schema,
502
+ {
503
+ ...baseSchemaConvertOptions,
504
+ strategy,
505
+ minStructureDepthForRef: 1
506
+ // not allow use $ref for root schemas
507
+ }
508
+ );
509
+ doc.components.schemas[key] = toOpenAPISchema(json);
510
+ }
511
+ }
512
+ return { baseSchemaConvertOptions, undefinedErrorJsonSchema };
513
+ }
514
+ async #request(doc, ref, def, baseSchemaConvertOptions) {
380
515
  const method = fallbackContractConfig("defaultMethod", def.route.method);
381
516
  const details = getEventIteratorSchemaDetails(def.inputSchema);
382
517
  if (details) {
383
518
  ref.requestBody = {
384
519
  required: true,
385
520
  content: toOpenAPIEventIteratorContent(
386
- await this.converter.convert(details.yields, { strategy: "input" }),
387
- await this.converter.convert(details.returns, { strategy: "input" })
521
+ await this.converter.convert(details.yields, { ...baseSchemaConvertOptions, strategy: "input" }),
522
+ await this.converter.convert(details.returns, { ...baseSchemaConvertOptions, strategy: "input" })
388
523
  )
389
524
  };
390
525
  return;
391
526
  }
392
527
  const dynamicParams = getDynamicParams(def.route.path)?.map((v) => v.name);
393
528
  const inputStructure = fallbackContractConfig("defaultInputStructure", def.route.inputStructure);
394
- let [required, schema] = await this.converter.convert(def.inputSchema, { strategy: "input" });
529
+ let [required, schema] = await this.converter.convert(
530
+ def.inputSchema,
531
+ {
532
+ ...baseSchemaConvertOptions,
533
+ strategy: "input",
534
+ minStructureDepthForRef: dynamicParams?.length || inputStructure === "detailed" ? 1 : 0
535
+ }
536
+ );
395
537
  if (isAnySchema(schema) && !dynamicParams?.length) {
396
538
  return;
397
539
  }
@@ -434,7 +576,8 @@ ${errors.join("\n\n")}`
434
576
  if (!isObjectSchema(schema)) {
435
577
  throw error;
436
578
  }
437
- if (dynamicParams?.length && (schema.properties?.params === void 0 || !isObjectSchema(schema.properties.params) || !checkParamsSchema(schema.properties.params, dynamicParams))) {
579
+ const resolvedParamSchema = schema.properties?.params !== void 0 ? resolveOpenAPIJsonSchemaRef(doc, schema.properties.params) : void 0;
580
+ if (dynamicParams?.length && (resolvedParamSchema === void 0 || !isObjectSchema(resolvedParamSchema) || !checkParamsSchema(resolvedParamSchema, dynamicParams))) {
438
581
  throw new OpenAPIGeneratorError(
439
582
  'When input structure is "detailed" and path has dynamic params, the "params" schema must be an object with all dynamic params as required.'
440
583
  );
@@ -442,12 +585,13 @@ ${errors.join("\n\n")}`
442
585
  for (const from of ["params", "query", "headers"]) {
443
586
  const fromSchema = schema.properties?.[from];
444
587
  if (fromSchema !== void 0) {
445
- if (!isObjectSchema(fromSchema)) {
588
+ const resolvedSchema = resolveOpenAPIJsonSchemaRef(doc, fromSchema);
589
+ if (!isObjectSchema(resolvedSchema)) {
446
590
  throw error;
447
591
  }
448
592
  const parameterIn = from === "params" ? "path" : from === "headers" ? "header" : "query";
449
593
  ref.parameters ??= [];
450
- ref.parameters.push(...toOpenAPIParameters(fromSchema, parameterIn));
594
+ ref.parameters.push(...toOpenAPIParameters(resolvedSchema, parameterIn));
451
595
  }
452
596
  }
453
597
  if (schema.properties?.body !== void 0) {
@@ -457,7 +601,7 @@ ${errors.join("\n\n")}`
457
601
  };
458
602
  }
459
603
  }
460
- async #successResponse(ref, def) {
604
+ async #successResponse(doc, ref, def, baseSchemaConvertOptions) {
461
605
  const outputSchema = def.outputSchema;
462
606
  const status = fallbackContractConfig("defaultSuccessStatus", def.route.successStatus);
463
607
  const description = fallbackContractConfig("defaultSuccessDescription", def.route?.successDescription);
@@ -468,13 +612,20 @@ ${errors.join("\n\n")}`
468
612
  ref.responses[status] = {
469
613
  description,
470
614
  content: toOpenAPIEventIteratorContent(
471
- await this.converter.convert(eventIteratorSchemaDetails.yields, { strategy: "output" }),
472
- await this.converter.convert(eventIteratorSchemaDetails.returns, { strategy: "output" })
615
+ await this.converter.convert(eventIteratorSchemaDetails.yields, { ...baseSchemaConvertOptions, strategy: "output" }),
616
+ await this.converter.convert(eventIteratorSchemaDetails.returns, { ...baseSchemaConvertOptions, strategy: "output" })
473
617
  )
474
618
  };
475
619
  return;
476
620
  }
477
- const [required, json] = await this.converter.convert(outputSchema, { strategy: "output" });
621
+ const [required, json] = await this.converter.convert(
622
+ outputSchema,
623
+ {
624
+ ...baseSchemaConvertOptions,
625
+ strategy: "output",
626
+ minStructureDepthForRef: outputStructure === "detailed" ? 1 : 0
627
+ }
628
+ );
478
629
  if (outputStructure === "compact") {
479
630
  ref.responses ??= {};
480
631
  ref.responses[status] = {
@@ -501,11 +652,12 @@ ${errors.join("\n\n")}`
501
652
  let schemaStatus;
502
653
  let schemaDescription;
503
654
  if (item.properties?.status !== void 0) {
504
- if (typeof item.properties.status !== "object" || item.properties.status.const === void 0 || typeof item.properties.status.const !== "number" || !Number.isInteger(item.properties.status.const) || isORPCErrorStatus(item.properties.status.const)) {
655
+ const statusSchema = resolveOpenAPIJsonSchemaRef(doc, item.properties.status);
656
+ if (typeof statusSchema !== "object" || statusSchema.const === void 0 || typeof statusSchema.const !== "number" || !Number.isInteger(statusSchema.const) || isORPCErrorStatus(statusSchema.const)) {
505
657
  throw error;
506
658
  }
507
- schemaStatus = item.properties.status.const;
508
- schemaDescription = item.properties.status.description;
659
+ schemaStatus = statusSchema.const;
660
+ schemaDescription = statusSchema.description;
509
661
  }
510
662
  const itemStatus = schemaStatus ?? status;
511
663
  const itemDescription = schemaDescription ?? description;
@@ -521,16 +673,17 @@ ${errors.join("\n\n")}`
521
673
  description: itemDescription
522
674
  };
523
675
  if (item.properties?.headers !== void 0) {
524
- if (!isObjectSchema(item.properties.headers)) {
676
+ const headersSchema = resolveOpenAPIJsonSchemaRef(doc, item.properties.headers);
677
+ if (!isObjectSchema(headersSchema)) {
525
678
  throw error;
526
679
  }
527
- for (const key in item.properties.headers.properties) {
528
- const headerSchema = item.properties.headers.properties[key];
680
+ for (const key in headersSchema.properties) {
681
+ const headerSchema = headersSchema.properties[key];
529
682
  if (headerSchema !== void 0) {
530
683
  ref.responses[itemStatus].headers ??= {};
531
684
  ref.responses[itemStatus].headers[key] = {
532
685
  schema: toOpenAPISchema(headerSchema),
533
- required: item.properties.headers.required?.includes(key)
686
+ required: item.required?.includes("headers") && headersSchema.required?.includes(key)
534
687
  };
535
688
  }
536
689
  }
@@ -542,7 +695,7 @@ ${errors.join("\n\n")}`
542
695
  }
543
696
  }
544
697
  }
545
- async #errorResponse(ref, def) {
698
+ async #errorResponse(ref, def, baseSchemaConvertOptions, undefinedErrorSchema) {
546
699
  const errorMap = def.errorMap;
547
700
  const errors = {};
548
701
  for (const code in errorMap) {
@@ -552,7 +705,7 @@ ${errors.join("\n\n")}`
552
705
  }
553
706
  const status = fallbackORPCErrorStatus(code, config.status);
554
707
  const message = fallbackORPCErrorMessage(code, config.message);
555
- const [dataRequired, dataSchema] = await this.converter.convert(config.data, { strategy: "output" });
708
+ const [dataRequired, dataSchema] = await this.converter.convert(config.data, { ...baseSchemaConvertOptions, strategy: "output" });
556
709
  errors[status] ??= [];
557
710
  errors[status].push({
558
711
  type: "object",
@@ -574,17 +727,7 @@ ${errors.join("\n\n")}`
574
727
  content: toOpenAPIContent({
575
728
  oneOf: [
576
729
  ...schemas,
577
- {
578
- type: "object",
579
- properties: {
580
- defined: { const: false },
581
- code: { type: "string" },
582
- status: { type: "number" },
583
- message: { type: "string" },
584
- data: {}
585
- },
586
- required: ["defined", "code", "status", "message"]
587
- }
730
+ undefinedErrorSchema
588
731
  ]
589
732
  })
590
733
  };
@@ -592,4 +735,4 @@ ${errors.join("\n\n")}`
592
735
  }
593
736
  }
594
737
 
595
- 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, separateObjectSchema as s, toOpenAPIPath as t };
738
+ 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 };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/openapi",
3
3
  "type": "module",
4
- "version": "0.0.0-next.fb0d07c",
4
+ "version": "0.0.0-next.fc23c8d",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -38,6 +38,11 @@
38
38
  "types": "./dist/adapters/node/index.d.mts",
39
39
  "import": "./dist/adapters/node/index.mjs",
40
40
  "default": "./dist/adapters/node/index.mjs"
41
+ },
42
+ "./aws-lambda": {
43
+ "types": "./dist/adapters/aws-lambda/index.d.mts",
44
+ "import": "./dist/adapters/aws-lambda/index.mjs",
45
+ "default": "./dist/adapters/aws-lambda/index.mjs"
41
46
  }
42
47
  },
43
48
  "files": [
@@ -45,17 +50,16 @@
45
50
  ],
46
51
  "dependencies": {
47
52
  "json-schema-typed": "^8.0.1",
48
- "openapi-types": "^12.1.3",
49
- "rou3": "^0.6.0",
50
- "@orpc/client": "0.0.0-next.fb0d07c",
51
- "@orpc/contract": "0.0.0-next.fb0d07c",
52
- "@orpc/openapi-client": "0.0.0-next.fb0d07c",
53
- "@orpc/shared": "0.0.0-next.fb0d07c",
54
- "@orpc/server": "0.0.0-next.fb0d07c",
55
- "@orpc/standard-server": "0.0.0-next.fb0d07c"
53
+ "rou3": "^0.7.2",
54
+ "@orpc/client": "0.0.0-next.fc23c8d",
55
+ "@orpc/contract": "0.0.0-next.fc23c8d",
56
+ "@orpc/openapi-client": "0.0.0-next.fc23c8d",
57
+ "@orpc/server": "0.0.0-next.fc23c8d",
58
+ "@orpc/shared": "0.0.0-next.fc23c8d",
59
+ "@orpc/standard-server": "0.0.0-next.fc23c8d"
56
60
  },
57
61
  "devDependencies": {
58
- "zod": "^3.25.11"
62
+ "zod": "^3.25.67"
59
63
  },
60
64
  "scripts": {
61
65
  "build": "unbuild",
@@ -1,53 +0,0 @@
1
- import { AnySchema, AnyContractProcedure, AnyContractRouter } from '@orpc/contract';
2
- import { StandardOpenAPIJsonSerializerOptions } from '@orpc/openapi-client/standard';
3
- import { AnyProcedure, AnyRouter } from '@orpc/server';
4
- import { OpenAPIV3_1 } from 'openapi-types';
5
- import { Promisable } from '@orpc/shared';
6
- import { JSONSchema } from 'json-schema-typed/draft-2020-12';
7
-
8
- interface SchemaConvertOptions {
9
- strategy: 'input' | 'output';
10
- }
11
- interface SchemaConverter {
12
- convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<[required: boolean, jsonSchema: JSONSchema]>;
13
- }
14
- interface ConditionalSchemaConverter extends SchemaConverter {
15
- condition(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<boolean>;
16
- }
17
- declare class CompositeSchemaConverter implements SchemaConverter {
18
- private readonly converters;
19
- constructor(converters: ConditionalSchemaConverter[]);
20
- convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promise<[required: boolean, jsonSchema: JSONSchema]>;
21
- }
22
-
23
- interface OpenAPIGeneratorOptions extends StandardOpenAPIJsonSerializerOptions {
24
- schemaConverters?: ConditionalSchemaConverter[];
25
- }
26
- interface OpenAPIGeneratorGenerateOptions extends Partial<Omit<OpenAPIV3_1.Document, 'openapi'>> {
27
- /**
28
- * Exclude procedures from the OpenAPI specification.
29
- *
30
- * @default () => false
31
- */
32
- exclude?: (procedure: AnyProcedure | AnyContractProcedure, path: readonly string[]) => boolean;
33
- }
34
- /**
35
- * The generator that converts oRPC routers/contracts to OpenAPI specifications.
36
- *
37
- * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
38
- */
39
- declare class OpenAPIGenerator {
40
- #private;
41
- private readonly serializer;
42
- private readonly converter;
43
- constructor(options?: OpenAPIGeneratorOptions);
44
- /**
45
- * Generates OpenAPI specifications from oRPC routers/contracts.
46
- *
47
- * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
48
- */
49
- generate(router: AnyContractRouter | AnyRouter, options?: OpenAPIGeneratorGenerateOptions): Promise<OpenAPIV3_1.Document>;
50
- }
51
-
52
- export { OpenAPIGenerator as b, CompositeSchemaConverter as d };
53
- export type { ConditionalSchemaConverter as C, OpenAPIGeneratorOptions as O, SchemaConvertOptions as S, OpenAPIGeneratorGenerateOptions as a, SchemaConverter as c };
@@ -1,53 +0,0 @@
1
- import { AnySchema, AnyContractProcedure, AnyContractRouter } from '@orpc/contract';
2
- import { StandardOpenAPIJsonSerializerOptions } from '@orpc/openapi-client/standard';
3
- import { AnyProcedure, AnyRouter } from '@orpc/server';
4
- import { OpenAPIV3_1 } from 'openapi-types';
5
- import { Promisable } from '@orpc/shared';
6
- import { JSONSchema } from 'json-schema-typed/draft-2020-12';
7
-
8
- interface SchemaConvertOptions {
9
- strategy: 'input' | 'output';
10
- }
11
- interface SchemaConverter {
12
- convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<[required: boolean, jsonSchema: JSONSchema]>;
13
- }
14
- interface ConditionalSchemaConverter extends SchemaConverter {
15
- condition(schema: AnySchema | undefined, options: SchemaConvertOptions): Promisable<boolean>;
16
- }
17
- declare class CompositeSchemaConverter implements SchemaConverter {
18
- private readonly converters;
19
- constructor(converters: ConditionalSchemaConverter[]);
20
- convert(schema: AnySchema | undefined, options: SchemaConvertOptions): Promise<[required: boolean, jsonSchema: JSONSchema]>;
21
- }
22
-
23
- interface OpenAPIGeneratorOptions extends StandardOpenAPIJsonSerializerOptions {
24
- schemaConverters?: ConditionalSchemaConverter[];
25
- }
26
- interface OpenAPIGeneratorGenerateOptions extends Partial<Omit<OpenAPIV3_1.Document, 'openapi'>> {
27
- /**
28
- * Exclude procedures from the OpenAPI specification.
29
- *
30
- * @default () => false
31
- */
32
- exclude?: (procedure: AnyProcedure | AnyContractProcedure, path: readonly string[]) => boolean;
33
- }
34
- /**
35
- * The generator that converts oRPC routers/contracts to OpenAPI specifications.
36
- *
37
- * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
38
- */
39
- declare class OpenAPIGenerator {
40
- #private;
41
- private readonly serializer;
42
- private readonly converter;
43
- constructor(options?: OpenAPIGeneratorOptions);
44
- /**
45
- * Generates OpenAPI specifications from oRPC routers/contracts.
46
- *
47
- * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification OpenAPI Specification Docs}
48
- */
49
- generate(router: AnyContractRouter | AnyRouter, options?: OpenAPIGeneratorGenerateOptions): Promise<OpenAPIV3_1.Document>;
50
- }
51
-
52
- export { OpenAPIGenerator as b, CompositeSchemaConverter as d };
53
- export type { ConditionalSchemaConverter as C, OpenAPIGeneratorOptions as O, SchemaConvertOptions as S, OpenAPIGeneratorGenerateOptions as a, SchemaConverter as c };