@orpc/contract 0.0.0-next.fc23c8d → 0.0.0-next.fc2dc8f
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 +10 -5
- package/dist/index.d.mts +69 -281
- package/dist/index.d.ts +69 -281
- package/dist/index.mjs +52 -49
- package/dist/plugins/index.d.mts +43 -0
- package/dist/plugins/index.d.ts +43 -0
- package/dist/plugins/index.mjs +81 -0
- package/dist/shared/contract.D_dZrO__.mjs +53 -0
- package/dist/shared/contract.TuRtB1Ca.d.mts +254 -0
- package/dist/shared/contract.TuRtB1Ca.d.ts +254 -0
- package/package.json +13 -8
package/dist/index.mjs
CHANGED
|
@@ -1,44 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as isContractProcedure, C as ContractProcedure, m as mergeErrorMap, V as ValidationError } from './shared/contract.D_dZrO__.mjs';
|
|
2
|
+
export { v as validateORPCError } from './shared/contract.D_dZrO__.mjs';
|
|
3
|
+
import { toHttpPath } from '@orpc/client/standard';
|
|
4
|
+
import { toArray, isAsyncIteratorObject, get, isTypescriptObject, isPropertyKey } from '@orpc/shared';
|
|
5
|
+
export { AsyncIteratorClass } from '@orpc/shared';
|
|
6
|
+
import { mapEventIterator, ORPCError } from '@orpc/client';
|
|
2
7
|
export { ORPCError } from '@orpc/client';
|
|
3
|
-
import { isAsyncIteratorObject, get, isTypescriptObject, isPropertyKey } from '@orpc/shared';
|
|
4
|
-
|
|
5
|
-
class ValidationError extends Error {
|
|
6
|
-
issues;
|
|
7
|
-
constructor(options) {
|
|
8
|
-
super(options.message, options);
|
|
9
|
-
this.issues = options.issues;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
function mergeErrorMap(errorMap1, errorMap2) {
|
|
13
|
-
return { ...errorMap1, ...errorMap2 };
|
|
14
|
-
}
|
|
15
8
|
|
|
16
9
|
function mergeMeta(meta1, meta2) {
|
|
17
10
|
return { ...meta1, ...meta2 };
|
|
18
11
|
}
|
|
19
12
|
|
|
20
|
-
class ContractProcedure {
|
|
21
|
-
/**
|
|
22
|
-
* This property holds the defined options for the contract procedure.
|
|
23
|
-
*/
|
|
24
|
-
"~orpc";
|
|
25
|
-
constructor(def) {
|
|
26
|
-
if (def.route?.successStatus && isORPCErrorStatus(def.route.successStatus)) {
|
|
27
|
-
throw new Error("[ContractProcedure] Invalid successStatus.");
|
|
28
|
-
}
|
|
29
|
-
if (Object.values(def.errorMap).some((val) => val && val.status && !isORPCErrorStatus(val.status))) {
|
|
30
|
-
throw new Error("[ContractProcedure] Invalid error status code.");
|
|
31
|
-
}
|
|
32
|
-
this["~orpc"] = def;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function isContractProcedure(item) {
|
|
36
|
-
if (item instanceof ContractProcedure) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
return (typeof item === "object" || typeof item === "function") && item !== null && "~orpc" in item && typeof item["~orpc"] === "object" && item["~orpc"] !== null && "errorMap" in item["~orpc"] && "route" in item["~orpc"] && "meta" in item["~orpc"];
|
|
40
|
-
}
|
|
41
|
-
|
|
42
13
|
function mergeRoute(a, b) {
|
|
43
14
|
return { ...a, ...b };
|
|
44
15
|
}
|
|
@@ -120,6 +91,26 @@ function minifyContractRouter(router) {
|
|
|
120
91
|
}
|
|
121
92
|
return json;
|
|
122
93
|
}
|
|
94
|
+
function populateContractRouterPaths(router, options = {}) {
|
|
95
|
+
const path = toArray(options.path);
|
|
96
|
+
if (isContractProcedure(router)) {
|
|
97
|
+
if (router["~orpc"].route.path === void 0) {
|
|
98
|
+
return new ContractProcedure({
|
|
99
|
+
...router["~orpc"],
|
|
100
|
+
route: {
|
|
101
|
+
...router["~orpc"].route,
|
|
102
|
+
path: toHttpPath(path)
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return router;
|
|
107
|
+
}
|
|
108
|
+
const populated = {};
|
|
109
|
+
for (const key in router) {
|
|
110
|
+
populated[key] = populateContractRouterPaths(router[key], { ...options, path: [...path, key] });
|
|
111
|
+
}
|
|
112
|
+
return populated;
|
|
113
|
+
}
|
|
123
114
|
|
|
124
115
|
class ContractBuilder extends ContractProcedure {
|
|
125
116
|
constructor(def) {
|
|
@@ -130,7 +121,7 @@ class ContractBuilder extends ContractProcedure {
|
|
|
130
121
|
/**
|
|
131
122
|
* Sets or overrides the initial meta.
|
|
132
123
|
*
|
|
133
|
-
* @see {@link https://orpc.
|
|
124
|
+
* @see {@link https://orpc.dev/docs/metadata Metadata Docs}
|
|
134
125
|
*/
|
|
135
126
|
$meta(initialMeta) {
|
|
136
127
|
return new ContractBuilder({
|
|
@@ -142,8 +133,8 @@ class ContractBuilder extends ContractProcedure {
|
|
|
142
133
|
* Sets or overrides the initial route.
|
|
143
134
|
* This option is typically relevant when integrating with OpenAPI.
|
|
144
135
|
*
|
|
145
|
-
* @see {@link https://orpc.
|
|
146
|
-
* @see {@link https://orpc.
|
|
136
|
+
* @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
|
|
137
|
+
* @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
|
|
147
138
|
*/
|
|
148
139
|
$route(initialRoute) {
|
|
149
140
|
return new ContractBuilder({
|
|
@@ -151,11 +142,22 @@ class ContractBuilder extends ContractProcedure {
|
|
|
151
142
|
route: initialRoute
|
|
152
143
|
});
|
|
153
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Sets or overrides the initial input schema.
|
|
147
|
+
*
|
|
148
|
+
* @see {@link https://orpc.dev/docs/procedure#initial-configuration Initial Procedure Configuration Docs}
|
|
149
|
+
*/
|
|
150
|
+
$input(initialInputSchema) {
|
|
151
|
+
return new ContractBuilder({
|
|
152
|
+
...this["~orpc"],
|
|
153
|
+
inputSchema: initialInputSchema
|
|
154
|
+
});
|
|
155
|
+
}
|
|
154
156
|
/**
|
|
155
157
|
* Adds type-safe custom errors to the contract.
|
|
156
158
|
* The provided errors are spared-merged with any existing errors in the contract.
|
|
157
159
|
*
|
|
158
|
-
* @see {@link https://orpc.
|
|
160
|
+
* @see {@link https://orpc.dev/docs/error-handling#type%E2%80%90safe-error-handling Type-Safe Error Handling Docs}
|
|
159
161
|
*/
|
|
160
162
|
errors(errors) {
|
|
161
163
|
return new ContractBuilder({
|
|
@@ -167,7 +169,7 @@ class ContractBuilder extends ContractProcedure {
|
|
|
167
169
|
* Sets or updates the metadata for the contract.
|
|
168
170
|
* The provided metadata is spared-merged with any existing metadata in the contract.
|
|
169
171
|
*
|
|
170
|
-
* @see {@link https://orpc.
|
|
172
|
+
* @see {@link https://orpc.dev/docs/metadata Metadata Docs}
|
|
171
173
|
*/
|
|
172
174
|
meta(meta) {
|
|
173
175
|
return new ContractBuilder({
|
|
@@ -180,8 +182,8 @@ class ContractBuilder extends ContractProcedure {
|
|
|
180
182
|
* The provided route is spared-merged with any existing route in the contract.
|
|
181
183
|
* This option is typically relevant when integrating with OpenAPI.
|
|
182
184
|
*
|
|
183
|
-
* @see {@link https://orpc.
|
|
184
|
-
* @see {@link https://orpc.
|
|
185
|
+
* @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
|
|
186
|
+
* @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
|
|
185
187
|
*/
|
|
186
188
|
route(route) {
|
|
187
189
|
return new ContractBuilder({
|
|
@@ -192,7 +194,7 @@ class ContractBuilder extends ContractProcedure {
|
|
|
192
194
|
/**
|
|
193
195
|
* Defines the input validation schema for the contract.
|
|
194
196
|
*
|
|
195
|
-
* @see {@link https://orpc.
|
|
197
|
+
* @see {@link https://orpc.dev/docs/procedure#input-output-validation Input Validation Docs}
|
|
196
198
|
*/
|
|
197
199
|
input(schema) {
|
|
198
200
|
return new ContractBuilder({
|
|
@@ -203,7 +205,7 @@ class ContractBuilder extends ContractProcedure {
|
|
|
203
205
|
/**
|
|
204
206
|
* Defines the output validation schema for the contract.
|
|
205
207
|
*
|
|
206
|
-
* @see {@link https://orpc.
|
|
208
|
+
* @see {@link https://orpc.dev/docs/procedure#input-output-validation Output Validation Docs}
|
|
207
209
|
*/
|
|
208
210
|
output(schema) {
|
|
209
211
|
return new ContractBuilder({
|
|
@@ -217,7 +219,7 @@ class ContractBuilder extends ContractProcedure {
|
|
|
217
219
|
*
|
|
218
220
|
* @note This option does not affect procedures that do not define a path in their route definition.
|
|
219
221
|
*
|
|
220
|
-
* @see {@link https://orpc.
|
|
222
|
+
* @see {@link https://orpc.dev/docs/openapi/routing#route-prefixes OpenAPI Route Prefixes Docs}
|
|
221
223
|
*/
|
|
222
224
|
prefix(prefix) {
|
|
223
225
|
return new ContractBuilder({
|
|
@@ -229,7 +231,7 @@ class ContractBuilder extends ContractProcedure {
|
|
|
229
231
|
* Adds tags to all procedures in the contract router.
|
|
230
232
|
* This helpful when you want to group procedures together in the OpenAPI specification.
|
|
231
233
|
*
|
|
232
|
-
* @see {@link https://orpc.
|
|
234
|
+
* @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata OpenAPI Operation Metadata Docs}
|
|
233
235
|
*/
|
|
234
236
|
tag(...tags) {
|
|
235
237
|
return new ContractBuilder({
|
|
@@ -240,7 +242,7 @@ class ContractBuilder extends ContractProcedure {
|
|
|
240
242
|
/**
|
|
241
243
|
* Applies all of the previously defined options to the specified contract router.
|
|
242
244
|
*
|
|
243
|
-
* @see {@link https://orpc.
|
|
245
|
+
* @see {@link https://orpc.dev/docs/router#extending-router Extending Router Docs}
|
|
244
246
|
*/
|
|
245
247
|
router(router) {
|
|
246
248
|
return enhanceContractRouter(router, this["~orpc"]);
|
|
@@ -289,7 +291,8 @@ function eventIterator(yields, returns) {
|
|
|
289
291
|
message: "Event iterator validation failed",
|
|
290
292
|
cause: new ValidationError({
|
|
291
293
|
issues: result.issues,
|
|
292
|
-
message: "Event iterator validation failed"
|
|
294
|
+
message: "Event iterator validation failed",
|
|
295
|
+
data: value
|
|
293
296
|
})
|
|
294
297
|
});
|
|
295
298
|
}
|
|
@@ -352,4 +355,4 @@ function isSchemaIssue(issue) {
|
|
|
352
355
|
return true;
|
|
353
356
|
}
|
|
354
357
|
|
|
355
|
-
export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, inferRPCMethodFromContractRouter, isContractProcedure, isSchemaIssue, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, minifyContractRouter, oc, prefixRoute, type, unshiftTagRoute };
|
|
358
|
+
export { ContractBuilder, ContractProcedure, ValidationError, enhanceContractRouter, enhanceRoute, eventIterator, fallbackContractConfig, getContractRouter, getEventIteratorSchemaDetails, inferRPCMethodFromContractRouter, isContractProcedure, isSchemaIssue, mergeErrorMap, mergeMeta, mergePrefix, mergeRoute, mergeTags, minifyContractRouter, oc, populateContractRouterPaths, prefixRoute, type, unshiftTagRoute };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ClientContext } from '@orpc/client';
|
|
2
|
+
import { StandardLinkPlugin, StandardLinkOptions } from '@orpc/client/standard';
|
|
3
|
+
import { A as AnyContractRouter } from '../shared/contract.TuRtB1Ca.mjs';
|
|
4
|
+
import '@orpc/shared';
|
|
5
|
+
import '@standard-schema/spec';
|
|
6
|
+
import 'openapi-types';
|
|
7
|
+
|
|
8
|
+
declare class RequestValidationPluginError extends Error {
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A link plugin that validates client requests against your contract schema,
|
|
12
|
+
* ensuring that data sent to your server matches the expected types defined in your contract.
|
|
13
|
+
*
|
|
14
|
+
* @throws {ORPCError} with code `BAD_REQUEST` (same as server side) if input doesn't match the expected schema
|
|
15
|
+
* @see {@link https://orpc.dev/docs/plugins/request-validation Request Validation Plugin Docs}
|
|
16
|
+
*/
|
|
17
|
+
declare class RequestValidationPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
18
|
+
private readonly contract;
|
|
19
|
+
constructor(contract: AnyContractRouter);
|
|
20
|
+
init(options: StandardLinkOptions<T>): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A link plugin that validates server responses against your contract schema,
|
|
25
|
+
* ensuring that data returned from your server matches the expected types defined in your contract.
|
|
26
|
+
*
|
|
27
|
+
* - Throws `ValidationError` if output doesn't match the expected schema
|
|
28
|
+
* - Converts mismatched defined errors to normal `ORPCError` instances
|
|
29
|
+
*
|
|
30
|
+
* @see {@link https://orpc.dev/docs/plugins/response-validation Response Validation Plugin Docs}
|
|
31
|
+
*/
|
|
32
|
+
declare class ResponseValidationPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
33
|
+
private readonly contract;
|
|
34
|
+
constructor(contract: AnyContractRouter);
|
|
35
|
+
/**
|
|
36
|
+
* run before (validate after) retry plugin, because validation failed can't be retried
|
|
37
|
+
* run before (validate after) durable iterator plugin, because we expect durable iterator to validation (if user use it)
|
|
38
|
+
*/
|
|
39
|
+
order: number;
|
|
40
|
+
init(options: StandardLinkOptions<T>): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { RequestValidationPlugin, RequestValidationPluginError, ResponseValidationPlugin };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ClientContext } from '@orpc/client';
|
|
2
|
+
import { StandardLinkPlugin, StandardLinkOptions } from '@orpc/client/standard';
|
|
3
|
+
import { A as AnyContractRouter } from '../shared/contract.TuRtB1Ca.js';
|
|
4
|
+
import '@orpc/shared';
|
|
5
|
+
import '@standard-schema/spec';
|
|
6
|
+
import 'openapi-types';
|
|
7
|
+
|
|
8
|
+
declare class RequestValidationPluginError extends Error {
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A link plugin that validates client requests against your contract schema,
|
|
12
|
+
* ensuring that data sent to your server matches the expected types defined in your contract.
|
|
13
|
+
*
|
|
14
|
+
* @throws {ORPCError} with code `BAD_REQUEST` (same as server side) if input doesn't match the expected schema
|
|
15
|
+
* @see {@link https://orpc.dev/docs/plugins/request-validation Request Validation Plugin Docs}
|
|
16
|
+
*/
|
|
17
|
+
declare class RequestValidationPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
18
|
+
private readonly contract;
|
|
19
|
+
constructor(contract: AnyContractRouter);
|
|
20
|
+
init(options: StandardLinkOptions<T>): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A link plugin that validates server responses against your contract schema,
|
|
25
|
+
* ensuring that data returned from your server matches the expected types defined in your contract.
|
|
26
|
+
*
|
|
27
|
+
* - Throws `ValidationError` if output doesn't match the expected schema
|
|
28
|
+
* - Converts mismatched defined errors to normal `ORPCError` instances
|
|
29
|
+
*
|
|
30
|
+
* @see {@link https://orpc.dev/docs/plugins/response-validation Response Validation Plugin Docs}
|
|
31
|
+
*/
|
|
32
|
+
declare class ResponseValidationPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
33
|
+
private readonly contract;
|
|
34
|
+
constructor(contract: AnyContractRouter);
|
|
35
|
+
/**
|
|
36
|
+
* run before (validate after) retry plugin, because validation failed can't be retried
|
|
37
|
+
* run before (validate after) durable iterator plugin, because we expect durable iterator to validation (if user use it)
|
|
38
|
+
*/
|
|
39
|
+
order: number;
|
|
40
|
+
init(options: StandardLinkOptions<T>): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { RequestValidationPlugin, RequestValidationPluginError, ResponseValidationPlugin };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { ORPCError } from '@orpc/client';
|
|
2
|
+
import { get } from '@orpc/shared';
|
|
3
|
+
import { i as isContractProcedure, V as ValidationError, v as validateORPCError } from '../shared/contract.D_dZrO__.mjs';
|
|
4
|
+
|
|
5
|
+
class RequestValidationPluginError extends Error {
|
|
6
|
+
}
|
|
7
|
+
class RequestValidationPlugin {
|
|
8
|
+
constructor(contract) {
|
|
9
|
+
this.contract = contract;
|
|
10
|
+
}
|
|
11
|
+
init(options) {
|
|
12
|
+
options.interceptors ??= [];
|
|
13
|
+
options.interceptors.push(async ({ next, path, input }) => {
|
|
14
|
+
const procedure = get(this.contract, path);
|
|
15
|
+
if (!isContractProcedure(procedure)) {
|
|
16
|
+
throw new RequestValidationPluginError(`No valid procedure found at path "${path.join(".")}", this may happen when the contract router is not properly configured.`);
|
|
17
|
+
}
|
|
18
|
+
const inputSchema = procedure["~orpc"].inputSchema;
|
|
19
|
+
if (inputSchema) {
|
|
20
|
+
const result = await inputSchema["~standard"].validate(input);
|
|
21
|
+
if (result.issues) {
|
|
22
|
+
throw new ORPCError("BAD_REQUEST", {
|
|
23
|
+
message: "Input validation failed",
|
|
24
|
+
data: {
|
|
25
|
+
issues: result.issues
|
|
26
|
+
},
|
|
27
|
+
cause: new ValidationError({
|
|
28
|
+
message: "Input validation failed",
|
|
29
|
+
issues: result.issues,
|
|
30
|
+
data: input
|
|
31
|
+
})
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return await next();
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class ResponseValidationPlugin {
|
|
41
|
+
constructor(contract) {
|
|
42
|
+
this.contract = contract;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* run before (validate after) retry plugin, because validation failed can't be retried
|
|
46
|
+
* run before (validate after) durable iterator plugin, because we expect durable iterator to validation (if user use it)
|
|
47
|
+
*/
|
|
48
|
+
order = 12e5;
|
|
49
|
+
init(options) {
|
|
50
|
+
options.interceptors ??= [];
|
|
51
|
+
options.interceptors.push(async ({ next, path }) => {
|
|
52
|
+
const procedure = get(this.contract, path);
|
|
53
|
+
if (!isContractProcedure(procedure)) {
|
|
54
|
+
throw new Error(`[ResponseValidationPlugin] no valid procedure found at path "${path.join(".")}", this may happen when the contract router is not properly configured.`);
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const output = await next();
|
|
58
|
+
const outputSchema = procedure["~orpc"].outputSchema;
|
|
59
|
+
if (!outputSchema) {
|
|
60
|
+
return output;
|
|
61
|
+
}
|
|
62
|
+
const result = await outputSchema["~standard"].validate(output);
|
|
63
|
+
if (result.issues) {
|
|
64
|
+
throw new ValidationError({
|
|
65
|
+
message: "Server response output does not match expected schema",
|
|
66
|
+
issues: result.issues,
|
|
67
|
+
data: output
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return result.value;
|
|
71
|
+
} catch (e) {
|
|
72
|
+
if (e instanceof ORPCError) {
|
|
73
|
+
throw await validateORPCError(procedure["~orpc"].errorMap, e);
|
|
74
|
+
}
|
|
75
|
+
throw e;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { RequestValidationPlugin, RequestValidationPluginError, ResponseValidationPlugin };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { fallbackORPCErrorStatus, ORPCError, isORPCErrorStatus } from '@orpc/client';
|
|
2
|
+
|
|
3
|
+
class ValidationError extends Error {
|
|
4
|
+
issues;
|
|
5
|
+
data;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super(options.message, options);
|
|
8
|
+
this.issues = options.issues;
|
|
9
|
+
this.data = options.data;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function mergeErrorMap(errorMap1, errorMap2) {
|
|
13
|
+
return { ...errorMap1, ...errorMap2 };
|
|
14
|
+
}
|
|
15
|
+
async function validateORPCError(map, error) {
|
|
16
|
+
const { code, status, message, data, cause, defined } = error;
|
|
17
|
+
const config = map?.[error.code];
|
|
18
|
+
if (!config || fallbackORPCErrorStatus(error.code, config.status) !== error.status) {
|
|
19
|
+
return defined ? new ORPCError(code, { defined: false, status, message, data, cause }) : error;
|
|
20
|
+
}
|
|
21
|
+
if (!config.data) {
|
|
22
|
+
return defined ? error : new ORPCError(code, { defined: true, status, message, data, cause });
|
|
23
|
+
}
|
|
24
|
+
const validated = await config.data["~standard"].validate(error.data);
|
|
25
|
+
if (validated.issues) {
|
|
26
|
+
return defined ? new ORPCError(code, { defined: false, status, message, data, cause }) : error;
|
|
27
|
+
}
|
|
28
|
+
return new ORPCError(code, { defined: true, status, message, data: validated.value, cause });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class ContractProcedure {
|
|
32
|
+
/**
|
|
33
|
+
* This property holds the defined options for the contract procedure.
|
|
34
|
+
*/
|
|
35
|
+
"~orpc";
|
|
36
|
+
constructor(def) {
|
|
37
|
+
if (def.route?.successStatus && isORPCErrorStatus(def.route.successStatus)) {
|
|
38
|
+
throw new Error("[ContractProcedure] Invalid successStatus.");
|
|
39
|
+
}
|
|
40
|
+
if (Object.values(def.errorMap).some((val) => val && val.status && !isORPCErrorStatus(val.status))) {
|
|
41
|
+
throw new Error("[ContractProcedure] Invalid error status code.");
|
|
42
|
+
}
|
|
43
|
+
this["~orpc"] = def;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function isContractProcedure(item) {
|
|
47
|
+
if (item instanceof ContractProcedure) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return (typeof item === "object" || typeof item === "function") && item !== null && "~orpc" in item && typeof item["~orpc"] === "object" && item["~orpc"] !== null && "errorMap" in item["~orpc"] && "route" in item["~orpc"] && "meta" in item["~orpc"];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { ContractProcedure as C, ValidationError as V, isContractProcedure as i, mergeErrorMap as m, validateORPCError as v };
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { ORPCErrorCode, ORPCError, HTTPMethod, HTTPPath } from '@orpc/client';
|
|
2
|
+
import { Promisable, IsEqual, ThrowableError } from '@orpc/shared';
|
|
3
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
4
|
+
import { OpenAPIV3_1 } from 'openapi-types';
|
|
5
|
+
|
|
6
|
+
type Schema<TInput, TOutput> = StandardSchemaV1<TInput, TOutput>;
|
|
7
|
+
type AnySchema = Schema<any, any>;
|
|
8
|
+
type SchemaIssue = StandardSchemaV1.Issue;
|
|
9
|
+
type InferSchemaInput<T extends AnySchema> = T extends StandardSchemaV1<infer UInput, any> ? UInput : never;
|
|
10
|
+
type InferSchemaOutput<T extends AnySchema> = T extends StandardSchemaV1<any, infer UOutput> ? UOutput : never;
|
|
11
|
+
type TypeRest<TInput, TOutput> = [map: (input: TInput) => Promisable<TOutput>] | (IsEqual<TInput, TOutput> extends true ? [] : never);
|
|
12
|
+
/**
|
|
13
|
+
* The schema for things can be trust without validation.
|
|
14
|
+
* If the TInput and TOutput are different, you need pass a map function.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link https://orpc.dev/docs/procedure#type-utility Type Utility Docs}
|
|
17
|
+
*/
|
|
18
|
+
declare function type<TInput, TOutput = TInput>(...[map]: TypeRest<TInput, TOutput>): Schema<TInput, TOutput>;
|
|
19
|
+
|
|
20
|
+
interface ValidationErrorOptions extends ErrorOptions {
|
|
21
|
+
message: string;
|
|
22
|
+
issues: readonly SchemaIssue[];
|
|
23
|
+
/**
|
|
24
|
+
* @todo require this field in v2
|
|
25
|
+
*/
|
|
26
|
+
data?: unknown;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* This errors usually used for ORPCError.cause when the error is a validation error.
|
|
30
|
+
*
|
|
31
|
+
* @see {@link https://orpc.dev/docs/advanced/validation-errors Validation Errors Docs}
|
|
32
|
+
*/
|
|
33
|
+
declare class ValidationError extends Error {
|
|
34
|
+
readonly issues: readonly SchemaIssue[];
|
|
35
|
+
readonly data: unknown;
|
|
36
|
+
constructor(options: ValidationErrorOptions);
|
|
37
|
+
}
|
|
38
|
+
interface ErrorMapItem<TDataSchema extends AnySchema> {
|
|
39
|
+
status?: number;
|
|
40
|
+
message?: string;
|
|
41
|
+
data?: TDataSchema;
|
|
42
|
+
}
|
|
43
|
+
type ErrorMap = {
|
|
44
|
+
[key in ORPCErrorCode]?: ErrorMapItem<AnySchema>;
|
|
45
|
+
};
|
|
46
|
+
type MergedErrorMap<T1 extends ErrorMap, T2 extends ErrorMap> = Omit<T1, keyof T2> & T2;
|
|
47
|
+
declare function mergeErrorMap<T1 extends ErrorMap, T2 extends ErrorMap>(errorMap1: T1, errorMap2: T2): MergedErrorMap<T1, T2>;
|
|
48
|
+
type ORPCErrorFromErrorMap<TErrorMap extends ErrorMap> = {
|
|
49
|
+
[K in keyof TErrorMap]: K extends string ? TErrorMap[K] extends ErrorMapItem<infer TDataSchema extends Schema<unknown, unknown>> ? ORPCError<K, InferSchemaOutput<TDataSchema>> : never : never;
|
|
50
|
+
}[keyof TErrorMap];
|
|
51
|
+
type ErrorFromErrorMap<TErrorMap extends ErrorMap> = ORPCErrorFromErrorMap<TErrorMap> | ThrowableError;
|
|
52
|
+
declare function validateORPCError(map: ErrorMap, error: ORPCError<any, any>): Promise<ORPCError<string, unknown>>;
|
|
53
|
+
|
|
54
|
+
type Meta = Record<string, any>;
|
|
55
|
+
declare function mergeMeta<T extends Meta>(meta1: T, meta2: T): T;
|
|
56
|
+
|
|
57
|
+
type InputStructure = 'compact' | 'detailed';
|
|
58
|
+
type OutputStructure = 'compact' | 'detailed';
|
|
59
|
+
interface Route {
|
|
60
|
+
/**
|
|
61
|
+
* The HTTP method of the procedure.
|
|
62
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
63
|
+
*
|
|
64
|
+
* @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
|
|
65
|
+
*/
|
|
66
|
+
method?: HTTPMethod;
|
|
67
|
+
/**
|
|
68
|
+
* The HTTP path of the procedure.
|
|
69
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
70
|
+
*
|
|
71
|
+
* @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
|
|
72
|
+
*/
|
|
73
|
+
path?: HTTPPath;
|
|
74
|
+
/**
|
|
75
|
+
* The operation ID of the endpoint.
|
|
76
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
77
|
+
*
|
|
78
|
+
* @default Concatenation of router segments
|
|
79
|
+
*/
|
|
80
|
+
operationId?: string;
|
|
81
|
+
/**
|
|
82
|
+
* The summary of the procedure.
|
|
83
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
84
|
+
*
|
|
85
|
+
* @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata OpenAPI Operation Metadata Docs}
|
|
86
|
+
*/
|
|
87
|
+
summary?: string;
|
|
88
|
+
/**
|
|
89
|
+
* The description of the procedure.
|
|
90
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
91
|
+
*
|
|
92
|
+
* @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata OpenAPI Operation Metadata Docs}
|
|
93
|
+
*/
|
|
94
|
+
description?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Marks the procedure as deprecated.
|
|
97
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
98
|
+
*
|
|
99
|
+
* @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata OpenAPI Operation Metadata Docs}
|
|
100
|
+
*/
|
|
101
|
+
deprecated?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* The tags of the procedure.
|
|
104
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
105
|
+
*
|
|
106
|
+
* @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata OpenAPI Operation Metadata Docs}
|
|
107
|
+
*/
|
|
108
|
+
tags?: readonly string[];
|
|
109
|
+
/**
|
|
110
|
+
* The status code of the response when the procedure is successful.
|
|
111
|
+
* The status code must be in the 200-399 range.
|
|
112
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
113
|
+
*
|
|
114
|
+
* @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
|
|
115
|
+
* @default 200
|
|
116
|
+
*/
|
|
117
|
+
successStatus?: number;
|
|
118
|
+
/**
|
|
119
|
+
* The description of the response when the procedure is successful.
|
|
120
|
+
* This option is typically relevant when integrating with OpenAPI.
|
|
121
|
+
*
|
|
122
|
+
* @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata OpenAPI Operation Metadata Docs}
|
|
123
|
+
* @default 'OK'
|
|
124
|
+
*/
|
|
125
|
+
successDescription?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Determines how the input should be structured based on `params`, `query`, `headers`, and `body`.
|
|
128
|
+
*
|
|
129
|
+
* @option 'compact'
|
|
130
|
+
* Combines `params` and either `query` or `body` (depending on the HTTP method) into a single object.
|
|
131
|
+
*
|
|
132
|
+
* @option 'detailed'
|
|
133
|
+
* Keeps each part of the request (`params`, `query`, `headers`, and `body`) as separate fields in the input object.
|
|
134
|
+
*
|
|
135
|
+
* Example:
|
|
136
|
+
* ```ts
|
|
137
|
+
* const input = {
|
|
138
|
+
* params: { id: 1 },
|
|
139
|
+
* query: { search: 'hello' },
|
|
140
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
141
|
+
* body: { name: 'John' },
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
|
|
146
|
+
* @default 'compact'
|
|
147
|
+
*/
|
|
148
|
+
inputStructure?: InputStructure;
|
|
149
|
+
/**
|
|
150
|
+
* Determines how the response should be structured based on the output.
|
|
151
|
+
*
|
|
152
|
+
* @option 'compact'
|
|
153
|
+
* The output data is directly returned as the response body.
|
|
154
|
+
*
|
|
155
|
+
* @option 'detailed'
|
|
156
|
+
* Return an object with optional properties:
|
|
157
|
+
* - `status`: The response status (must be in 200-399 range) if not set fallback to `successStatus`.
|
|
158
|
+
* - `headers`: Custom headers to merge with the response headers (`Record<string, string | string[] | undefined>`)
|
|
159
|
+
* - `body`: The response body.
|
|
160
|
+
*
|
|
161
|
+
* Example:
|
|
162
|
+
* ```ts
|
|
163
|
+
* const output = {
|
|
164
|
+
* status: 201,
|
|
165
|
+
* headers: { 'x-custom-header': 'value' },
|
|
166
|
+
* body: { message: 'Hello, world!' },
|
|
167
|
+
* };
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
|
|
171
|
+
* @default 'compact'
|
|
172
|
+
*/
|
|
173
|
+
outputStructure?: OutputStructure;
|
|
174
|
+
/**
|
|
175
|
+
* Override entire auto-generated OpenAPI Operation Object Specification.
|
|
176
|
+
*
|
|
177
|
+
* @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata Operation Metadata Docs}
|
|
178
|
+
*/
|
|
179
|
+
spec?: OpenAPIV3_1.OperationObject | ((current: OpenAPIV3_1.OperationObject) => OpenAPIV3_1.OperationObject);
|
|
180
|
+
}
|
|
181
|
+
declare function mergeRoute(a: Route, b: Route): Route;
|
|
182
|
+
declare function prefixRoute(route: Route, prefix: HTTPPath): Route;
|
|
183
|
+
declare function unshiftTagRoute(route: Route, tags: readonly string[]): Route;
|
|
184
|
+
declare function mergePrefix(a: HTTPPath | undefined, b: HTTPPath): HTTPPath;
|
|
185
|
+
declare function mergeTags(a: readonly string[] | undefined, b: readonly string[]): readonly string[];
|
|
186
|
+
interface EnhanceRouteOptions {
|
|
187
|
+
prefix?: HTTPPath;
|
|
188
|
+
tags?: readonly string[];
|
|
189
|
+
}
|
|
190
|
+
declare function enhanceRoute(route: Route, options: EnhanceRouteOptions): Route;
|
|
191
|
+
|
|
192
|
+
interface ContractProcedureDef<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, TMeta extends Meta> {
|
|
193
|
+
meta: TMeta;
|
|
194
|
+
route: Route;
|
|
195
|
+
inputSchema?: TInputSchema;
|
|
196
|
+
outputSchema?: TOutputSchema;
|
|
197
|
+
errorMap: TErrorMap;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* This class represents a contract procedure.
|
|
201
|
+
*
|
|
202
|
+
* @see {@link https://orpc.dev/docs/contract-first/define-contract#procedure-contract Contract Procedure Docs}
|
|
203
|
+
*/
|
|
204
|
+
declare class ContractProcedure<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, TMeta extends Meta> {
|
|
205
|
+
/**
|
|
206
|
+
* This property holds the defined options for the contract procedure.
|
|
207
|
+
*/
|
|
208
|
+
'~orpc': ContractProcedureDef<TInputSchema, TOutputSchema, TErrorMap, TMeta>;
|
|
209
|
+
constructor(def: ContractProcedureDef<TInputSchema, TOutputSchema, TErrorMap, TMeta>);
|
|
210
|
+
}
|
|
211
|
+
type AnyContractProcedure = ContractProcedure<any, any, any, any>;
|
|
212
|
+
declare function isContractProcedure(item: unknown): item is AnyContractProcedure;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Represents a contract router, which defines a hierarchical structure of contract procedures.
|
|
216
|
+
*
|
|
217
|
+
* @info A contract procedure is a contract router too.
|
|
218
|
+
* @see {@link https://orpc.dev/docs/contract-first/define-contract#contract-router Contract Router Docs}
|
|
219
|
+
*/
|
|
220
|
+
type ContractRouter<TMeta extends Meta> = ContractProcedure<any, any, any, TMeta> | {
|
|
221
|
+
[k: string]: ContractRouter<TMeta>;
|
|
222
|
+
};
|
|
223
|
+
type AnyContractRouter = ContractRouter<any>;
|
|
224
|
+
/**
|
|
225
|
+
* Infer all inputs of the contract router.
|
|
226
|
+
*
|
|
227
|
+
* @info A contract procedure is a contract router too.
|
|
228
|
+
* @see {@link https://orpc.dev/docs/contract-first/define-contract#utilities Contract Utilities Docs}
|
|
229
|
+
*/
|
|
230
|
+
type InferContractRouterInputs<T extends AnyContractRouter> = T extends ContractProcedure<infer UInputSchema, any, any, any> ? InferSchemaInput<UInputSchema> : {
|
|
231
|
+
[K in keyof T]: T[K] extends AnyContractRouter ? InferContractRouterInputs<T[K]> : never;
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Infer all outputs of the contract router.
|
|
235
|
+
*
|
|
236
|
+
* @info A contract procedure is a contract router too.
|
|
237
|
+
* @see {@link https://orpc.dev/docs/contract-first/define-contract#utilities Contract Utilities Docs}
|
|
238
|
+
*/
|
|
239
|
+
type InferContractRouterOutputs<T extends AnyContractRouter> = T extends ContractProcedure<any, infer UOutputSchema, any, any> ? InferSchemaOutput<UOutputSchema> : {
|
|
240
|
+
[K in keyof T]: T[K] extends AnyContractRouter ? InferContractRouterOutputs<T[K]> : never;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Infer all errors of the contract router.
|
|
244
|
+
*
|
|
245
|
+
* @info A contract procedure is a contract router too.
|
|
246
|
+
* @see {@link https://orpc.dev/docs/contract-first/define-contract#utilities Contract Utilities Docs}
|
|
247
|
+
*/
|
|
248
|
+
type InferContractRouterErrorMap<T extends AnyContractRouter> = T extends ContractProcedure<any, any, infer UErrorMap, any> ? UErrorMap : {
|
|
249
|
+
[K in keyof T]: T[K] extends AnyContractRouter ? InferContractRouterErrorMap<T[K]> : never;
|
|
250
|
+
}[keyof T];
|
|
251
|
+
type InferContractRouterMeta<T extends AnyContractRouter> = T extends ContractRouter<infer UMeta> ? UMeta : never;
|
|
252
|
+
|
|
253
|
+
export { ContractProcedure as C, type as D, ValidationError as j, mergeErrorMap as m, mergeMeta as n, isContractProcedure as p, mergeRoute as q, prefixRoute as r, mergePrefix as s, mergeTags as t, unshiftTagRoute as u, validateORPCError as v, enhanceRoute as w };
|
|
254
|
+
export type { AnyContractRouter as A, InferContractRouterMeta as B, ErrorMap as E, InputStructure as I, MergedErrorMap as M, OutputStructure as O, Route as R, Schema as S, TypeRest as T, ValidationErrorOptions as V, EnhanceRouteOptions as a, AnySchema as b, Meta as c, ContractRouter as d, ContractProcedureDef as e, InferSchemaInput as f, InferSchemaOutput as g, ErrorFromErrorMap as h, SchemaIssue as i, ErrorMapItem as k, ORPCErrorFromErrorMap as l, AnyContractProcedure as o, InferContractRouterInputs as x, InferContractRouterOutputs as y, InferContractRouterErrorMap as z };
|