@orpc/contract 1.2.0 → 1.4.0

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
@@ -49,6 +49,7 @@ 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
53
  - [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
53
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).
54
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).
package/dist/index.d.mts CHANGED
@@ -3,6 +3,8 @@ export { HTTPMethod, HTTPPath, ORPCError } from '@orpc/client';
3
3
  import { Promisable, IsEqual, ThrowableError } from '@orpc/shared';
4
4
  export { Registry, ThrowableError } from '@orpc/shared';
5
5
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
+ import { OpenAPIV3_1 } from 'openapi-types';
7
+ export { OpenAPIV3_1 as OpenAPI } from 'openapi-types';
6
8
 
7
9
  type Schema<TInput, TOutput> = StandardSchemaV1<TInput, TOutput>;
8
10
  type AnySchema = Schema<any, any>;
@@ -96,6 +98,7 @@ interface Route {
96
98
  tags?: readonly string[];
97
99
  /**
98
100
  * The status code of the response when the procedure is successful.
101
+ * The status code must be in the 200-399 range.
99
102
  * This option is typically relevant when integrating with OpenAPI.
100
103
  *
101
104
  * @see {@link https://orpc.unnoq.com/docs/openapi/routing OpenAPI Routing Docs}
@@ -137,16 +140,18 @@ interface Route {
137
140
  * Determines how the response should be structured based on the output.
138
141
  *
139
142
  * @option 'compact'
140
- * Includes only the body data, encoded directly in the response.
143
+ * The output data is directly returned as the response body.
141
144
  *
142
145
  * @option 'detailed'
143
- * Separates the output into `headers` and `body` fields.
144
- * - `headers`: Custom headers to merge with the response headers.
145
- * - `body`: The response data.
146
+ * Return an object with optional properties:
147
+ * - `status`: The response status (must be in 200-399 range) if not set fallback to `successStatus`.
148
+ * - `headers`: Custom headers to merge with the response headers (`Record<string, string | string[] | undefined>`)
149
+ * - `body`: The response body.
146
150
  *
147
151
  * Example:
148
152
  * ```ts
149
153
  * const output = {
154
+ * status: 201,
150
155
  * headers: { 'x-custom-header': 'value' },
151
156
  * body: { message: 'Hello, world!' },
152
157
  * };
@@ -156,6 +161,12 @@ interface Route {
156
161
  * @default 'compact'
157
162
  */
158
163
  outputStructure?: OutputStructure;
164
+ /**
165
+ * Override entire auto-generated OpenAPI Operation Object Specification.
166
+ *
167
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification#operation-metadata Operation Metadata Docs}
168
+ */
169
+ spec?: OpenAPIV3_1.OperationObject;
159
170
  }
160
171
  declare function mergeRoute(a: Route, b: Route): Route;
161
172
  declare function prefixRoute(route: Route, prefix: HTTPPath): Route;
@@ -237,6 +248,15 @@ interface EnhanceContractRouterOptions<TErrorMap extends ErrorMap> extends Enhan
237
248
  errorMap: TErrorMap;
238
249
  }
239
250
  declare function enhanceContractRouter<T extends AnyContractRouter, TErrorMap extends ErrorMap>(router: T, options: EnhanceContractRouterOptions<TErrorMap>): EnhancedContractRouter<T, TErrorMap>;
251
+ /**
252
+ * Minify a contract router into a smaller object.
253
+ *
254
+ * You should export the result to a JSON file. On the client side, you can import this JSON file and use it as a contract router.
255
+ * This reduces the size of the contract and helps prevent leaking internal details of the router to the client.
256
+ *
257
+ * @see {@link https://orpc.unnoq.com/docs/contract-first/router-to-contract#minify-export-the-contract-router-for-the-client Router to Contract Docs}
258
+ */
259
+ declare function minifyContractRouter(router: AnyContractRouter): AnyContractRouter;
240
260
 
