@orpc/contract 2.0.0-beta.3 → 2.0.0-beta.30
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 +71 -101
- package/dist/index.d.mts +270 -19
- package/dist/index.d.ts +270 -19
- package/dist/index.mjs +188 -56
- package/dist/plugins/index.d.mts +11 -2
- package/dist/plugins/index.d.ts +11 -2
- package/dist/plugins/index.mjs +21 -20
- package/dist/shared/{contract.Do92aRJ4.d.mts → contract.DUiXUlmP.d.mts} +84 -7
- package/dist/shared/{contract.Do92aRJ4.d.ts → contract.DUiXUlmP.d.ts} +84 -7
- package/dist/shared/{contract.CW-2wl1i.mjs → contract.DjQcyGZi.mjs} +3 -2
- package/package.json +19 -6
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isTypescriptObject, toArray, set,
|
|
2
|
-
import { P as ProcedureContract, r as resolveMetaPlugins, m as mergeErrorMap, a as augmentContractRouter, V as ValidationError } from './shared/contract.
|
|
3
|
-
export { d as defineMeta, g as
|
|
4
|
-
import { createORPCClient,
|
|
1
|
+
import { isTypescriptObject, toArray, get, set, isPropertyKey, ORPC_NAME, resolveMaybeOptionalOptions, isAsyncIteratorObject } from '@orpc/shared';
|
|
2
|
+
import { P as ProcedureContract, r as resolveMetaPlugins, m as mergeErrorMap, a as augmentContractRouter, V as ValidationError } from './shared/contract.DjQcyGZi.mjs';
|
|
3
|
+
export { d as defineMeta, g as getContractRouter, b as getProcedureContractOrThrow, g as getRouterContract, c as minifyContractRouter, c as minifyRouterContract, e as reconcileORPCError } from './shared/contract.DjQcyGZi.mjs';
|
|
4
|
+
import { createORPCClient, ORPCError, wrapAsyncIteratorPreservingEventMeta } from '@orpc/client';
|
|
5
5
|
|
|
6
6
|
const HIDDEN_META_PLUGINS_SYMBOL = Symbol.for("ORPC_HIDDEN_META_PLUGINS");
|
|
7
7
|
function getHiddenMetaPlugins(container) {
|
|
@@ -22,12 +22,23 @@ class ContractBuilder extends ProcedureContract {
|
|
|
22
22
|
constructor(definition) {
|
|
23
23
|
super(definition);
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates a fresh contract builder with an empty definition.
|
|
27
|
+
* Prefer the exported `oc` instance over calling this directly.
|
|
28
|
+
*
|
|
29
|
+
* @see {@link https://orpc.dev/docs/contract/procedure | Procedure Contract}
|
|
30
|
+
*/
|
|
25
31
|
static create() {
|
|
26
32
|
return new ContractBuilder({
|
|
27
33
|
errorMap: {},
|
|
28
34
|
meta: {}
|
|
29
35
|
});
|
|
30
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Applies metadata plugins to contracts built from this builder.
|
|
39
|
+
*
|
|
40
|
+
* @see {@link https://orpc.dev/docs/contract/procedure#metadata | Procedure Contract - Metadata}
|
|
41
|
+
*/
|
|
31
42
|
meta(...plugins) {
|
|
32
43
|
const [meta, metaPlugins] = resolveMetaPlugins(
|
|
33
44
|
this["~orpc"].meta,
|
|
@@ -40,6 +51,11 @@ class ContractBuilder extends ProcedureContract {
|
|
|
40
51
|
metaPlugins
|
|
41
52
|
});
|
|
42
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Defines typesafe errors that implementations of this contract can throw.
|
|
56
|
+
*
|
|
57
|
+
* @see {@link https://orpc.dev/docs/contract/procedure#typesafe-errors | Procedure Contract - Typesafe Errors}
|
|
58
|
+
*/
|
|
43
59
|
errors(errors) {
|
|
44
60
|
let result = new ContractBuilder({
|
|
45
61
|
...this["~orpc"],
|
|
@@ -51,6 +67,11 @@ class ContractBuilder extends ProcedureContract {
|
|
|
51
67
|
}
|
|
52
68
|
return result;
|
|
53
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Defines the input schema used to validate and type the procedure input.
|
|
72
|
+
*
|
|
73
|
+
* @see {@link https://orpc.dev/docs/contract/procedure#inputoutput-validation | Procedure Contract - Input/Output Validation}
|
|
74
|
+
*/
|
|
54
75
|
input(schema) {
|
|
55
76
|
let result = new ContractBuilder({
|
|
56
77
|
...this["~orpc"],
|
|
@@ -62,6 +83,11 @@ class ContractBuilder extends ProcedureContract {
|
|
|
62
83
|
}
|
|
63
84
|
return result;
|
|
64
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Defines the output schema used to validate and type the procedure output.
|
|
88
|
+
*
|
|
89
|
+
* @see {@link https://orpc.dev/docs/contract/procedure#inputoutput-validation | Procedure Contract - Input/Output Validation}
|
|
90
|
+
*/
|
|
65
91
|
output(schema) {
|
|
66
92
|
let result = new ContractBuilder({
|
|
67
93
|
...this["~orpc"],
|
|
@@ -73,6 +99,12 @@ class ContractBuilder extends ProcedureContract {
|
|
|
73
99
|
}
|
|
74
100
|
return result;
|
|
75
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Applies the builder's errors and metadata to every procedure contract in
|
|
104
|
+
* the given router contract.
|
|
105
|
+
*
|
|
106
|
+
* @see {@link https://orpc.dev/docs/contract/router#extending-router | Router Contract - Extending Router}
|
|
107
|
+
*/
|
|
76
108
|
router(router) {
|
|
77
109
|
return augmentContractRouter(router, this["~orpc"]);
|
|
78
110
|
}
|
|
@@ -95,41 +127,170 @@ const meta = {
|
|
|
95
127
|
function getPathMeta(procedureOrLazy) {
|
|
96
128
|
return procedureOrLazy["~orpc"].meta["~path"];
|
|
97
129
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const path = getPathMeta(procedure);
|
|
130
|
+
function resolveBasePathMeta(contract, currentPath = []) {
|
|
131
|
+
if (contract instanceof ProcedureContract) {
|
|
132
|
+
const path = getPathMeta(contract);
|
|
102
133
|
if (!path) {
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
const base = path.slice(0, Math.max(0, path.length - currentPath.length));
|
|
137
|
+
if (currentPath.some((key, i) => path[base.length + i] !== key)) {
|
|
103
138
|
throw new TypeError(
|
|
104
|
-
|
|
139
|
+
`Procedure contract at "${currentPath.join(".")}" defines meta.path "${path.join(".")}" that does not match its path inside the given router contract.`
|
|
105
140
|
);
|
|
106
141
|
}
|
|
107
|
-
|
|
108
|
-
|
|
142
|
+
return base;
|
|
143
|
+
}
|
|
144
|
+
if (isTypescriptObject(contract)) {
|
|
145
|
+
for (const key in contract) {
|
|
146
|
+
const base = resolveBasePathMeta(contract[key], [...currentPath, key]);
|
|
147
|
+
if (base !== void 0) {
|
|
148
|
+
return base;
|
|
149
|
+
}
|
|
109
150
|
}
|
|
110
|
-
|
|
111
|
-
|
|
151
|
+
}
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function createContractClientFactory(link, options = {}) {
|
|
156
|
+
const factory = (contract) => {
|
|
157
|
+
const path = resolveBasePathMeta(contract);
|
|
158
|
+
if (path === void 0) {
|
|
112
159
|
throw new TypeError(
|
|
113
|
-
|
|
160
|
+
"ContractClientFactory: procedure contract must define `meta.path` that matches its path in the root router contract."
|
|
114
161
|
);
|
|
115
162
|
}
|
|
116
|
-
const
|
|
117
|
-
|
|
163
|
+
const contractRef = options.contractRef;
|
|
164
|
+
if (contractRef) {
|
|
165
|
+
const register = (contract2, path2) => {
|
|
166
|
+
if (contract2 instanceof ProcedureContract) {
|
|
167
|
+
set(contractRef, [...path2, "~orpc"], contract2["~orpc"]);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (isTypescriptObject(contract2)) {
|
|
171
|
+
for (const [key, value] of Object.entries(contract2)) {
|
|
172
|
+
register(value, [...path2, key]);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
register(contract, path);
|
|
177
|
+
}
|
|
178
|
+
return createORPCClient(link, { ...options, scoped: get(options.scoped, path), path });
|
|
118
179
|
};
|
|
180
|
+
return factory;
|
|
119
181
|
}
|
|
120
182
|
|
|
121
|
-
|
|
122
|
-
function eventIterator(yieldSchema, returnSchema) {
|
|
183
|
+
function type(...[map]) {
|
|
123
184
|
return {
|
|
124
185
|
"~standard": {
|
|
125
|
-
|
|
186
|
+
vendor: ORPC_NAME,
|
|
187
|
+
version: 1,
|
|
188
|
+
async validate(value) {
|
|
189
|
+
if (map) {
|
|
190
|
+
return { value: await map(value) };
|
|
191
|
+
}
|
|
192
|
+
return { value };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function isSchemaIssue(issue) {
|
|
198
|
+
if (!isTypescriptObject(issue) || typeof issue.message !== "string") {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
if (issue.path !== void 0) {
|
|
202
|
+
if (!Array.isArray(issue.path)) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
if (!issue.path.every((segment) => isPropertyKey(segment) || isTypescriptObject(segment) && isPropertyKey(segment.key))) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function error(code, { data: dataSchema, message } = {}) {
|
|
213
|
+
const validateData = (schema, value) => {
|
|
214
|
+
const result = schema["~standard"].validate(value);
|
|
215
|
+
if (result instanceof Promise) {
|
|
216
|
+
throw new TypeError(
|
|
217
|
+
`Error factory "${code}" does not support async data schemas.`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return result;
|
|
221
|
+
};
|
|
222
|
+
return class extends ORPCError {
|
|
223
|
+
static code = code;
|
|
224
|
+
static data = dataSchema ?? type();
|
|
225
|
+
static message = message;
|
|
226
|
+
constructor(...rest) {
|
|
227
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
228
|
+
let data = options.data;
|
|
229
|
+
if (dataSchema) {
|
|
230
|
+
const result = validateData(dataSchema, options.data);
|
|
231
|
+
if (result.issues) {
|
|
232
|
+
throw new ValidationError({
|
|
233
|
+
message: `Error factory "${code}" data validation failed`,
|
|
234
|
+
issues: result.issues,
|
|
235
|
+
invalidData: options.data
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
data = result.value;
|
|
239
|
+
}
|
|
240
|
+
super(code, { message, ...options, data });
|
|
241
|
+
}
|
|
242
|
+
static [Symbol.hasInstance](instance) {
|
|
243
|
+
if (!(instance instanceof ORPCError)) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
if (instance.code !== code) {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
if (dataSchema && validateData(dataSchema, instance.data).issues) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function createORPCErrorConstructorMap(errorMap) {
|
|
257
|
+
const proxy = new Proxy(errorMap, {
|
|
258
|
+
get(target, code) {
|
|
259
|
+
if (typeof code !== "string") {
|
|
260
|
+
return Reflect.get(target, code);
|
|
261
|
+
}
|
|
262
|
+
const item = (...rest) => {
|
|
263
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
264
|
+
const config = errorMap[code];
|
|
265
|
+
const error2 = new ORPCError(code, {
|
|
266
|
+
message: options.message ?? config?.message,
|
|
267
|
+
data: options.data,
|
|
268
|
+
cause: options.cause
|
|
269
|
+
});
|
|
270
|
+
if (config) {
|
|
271
|
+
error2.defined = true;
|
|
272
|
+
error2.inferable = true;
|
|
273
|
+
}
|
|
274
|
+
return error2;
|
|
275
|
+
};
|
|
276
|
+
return item;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
return proxy;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const ASYNC_ITERATOR_OBJECT_SCHEMA_DETAILS_SYMBOL = Symbol.for("ORPC_ASYNC_ITERATOR_OBJECT_SCHEMA_DETAILS");
|
|
283
|
+
function asyncIteratorObject(yieldSchema, returnSchema) {
|
|
284
|
+
return {
|
|
285
|
+
"~standard": {
|
|
286
|
+
[ASYNC_ITERATOR_OBJECT_SCHEMA_DETAILS_SYMBOL]: { yieldSchema, returnSchema },
|
|
126
287
|
vendor: ORPC_NAME,
|
|
127
288
|
version: 1,
|
|
128
289
|
validate(iterator) {
|
|
129
290
|
if (!isAsyncIteratorObject(iterator)) {
|
|
130
|
-
return { issues: [{ message: "Expect
|
|
291
|
+
return { issues: [{ message: "Expect AsyncIteratorObject", path: [] }] };
|
|
131
292
|
}
|
|
132
|
-
const mapped =
|
|
293
|
+
const mapped = wrapAsyncIteratorPreservingEventMeta(iterator, {
|
|
133
294
|
async mapResult(result) {
|
|
134
295
|
const schema = result.done ? returnSchema : yieldSchema;
|
|
135
296
|
if (!schema) {
|
|
@@ -137,11 +298,11 @@ function eventIterator(yieldSchema, returnSchema) {
|
|
|
137
298
|
}
|
|
138
299
|
const validated = await schema["~standard"].validate(result.value);
|
|
139
300
|
if (validated.issues) {
|
|
140
|
-
throw new ORPCError("
|
|
141
|
-
message: "
|
|
301
|
+
throw new ORPCError("ASYNC_ITERATOR_OBJECT_VALIDATION_FAILED", {
|
|
302
|
+
message: "AsyncIteratorObject validation failed",
|
|
142
303
|
cause: new ValidationError({
|
|
143
304
|
issues: validated.issues,
|
|
144
|
-
message: "
|
|
305
|
+
message: "AsyncIteratorObject validation failed",
|
|
145
306
|
invalidData: result.value
|
|
146
307
|
})
|
|
147
308
|
});
|
|
@@ -154,40 +315,11 @@ function eventIterator(yieldSchema, returnSchema) {
|
|
|
154
315
|
}
|
|
155
316
|
};
|
|
156
317
|
}
|
|
157
|
-
function
|
|
318
|
+
function getAsyncIteratorObjectSchemaDetails(schema) {
|
|
158
319
|
if (schema === void 0) {
|
|
159
320
|
return void 0;
|
|
160
321
|
}
|
|
161
|
-
return schema["~standard"][
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function type(...[map]) {
|
|
165
|
-
return {
|
|
166
|
-
"~standard": {
|
|
167
|
-
vendor: ORPC_NAME,
|
|
168
|
-
version: 1,
|
|
169
|
-
async validate(value) {
|
|
170
|
-
if (map) {
|
|
171
|
-
return { value: await map(value) };
|
|
172
|
-
}
|
|
173
|
-
return { value };
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
function isSchemaIssue(issue) {
|
|
179
|
-
if (!isTypescriptObject(issue) || typeof issue.message !== "string") {
|
|
180
|
-
return false;
|
|
181
|
-
}
|
|
182
|
-
if (issue.path !== void 0) {
|
|
183
|
-
if (!Array.isArray(issue.path)) {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
if (!issue.path.every((segment) => isPropertyKey(segment) || isTypescriptObject(segment) && isPropertyKey(segment.key))) {
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return true;
|
|
322
|
+
return schema["~standard"][ASYNC_ITERATOR_OBJECT_SCHEMA_DETAILS_SYMBOL];
|
|
191
323
|
}
|
|
192
324
|
|
|
193
|
-
export { ContractBuilder, HIDDEN_META_PLUGINS_SYMBOL, ProcedureContract, ValidationError, augmentContractRouter,
|
|
325
|
+
export { ContractBuilder, HIDDEN_META_PLUGINS_SYMBOL, ProcedureContract, ValidationError, asyncIteratorObject, augmentContractRouter, createContractClientFactory, createORPCErrorConstructorMap, error, asyncIteratorObject as eventIterator, getAsyncIteratorObjectSchemaDetails, getHiddenMetaPlugins, getPathMeta, isSchemaIssue, mergeErrorMap, meta, oc, resolveBasePathMeta, resolveMetaPlugins, setHiddenMetaPlugins, type };
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClientContext } from '@orpc/client';
|
|
2
2
|
import { StandardLinkPlugin, StandardLinkOptions } from '@orpc/client/standard';
|
|
3
|
-
import {
|
|
3
|
+
import { RouterContract } from '../index.mjs';
|
|
4
4
|
import '@orpc/shared';
|
|
5
5
|
import '@standard-schema/spec';
|
|
6
6
|
|
|
@@ -18,6 +18,9 @@ interface RequestValidationLinkPluginOptions<_T extends ClientContext> {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Validates client request input against contract schemas before the request is encoded.
|
|
21
|
+
* This is useful when your application relies on server-side validation.
|
|
22
|
+
*
|
|
23
|
+
* @see {@link https://orpc.dev/docs/plugins/request-validation | Request Validation Plugin}
|
|
21
24
|
*/
|
|
22
25
|
declare class RequestValidationLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
23
26
|
private readonly contract;
|
|
@@ -27,6 +30,12 @@ declare class RequestValidationLinkPlugin<T extends ClientContext> implements St
|
|
|
27
30
|
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Validates server responses against contract schemas before your application uses them.
|
|
35
|
+
* This helps ensure the data returned by the server matches the types defined in your contract.
|
|
36
|
+
*
|
|
37
|
+
* @see {@link https://orpc.dev/docs/plugins/response-validation | Response Validation Plugin}
|
|
38
|
+
*/
|
|
30
39
|
declare class ResponseValidationLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
31
40
|
private readonly contract;
|
|
32
41
|
name: string;
|
|
@@ -34,5 +43,5 @@ declare class ResponseValidationLinkPlugin<T extends ClientContext> implements S
|
|
|
34
43
|
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
35
44
|
}
|
|
36
45
|
|
|
37
|
-
export { RequestValidationLinkPlugin, ResponseValidationLinkPlugin };
|
|
46
|
+
export { RequestValidationLinkPlugin, RequestValidationLinkPlugin as RequestValidationPlugin, ResponseValidationLinkPlugin, ResponseValidationLinkPlugin as ResponseValidationPlugin };
|
|
38
47
|
export type { RequestValidationLinkPluginOptions };
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ClientContext } from '@orpc/client';
|
|
2
2
|
import { StandardLinkPlugin, StandardLinkOptions } from '@orpc/client/standard';
|
|
3
|
-
import {
|
|
3
|
+
import { RouterContract } from '../index.js';
|
|
4
4
|
import '@orpc/shared';
|
|
5
5
|
import '@standard-schema/spec';
|
|
6
6
|
|
|
@@ -18,6 +18,9 @@ interface RequestValidationLinkPluginOptions<_T extends ClientContext> {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Validates client request input against contract schemas before the request is encoded.
|
|
21
|
+
* This is useful when your application relies on server-side validation.
|
|
22
|
+
*
|
|
23
|
+
* @see {@link https://orpc.dev/docs/plugins/request-validation | Request Validation Plugin}
|
|
21
24
|
*/
|
|
22
25
|
declare class RequestValidationLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
23
26
|
private readonly contract;
|
|
@@ -27,6 +30,12 @@ declare class RequestValidationLinkPlugin<T extends ClientContext> implements St
|
|
|
27
30
|
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Validates server responses against contract schemas before your application uses them.
|
|
35
|
+
* This helps ensure the data returned by the server matches the types defined in your contract.
|
|
36
|
+
*
|
|
37
|
+
* @see {@link https://orpc.dev/docs/plugins/response-validation | Response Validation Plugin}
|
|
38
|
+
*/
|
|
30
39
|
declare class ResponseValidationLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
31
40
|
private readonly contract;
|
|
32
41
|
name: string;
|
|
@@ -34,5 +43,5 @@ declare class ResponseValidationLinkPlugin<T extends ClientContext> implements S
|
|
|
34
43
|
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
35
44
|
}
|
|
36
45
|
|
|
37
|
-
export { RequestValidationLinkPlugin, ResponseValidationLinkPlugin };
|
|
46
|
+
export { RequestValidationLinkPlugin, RequestValidationLinkPlugin as RequestValidationPlugin, ResponseValidationLinkPlugin, ResponseValidationLinkPlugin as ResponseValidationPlugin };
|
|
38
47
|
export type { RequestValidationLinkPluginOptions };
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ORPCError } from '@orpc/client';
|
|
2
|
-
import { toArray } from '@orpc/shared';
|
|
3
|
-
import {
|
|
2
|
+
import { toArray, isPlainObject, mergeTwoLevels } from '@orpc/shared';
|
|
3
|
+
import { b as getProcedureContractOrThrow, V as ValidationError, e as reconcileORPCError } from '../shared/contract.DjQcyGZi.mjs';
|
|
4
4
|
|
|
5
5
|
class RequestValidationLinkPlugin {
|
|
6
6
|
constructor(contract, options = {}) {
|
|
@@ -14,25 +14,26 @@ class RequestValidationLinkPlugin {
|
|
|
14
14
|
...options,
|
|
15
15
|
interceptors: [...toArray(options.interceptors), async ({ next, ...interceptorOptions }) => {
|
|
16
16
|
const procedure = getProcedureContractOrThrow(this.contract, interceptorOptions.path);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
const inputSchemas = toArray(procedure["~orpc"].inputSchemas);
|
|
18
|
+
const originalInput = interceptorOptions.input;
|
|
19
|
+
let currentInput = originalInput;
|
|
20
|
+
for (const [index, schema] of inputSchemas.entries()) {
|
|
21
|
+
const validating = inputSchemas.length > 1 && isPlainObject(currentInput) ? originalInput : currentInput;
|
|
22
|
+
const result = await schema["~standard"].validate(validating);
|
|
23
|
+
if (result.issues) {
|
|
24
|
+
throw new ORPCError("BAD_REQUEST", {
|
|
25
|
+
message: "Input validation failed",
|
|
26
|
+
data: {
|
|
27
|
+
issues: result.issues
|
|
28
|
+
},
|
|
29
|
+
cause: new ValidationError({
|
|
23
30
|
message: "Input validation failed",
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
message: "Input validation failed",
|
|
29
|
-
issues: result.issues,
|
|
30
|
-
invalidData: currentInput
|
|
31
|
-
})
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
currentInput = result.value;
|
|
31
|
+
issues: result.issues,
|
|
32
|
+
invalidData: validating
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
35
|
}
|
|
36
|
+
currentInput = index !== 0 ? mergeTwoLevels(currentInput, result.value) : result.value;
|
|
36
37
|
}
|
|
37
38
|
return this.forwardValidatedInput ? next({ ...interceptorOptions, input: currentInput }) : next();
|
|
38
39
|
}]
|
|
@@ -87,4 +88,4 @@ class ResponseValidationLinkPlugin {
|
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
export { RequestValidationLinkPlugin, ResponseValidationLinkPlugin };
|
|
91
|
+
export { RequestValidationLinkPlugin, RequestValidationLinkPlugin as RequestValidationPlugin, ResponseValidationLinkPlugin, ResponseValidationLinkPlugin as ResponseValidationPlugin };
|
|
@@ -6,28 +6,63 @@ import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
|
6
6
|
* TOutput default = TInput for better readability (shorter) in-case both TInput, TOutput is equal
|
|
7
7
|
*/
|
|
8
8
|
type Schema<TInput, TOutput = TInput> = StandardSchemaV1<TInput, TOutput>;
|
|
9
|
+
/**
|
|
10
|
+
* Any Standard Schema compatible schema, regardless of its input and output types.
|
|
11
|
+
*
|
|
12
|
+
* @see {@link https://orpc.dev/docs/integrations/standard-schema | Standard Schema Integration}
|
|
13
|
+
*/
|
|
9
14
|
type AnySchema = Schema<any>;
|
|
10
15
|
type SchemaIssue = StandardSchemaV1.Issue;
|
|
16
|
+
/**
|
|
17
|
+
* Infers the input type of a schema.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://orpc.dev/docs/metadata | Metadata}
|
|
20
|
+
*/
|
|
11
21
|
type InferSchemaInput<T extends AnySchema> = T extends StandardSchemaV1<infer UInput, any> ? UInput : never;
|
|
22
|
+
/**
|
|
23
|
+
* Infers the output type of a schema.
|
|
24
|
+
*
|
|
25
|
+
* @see {@link https://orpc.dev/docs/metadata | Metadata}
|
|
26
|
+
*/
|
|
12
27
|
type InferSchemaOutput<T extends AnySchema> = T extends StandardSchemaV1<any, infer UOutput> ? UOutput : never;
|
|
13
28
|
type MergedSchema<T extends AnySchema, U extends AnySchema> = T extends Schema<infer TInput, infer TOutput> ? U extends Schema<infer UInput, infer UOutput> ? Schema<TInput & UInput, TOutput & UOutput> : never : never;
|
|
14
29
|
|
|
15
|
-
interface ErrorMapItem
|
|
16
|
-
|
|
17
|
-
|
|
30
|
+
interface ErrorMapItem {
|
|
31
|
+
/**
|
|
32
|
+
* Default message, can be overridden when constructing an error.
|
|
33
|
+
*/
|
|
34
|
+
message?: undefined | string;
|
|
35
|
+
/**
|
|
36
|
+
* Schema used to type and validate the error data.
|
|
37
|
+
*/
|
|
38
|
+
data?: undefined | AnySchema;
|
|
18
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Map of error codes to their definitions, as passed to `.errors(...)`.
|
|
42
|
+
* Errors defined here remain properly typed on the client.
|
|
43
|
+
*
|
|
44
|
+
* @see {@link https://orpc.dev/docs/metadata | Metadata}
|
|
45
|
+
*/
|
|
19
46
|
type ErrorMap = {
|
|
20
|
-
[key in ORPCErrorCode]?: ErrorMapItem
|
|
47
|
+
[key in ORPCErrorCode]?: ErrorMapItem;
|
|
21
48
|
};
|
|
22
49
|
type ORPCErrorFromErrorMap<TErrorMap extends ErrorMap> = {
|
|
23
|
-
[K in keyof TErrorMap]: K extends
|
|
50
|
+
[K in keyof TErrorMap]: TErrorMap[K] extends ErrorMapItem ? ORPCError<K & ORPCErrorCode, TErrorMap[K]['data'] extends AnySchema ? InferSchemaOutput<TErrorMap[K]['data']> : unknown> : never;
|
|
24
51
|
}[keyof TErrorMap];
|
|
25
52
|
interface ValidationErrorOptions extends ErrorOptions {
|
|
26
53
|
message: string;
|
|
27
54
|
issues: readonly SchemaIssue[];
|
|
28
55
|
invalidData: unknown;
|
|
29
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Error thrown when input, output, or error data fails schema validation,
|
|
59
|
+
* carrying the standard-schema `issues` and the invalid data.
|
|
60
|
+
* Usually found as the `cause` of an `ORPCError`.
|
|
61
|
+
*
|
|
62
|
+
* @see {@link https://orpc.dev/docs/advanced/validation-customization | Validation Customization}
|
|
63
|
+
*/
|
|
30
64
|
declare class ValidationError extends Error {
|
|
65
|
+
name: string;
|
|
31
66
|
/**
|
|
32
67
|
* This array is readonly because the upstream Standard Schema returns readonly issues.
|
|
33
68
|
*/
|
|
@@ -36,6 +71,12 @@ declare class ValidationError extends Error {
|
|
|
36
71
|
constructor(options: ValidationErrorOptions);
|
|
37
72
|
}
|
|
38
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Arbitrary metadata attached to a procedure.
|
|
76
|
+
* Middleware, plugins, and tooling can read it later to control behavior.
|
|
77
|
+
*
|
|
78
|
+
* @see {@link https://orpc.dev/docs/metadata | Metadata}
|
|
79
|
+
*/
|
|
39
80
|
interface Meta {
|
|
40
81
|
[key: PropertyKey]: unknown;
|
|
41
82
|
}
|
|
@@ -50,6 +91,12 @@ interface MetaPluginDefinition<TInputSchema extends AnySchema, TOutputSchema ext
|
|
|
50
91
|
type: TErrorMap;
|
|
51
92
|
};
|
|
52
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* A metadata plugin passed to `.meta(...)`.
|
|
96
|
+
* Defines how metadata is initialized and merged, and can infer or restrict procedure types.
|
|
97
|
+
*
|
|
98
|
+
* @see {@link https://orpc.dev/docs/metadata | Metadata}
|
|
99
|
+
*/
|
|
53
100
|
interface MetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> {
|
|
54
101
|
/** This only for types, so it should be optional */
|
|
55
102
|
'~orpc'?: MetaPluginDefinition<TInputSchema, TOutputSchema, TErrorMap> | undefined;
|
|
@@ -66,6 +113,12 @@ interface MetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySc
|
|
|
66
113
|
*/
|
|
67
114
|
'apply'?: (meta: Meta) => Meta;
|
|
68
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* A `MetaPlugin` with all type parameters relaxed to `any`.
|
|
118
|
+
*
|
|
119
|
+
* @see {@link https://orpc.dev/docs/contract/procedure | Procedure Contract}
|
|
120
|
+
* @see {@link https://orpc.dev/docs/procedure | Procedure}
|
|
121
|
+
*/
|
|
69
122
|
type AnyMetaPlugin = MetaPlugin<any, any, any>;
|
|
70
123
|
declare const HIDDEN_META_PLUGINS_SYMBOL: unique symbol;
|
|
71
124
|
declare function getHiddenMetaPlugins(container: unknown): AnyMetaPlugin[] | undefined;
|
|
@@ -91,36 +144,60 @@ declare class ProcedureContract<TInputSchema extends AnySchema, TOutputSchema ex
|
|
|
91
144
|
'~orpc': ProcedureContractDefinition<TInputSchema, TOutputSchema, TErrorMap>;
|
|
92
145
|
constructor(def: ProcedureContractDefinition<TInputSchema, TOutputSchema, TErrorMap>);
|
|
93
146
|
/**
|
|
94
|
-
* Checks if the given instance satisfies the {@
|
|
147
|
+
* Checks if the given instance satisfies the {@link ProcedureContract} class/interface.
|
|
95
148
|
*/
|
|
96
149
|
static [Symbol.hasInstance](instance: unknown): boolean;
|
|
97
150
|
}
|
|
98
151
|
type AnyProcedureContract = ProcedureContract<any, any, any>;
|
|
99
152
|
|
|
153
|
+
/**
|
|
154
|
+
* A router contract: a single procedure contract or a nested record of them.
|
|
155
|
+
*
|
|
156
|
+
* @see {@link https://orpc.dev/docs/advanced/scaling-large-projects | Scaling Large Projects}
|
|
157
|
+
*/
|
|
100
158
|
type RouterContract = AnyProcedureContract | {
|
|
101
159
|
[k: string]: RouterContract;
|
|
102
160
|
};
|
|
161
|
+
/**
|
|
162
|
+
* Infer the input types for each procedure-contract, preserving the router-contract shape.
|
|
163
|
+
*
|
|
164
|
+
* @see {@link https://orpc.dev/docs/contract/router#infer-router-contract-inputs | Router Contract - Infer Router Contract Inputs}
|
|
165
|
+
*/
|
|
103
166
|
type InferRouterContractInputs<T extends RouterContract> = T extends ProcedureContract<infer UInputSchema, any, any> ? InferSchemaInput<UInputSchema> : {
|
|
104
167
|
[K in keyof T]: T[K] extends RouterContract ? InferRouterContractInputs<T[K]> : never;
|
|
105
168
|
};
|
|
169
|
+
/**
|
|
170
|
+
* Infer the output types for each procedure-contract, preserving the router-contract shape.
|
|
171
|
+
*
|
|
172
|
+
* @see {@link https://orpc.dev/docs/contract/router#infer-router-contract-outputs | Router Contract - Infer Router Contract Outputs}
|
|
173
|
+
*/
|
|
106
174
|
type InferRouterContractOutputs<T extends RouterContract> = T extends ProcedureContract<any, infer UOutputSchema, any> ? InferSchemaOutput<UOutputSchema> : {
|
|
107
175
|
[K in keyof T]: T[K] extends RouterContract ? InferRouterContractOutputs<T[K]> : never;
|
|
108
176
|
};
|
|
177
|
+
/**
|
|
178
|
+
* Infer the union of error maps defined across the entire router-contract.
|
|
179
|
+
*
|
|
180
|
+
* @see {@link https://orpc.dev/docs/contract/router#infer-router-contract-error-map | Router Contract - Infer Router Contract Error Map}
|
|
181
|
+
*/
|
|
109
182
|
type InferRouterContractErrorMap<T extends RouterContract> = T extends ProcedureContract<any, any, infer UErrorMap> ? UErrorMap : {
|
|
110
183
|
[K in keyof T]: T[K] extends RouterContract ? InferRouterContractErrorMap<T[K]> : never;
|
|
111
184
|
}[keyof T];
|
|
112
185
|
/**
|
|
113
186
|
* Infer the union of throwable errors for entire router-contract.
|
|
187
|
+
*
|
|
188
|
+
* @see {@link https://orpc.dev/docs/contract/router#infer-router-contract-error | Router Contract - Infer Router Contract Error}
|
|
114
189
|
*/
|
|
115
190
|
type InferRouterContractError<T extends RouterContract> = T extends ProcedureContract<any, any, infer UErrorMap> ? ORPCErrorFromErrorMap<UErrorMap> | ThrowableError : {
|
|
116
191
|
[K in keyof T]: T[K] extends RouterContract ? InferRouterContractError<T[K]> : never;
|
|
117
192
|
}[keyof T];
|
|
118
193
|
/**
|
|
119
194
|
* Infer throwable errors for each procedure-contract, preserving the router-contract shape.
|
|
195
|
+
*
|
|
196
|
+
* @see {@link https://orpc.dev/docs/contract/router#infer-router-contract-errors | Router Contract - Infer Router Contract Errors}
|
|
120
197
|
*/
|
|
121
198
|
type InferRouterContractErrors<T extends RouterContract> = T extends ProcedureContract<any, any, infer UErrorMap> ? ORPCErrorFromErrorMap<UErrorMap> | ThrowableError : {
|
|
122
199
|
[K in keyof T]: T[K] extends RouterContract ? InferRouterContractErrors<T[K]> : never;
|
|
123
200
|
};
|
|
124
201
|
|
|
125
202
|
export { HIDDEN_META_PLUGINS_SYMBOL as H, ProcedureContract as P, ValidationError as V, getHiddenMetaPlugins as p, setHiddenMetaPlugins as s };
|
|
126
|
-
export type { AnySchema as A, ErrorMap as E, InferSchemaInput as I, MetaPlugin as M, ORPCErrorFromErrorMap as O, RouterContract as R, Schema as S, MergedSchema as a, Meta as b, AnyMetaPlugin as c, AnyProcedureContract as d, InferSchemaOutput as e,
|
|
203
|
+
export type { AnySchema as A, ErrorMap as E, InferSchemaInput as I, MetaPlugin as M, ORPCErrorFromErrorMap as O, RouterContract as R, Schema as S, MergedSchema as a, Meta as b, AnyMetaPlugin as c, AnyProcedureContract as d, InferSchemaOutput as e, ErrorMapItem as f, SchemaIssue as g, InferRouterContractErrorMap as h, InferRouterContractInputs as i, InferRouterContractOutputs as j, InferRouterContractError as k, InferRouterContractErrors as l, MetaPluginDefinition as m, ProcedureContractDefinition as n, ValidationErrorOptions as o };
|