241
261
  interface ContractProcedureBuilder<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, TMeta extends Meta> extends ContractProcedure<TInputSchema, TOutputSchema, TErrorMap, TMeta> {
242
262
  /**
@@ -501,11 +521,20 @@ interface EventIteratorSchemaDetails {
501
521
  declare function eventIterator<TYieldIn, TYieldOut, TReturnIn = unknown, TReturnOut = unknown>(yields: Schema<TYieldIn, TYieldOut>, returns?: Schema<TReturnIn, TReturnOut>): Schema<AsyncIteratorObject<TYieldIn, TReturnIn, void>, AsyncIteratorObject<TYieldOut, TReturnOut, void>>;
502
522
  declare function getEventIteratorSchemaDetails(schema: AnySchema | undefined): undefined | EventIteratorSchemaDetails;
503
523
 
524
+ /**
525
+ * Help RPCLink automatically send requests using the specified HTTP method in the contract.
526
+ *
527
+ * @see {@link https://orpc.unnoq.com/docs/client/rpc-link#custom-request-method RPCLink Custom Request Method}
528
+ */
529
+ declare function inferRPCMethodFromContractRouter(contract: AnyContractRouter): (options: unknown, path: readonly string[]) => Exclude<HTTPMethod, 'HEAD'>;
530
+
504
531
  type ContractProcedureClient<TClientContext extends ClientContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> = Client<TClientContext, InferSchemaInput<TInputSchema>, InferSchemaOutput<TOutputSchema>, ErrorFromErrorMap<TErrorMap>>;
505
532
 
506
533
  type ContractRouterClient<TRouter extends AnyContractRouter, TClientContext extends ClientContext = Record<never, never>> = TRouter extends ContractProcedure<infer UInputSchema, infer UOutputSchema, infer UErrorMap, any> ? ContractProcedureClient<TClientContext, UInputSchema, UOutputSchema, UErrorMap> : {
507
534
  [K in keyof TRouter]: TRouter[K] extends AnyContractRouter ? ContractRouterClient<TRouter[K], TClientContext> : never;
508
535
  };
509
536
 
510
- export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, isContractProcedure, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, oc, prefixRoute, type, unshiftTagRoute };
537
+ declare function isSchemaIssue(issue: unknown): issue is SchemaIssue;
538
+
539
+ export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, inferRPCMethodFromContractRouter, isContractProcedure, isSchemaIssue, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, minifyContractRouter, oc, prefixRoute, type, unshiftTagRoute };
511
540
  export type { AnyContractProcedure, AnyContractRouter, AnySchema, ContractBuilderDef, ContractConfig, ContractProcedureBuilder, ContractProcedureBuilderWithInput, ContractProcedureBuilderWithInputOutput, ContractProcedureBuilderWithOutput, ContractProcedureClient, ContractProcedureDef, ContractRouter, ContractRouterBuilder, ContractRouterClient, EnhanceContractRouterOptions, EnhanceRouteOptions, EnhancedContractRouter, ErrorFromErrorMap, ErrorMap, ErrorMapItem, EventIteratorSchemaDetails, InferContractRouterErrorMap, InferContractRouterInputs, InferContractRouterMeta, InferContractRouterOutputs, InferSchemaInput, InferSchemaOutput, InputStructure, MergedErrorMap, Meta, ORPCErrorFromErrorMap, OutputStructure, Route, Schema, SchemaIssue, TypeRest, ValidationErrorOptions };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export { HTTPMethod, HTTPPath, ORPCError } from '@orpc/client';
3
3
  import { Promisable, IsEqual, ThrowableError } from '@orpc/shared';
4
4
  export { Registry, ThrowableError } from '@orpc/shared';
5
5
  import { StandardSchemaV1 } from '@standard-schema/spec';
6
+ import { OpenAPIV3_1 } from 'openapi-types';
7
+ export { OpenAPIV3_1 as OpenAPI } from 'openapi-types';
6
8
 
7
9
  type Schema<TInput, TOutput> = StandardSchemaV1<TInput, TOutput>;
8
10
  type AnySchema = Schema<any, any>;
@@ -96,6 +98,7 @@ interface Route {
96
98
  tags?: readonly string[];
97
99
  /**
98
100
  * The status code of the response when the procedure is successful.
101
+ * The status code must be in the 200-399 range.
99
102
  * This option is typically relevant when integrating with OpenAPI.
100
103
  *
101
104
  * @see {@link https://orpc.unnoq.com/docs/openapi/routing OpenAPI Routing Docs}
@@ -137,16 +140,18 @@ interface Route {
137
140
  * Determines how the response should be structured based on the output.
138
141
  *
139
142
  * @option 'compact'
140
- * Includes only the body data, encoded directly in the response.
143
+ * The output data is directly returned as the response body.
141
144
  *
142
145
  * @option 'detailed'
143
- * Separates the output into `headers` and `body` fields.
144
- * - `headers`: Custom headers to merge with the response headers.
145
- * - `body`: The response data.
146
+ * Return an object with optional properties:
147
+ * - `status`: The response status (must be in 200-399 range) if not set fallback to `successStatus`.
148
+ * - `headers`: Custom headers to merge with the response headers (`Record<string, string | string[] | undefined>`)
149
+ * - `body`: The response body.
146
150
  *
147
151
  * Example:
148
152
  * ```ts
149
153
  * const output = {
154
+ * status: 201,
150
155
  * headers: { 'x-custom-header': 'value' },
151
156
  * body: { message: 'Hello, world!' },
152
157
  * };
@@ -156,6 +161,12 @@ interface Route {
156
161
  * @default 'compact'
157
162
  */
158
163
  outputStructure?: OutputStructure;
164
+ /**
165
+ * Override entire auto-generated OpenAPI Operation Object Specification.
166
+ *
167
+ * @see {@link https://orpc.unnoq.com/docs/openapi/openapi-specification#operation-metadata Operation Metadata Docs}
168
+ */
169
+ spec?: OpenAPIV3_1.OperationObject;
159
170
  }
160
171
  declare function mergeRoute(a: Route, b: Route): Route;
161
172
  declare function prefixRoute(route: Route, prefix: HTTPPath): Route;
@@ -237,6 +248,15 @@ interface EnhanceContractRouterOptions<TErrorMap extends ErrorMap> extends Enhan
237
248
  errorMap: TErrorMap;
238
249
  }
239
250
  declare function enhanceContractRouter<T extends AnyContractRouter, TErrorMap extends ErrorMap>(router: T, options: EnhanceContractRouterOptions<TErrorMap>): EnhancedContractRouter<T, TErrorMap>;
251
+ /**
252
+ * Minify a contract router into a smaller object.
253
+ *
254
+ * You should export the result to a JSON file. On the client side, you can import this JSON file and use it as a contract router.
255
+ * This reduces the size of the contract and helps prevent leaking internal details of the router to the client.
256
+ *
257
+ * @see {@link https://orpc.unnoq.com/docs/contract-first/router-to-contract#minify-export-the-contract-router-for-the-client Router to Contract Docs}
258
+ */
259
+ declare function minifyContractRouter(router: AnyContractRouter): AnyContractRouter;
240
260
 
241
261
  interface ContractProcedureBuilder<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, TMeta extends Meta> extends ContractProcedure<TInputSchema, TOutputSchema, TErrorMap, TMeta> {
242
262
  /**
@@ -501,11 +521,20 @@ interface EventIteratorSchemaDetails {
501
521
  declare function eventIterator<TYieldIn, TYieldOut, TReturnIn = unknown, TReturnOut = unknown>(yields: Schema<TYieldIn, TYieldOut>, returns?: Schema<TReturnIn, TReturnOut>): Schema<AsyncIteratorObject<TYieldIn, TReturnIn, void>, AsyncIteratorObject<TYieldOut, TReturnOut, void>>;
502
522
  declare function getEventIteratorSchemaDetails(schema: AnySchema | undefined): undefined | EventIteratorSchemaDetails;
503
523
 
524
+ /**
525
+ * Help RPCLink automatically send requests using the specified HTTP method in the contract.
526
+ *
527
+ * @see {@link https://orpc.unnoq.com/docs/client/rpc-link#custom-request-method RPCLink Custom Request Method}
528
+ */
529
+ declare function inferRPCMethodFromContractRouter(contract: AnyContractRouter): (options: unknown, path: readonly string[]) => Exclude<HTTPMethod, 'HEAD'>;
530
+
504
531
  type ContractProcedureClient<TClientContext extends ClientContext, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> = Client<TClientContext, InferSchemaInput<TInputSchema>, InferSchemaOutput<TOutputSchema>, ErrorFromErrorMap<TErrorMap>>;
505
532
 
506
533
  type ContractRouterClient<TRouter extends AnyContractRouter, TClientContext extends ClientContext = Record<never, never>> = TRouter extends ContractProcedure<infer UInputSchema, infer UOutputSchema, infer UErrorMap, any> ? ContractProcedureClient<TClientContext, UInputSchema, UOutputSchema, UErrorMap> : {
507
534
  [K in keyof TRouter]: TRouter[K] extends AnyContractRouter ? ContractRouterClient<TRouter[K], TClientContext> : never;
508
535
  };
509
536
 
510
- export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, isContractProcedure, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, oc, prefixRoute, type, unshiftTagRoute };
537
+ declare function isSchemaIssue(issue: unknown): issue is SchemaIssue;
538
+
539
+ export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, inferRPCMethodFromContractRouter, isContractProcedure, isSchemaIssue, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, minifyContractRouter, oc, prefixRoute, type, unshiftTagRoute };
511
540
  export type { AnyContractProcedure, AnyContractRouter, AnySchema, ContractBuilderDef, ContractConfig, ContractProcedureBuilder, ContractProcedureBuilderWithInput, ContractProcedureBuilderWithInputOutput, ContractProcedureBuilderWithOutput, ContractProcedureClient, ContractProcedureDef, ContractRouter, ContractRouterBuilder, ContractRouterClient, EnhanceContractRouterOptions, EnhanceRouteOptions, EnhancedContractRouter, ErrorFromErrorMap, ErrorMap, ErrorMapItem, EventIteratorSchemaDetails, InferContractRouterErrorMap, InferContractRouterInputs, InferContractRouterMeta, InferContractRouterOutputs, InferSchemaInput, InferSchemaOutput, InputStructure, MergedErrorMap, Meta, ORPCErrorFromErrorMap, OutputStructure, Route, Schema, SchemaIssue, TypeRest, ValidationErrorOptions };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isORPCErrorStatus, mapEventIterator, ORPCError } from '@orpc/client';
2
2
  export { ORPCError } from '@orpc/client';
3
- import { isAsyncIteratorObject } from '@orpc/shared';
3
+ import { isAsyncIteratorObject, get, isTypescriptObject, isPropertyKey } from '@orpc/shared';
4
4
 
5
5
  class ValidationError extends Error {
6
6
  issues;
@@ -103,6 +103,23 @@ function enhanceContractRouter(router, options) {
103
103
  }
104
104
  return enhanced;
105
105
  }
106
+ function minifyContractRouter(router) {
107
+ if (isContractProcedure(router)) {
108
+ const procedure = {
109
+ "~orpc": {
110
+ errorMap: {},
111
+ meta: router["~orpc"].meta,
112
+ route: router["~orpc"].route
113
+ }
114
+ };
115
+ return procedure;
116
+ }
117
+ const json = {};
118
+ for (const key in router) {
119
+ json[key] = minifyContractRouter(router[key]);
120
+ }
121
+ return json;
122
+ }
106
123
 
107
124
  class ContractBuilder extends ContractProcedure {
108
125
  constructor(def) {
@@ -292,6 +309,19 @@ function getEventIteratorSchemaDetails(schema) {
292
309
  return schema["~standard"][EVENT_ITERATOR_DETAILS_SYMBOL];
293
310
  }
294
311
 
312
+ function inferRPCMethodFromContractRouter(contract) {
313
+ return (_, path) => {
314
+ const procedure = get(contract, path);
315
+ if (!isContractProcedure(procedure)) {
316
+ throw new Error(
317
+ `[inferRPCMethodFromContractRouter] No valid procedure found at path "${path.join(".")}". This may happen when the contract router is not properly configured.`
318
+ );
319
+ }
320
+ const method = fallbackContractConfig("defaultMethod", procedure["~orpc"].route.method);
321
+ return method === "HEAD" ? "GET" : method;
322
+ };
323
+ }
324
+
295
325
  function type(...[map]) {
296
326
  return {
297
327
  "~standard": {
@@ -307,4 +337,19 @@ function type(...[map]) {
307
337
  };
308
338
  }
309
339
 
310
- export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, isContractProcedure, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, oc, prefixRoute, type, unshiftTagRoute };
340
+ function isSchemaIssue(issue) {
341
+ if (!isTypescriptObject(issue) || typeof issue.message !== "string") {
342
+ return false;
343
+ }
344
+ if (issue.path !== void 0) {
345
+ if (!Array.isArray(issue.path)) {
346
+ return false;
347
+ }
348
+ if (!issue.path.every((segment) => isPropertyKey(segment) || isTypescriptObject(segment) && isPropertyKey(segment.key))) {
349
+ return false;
350
+ }
351
+ }
352
+ return true;
353
+ }
354
+
355
+ export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, inferRPCMethodFromContractRouter, isContractProcedure, isSchemaIssue, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, minifyContractRouter, oc, prefixRoute, type, unshiftTagRoute };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/contract",
3
3
  "type": "module",
4
- "version": "1.2.0",
4
+ "version": "1.4.0",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -25,13 +25,14 @@
25
25
  ],
26
26
  "dependencies": {
27
27
  "@standard-schema/spec": "^1.0.0",
28
- "@orpc/shared": "1.2.0",
29
- "@orpc/client": "1.2.0"
28
+ "openapi-types": "^12.1.3",
29
+ "@orpc/client": "1.4.0",
30
+ "@orpc/shared": "1.4.0"
30
31
  },
31
32
  "devDependencies": {
32
33
  "arktype": "2.1.20",
33
- "valibot": "1.0.0",
34
- "zod": "^3.24.2"
34
+ "valibot": "^1.1.0",
35
+ "zod": "^3.25.49"
35
36
  },
36
37
  "scripts": {
37
38
  "build": "unbuild",