@orpc/json-schema 2.0.0-beta.42 → 2.0.0-beta.44
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 +2 -10
- package/dist/index.d.mts +27 -3
- package/dist/index.d.ts +27 -3
- package/dist/index.mjs +113 -26
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
|
|
18
18
|
</a>
|
|
19
19
|
<a href="https://deepwiki.com/middleapi/orpc">
|
|
20
|
-
<img src="https://
|
|
20
|
+
<img alt="Ask DeepWiki" src="https://img.shields.io/badge/Ask-DeepWiki-blue" />
|
|
21
21
|
</a>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -95,14 +95,6 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
95
95
|
</tr>
|
|
96
96
|
</table>
|
|
97
97
|
|
|
98
|
-
### Special Sponsors
|
|
99
|
-
|
|
100
|
-
<table>
|
|
101
|
-
<tr>
|
|
102
|
-
<td align="center"><a href="http://twitter.com/rauchg?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guillermo Rauch"><img src="https://avatars.githubusercontent.com/u/13041?u=1ee8d111657cdd02ff6d253df00978d17ee6d722&v=4" width="279" alt="Guillermo Rauch"/><br />Guillermo Rauch</a></td>
|
|
103
|
-
</tr>
|
|
104
|
-
</table>
|
|
105
|
-
|
|
106
98
|
### Premium Sponsors
|
|
107
99
|
|
|
108
100
|
<table>
|
|
@@ -178,7 +170,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
178
170
|
</tr>
|
|
179
171
|
</table>
|
|
180
172
|
|
|
181
|
-
With thanks to [
|
|
173
|
+
With thanks to [39 past sponsors](https://orpc.dev/sponsors#past-sponsors) who helped get oRPC here.
|
|
182
174
|
|
|
183
175
|
## References
|
|
184
176
|
|
package/dist/index.d.mts
CHANGED
|
@@ -60,9 +60,33 @@ declare enum JsonSchemaXNativeType {
|
|
|
60
60
|
Map = "map"
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
interface JsonSchemaCoercerOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Maximum digits, excluding a leading `-`, of a string coerced to `bigint`. Longer strings are left unchanged.
|
|
66
|
+
* `Number.POSITIVE_INFINITY` disables it.
|
|
67
|
+
*
|
|
68
|
+
* @default 4300
|
|
69
|
+
*/
|
|
70
|
+
maxBigIntDigits?: number | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Maximum coercion steps per input value, where a step applies one schema to one value.
|
|
73
|
+
* Inputs with fewer than 100 values are budgeted as 100. Past the budget the whole input is left uncoerced,
|
|
74
|
+
* so validation still runs and reports any mismatch.
|
|
75
|
+
*
|
|
76
|
+
* @default 1000
|
|
77
|
+
*/
|
|
78
|
+
maxStepsPerValue?: number | undefined;
|
|
79
|
+
}
|
|
63
80
|
declare class JsonSchemaCoercer {
|
|
81
|
+
private readonly nativeCoerceOptions;
|
|
82
|
+
private readonly maxStepsPerValue;
|
|
83
|
+
/** Reused between calls, since building a context is slow until V8 warms up. */
|
|
84
|
+
private idleContext;
|
|
85
|
+
constructor(options?: JsonSchemaCoercerOptions);
|
|
64
86
|
coerce([schema, optional]: [schema: JsonSchema, optional: boolean], value: unknown): unknown;
|
|
65
87
|
private coerceInternal;
|
|
88
|
+
private coerceRef;
|
|
89
|
+
private extendBudget;
|
|
66
90
|
}
|
|
67
91
|
|
|
68
92
|
/**
|
|
@@ -203,7 +227,7 @@ declare function hoistRecursiveRefToDef(schema: JsonSchema): JsonSchema;
|
|
|
203
227
|
*/
|
|
204
228
|
declare function resolveJsonSchemaRootLocalRef(schema: JsonSchema, $defs?: Exclude<JsonSchema, boolean>['$defs']): JsonSchema;
|
|
205
229
|
|
|
206
|
-
interface SmartCoercionHandlerPluginOptions {
|
|
230
|
+
interface SmartCoercionHandlerPluginOptions extends JsonSchemaCoercerOptions {
|
|
207
231
|
converters?: undefined | JsonSchemaConverter[];
|
|
208
232
|
}
|
|
209
233
|
/**
|
|
@@ -222,7 +246,7 @@ declare class SmartCoercionHandlerPlugin<T extends Context> implements StandardH
|
|
|
222
246
|
private coerceValue;
|
|
223
247
|
}
|
|
224
248
|
|
|
225
|
-
interface SmartCoercionLinkPluginOptions {
|
|
249
|
+
interface SmartCoercionLinkPluginOptions extends JsonSchemaCoercerOptions {
|
|
226
250
|
converters?: undefined | JsonSchemaConverter[];
|
|
227
251
|
}
|
|
228
252
|
/**
|
|
@@ -260,4 +284,4 @@ declare class StandardJsonSchemaConverter implements JsonSchemaConverter {
|
|
|
260
284
|
}
|
|
261
285
|
|
|
262
286
|
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
|
263
|
-
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
|
287
|
+
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaCoercerOptions, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -60,9 +60,33 @@ declare enum JsonSchemaXNativeType {
|
|
|
60
60
|
Map = "map"
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
interface JsonSchemaCoercerOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Maximum digits, excluding a leading `-`, of a string coerced to `bigint`. Longer strings are left unchanged.
|
|
66
|
+
* `Number.POSITIVE_INFINITY` disables it.
|
|
67
|
+
*
|
|
68
|
+
* @default 4300
|
|
69
|
+
*/
|
|
70
|
+
maxBigIntDigits?: number | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Maximum coercion steps per input value, where a step applies one schema to one value.
|
|
73
|
+
* Inputs with fewer than 100 values are budgeted as 100. Past the budget the whole input is left uncoerced,
|
|
74
|
+
* so validation still runs and reports any mismatch.
|
|
75
|
+
*
|
|
76
|
+
* @default 1000
|
|
77
|
+
*/
|
|
78
|
+
maxStepsPerValue?: number | undefined;
|
|
79
|
+
}
|
|
63
80
|
declare class JsonSchemaCoercer {
|
|
81
|
+
private readonly nativeCoerceOptions;
|
|
82
|
+
private readonly maxStepsPerValue;
|
|
83
|
+
/** Reused between calls, since building a context is slow until V8 warms up. */
|
|
84
|
+
private idleContext;
|
|
85
|
+
constructor(options?: JsonSchemaCoercerOptions);
|
|
64
86
|
coerce([schema, optional]: [schema: JsonSchema, optional: boolean], value: unknown): unknown;
|
|
65
87
|
private coerceInternal;
|
|
88
|
+
private coerceRef;
|
|
89
|
+
private extendBudget;
|
|
66
90
|
}
|
|
67
91
|
|
|
68
92
|
/**
|
|
@@ -203,7 +227,7 @@ declare function hoistRecursiveRefToDef(schema: JsonSchema): JsonSchema;
|
|
|
203
227
|
*/
|
|
204
228
|
declare function resolveJsonSchemaRootLocalRef(schema: JsonSchema, $defs?: Exclude<JsonSchema, boolean>['$defs']): JsonSchema;
|
|
205
229
|
|
|
206
|
-
interface SmartCoercionHandlerPluginOptions {
|
|
230
|
+
interface SmartCoercionHandlerPluginOptions extends JsonSchemaCoercerOptions {
|
|
207
231
|
converters?: undefined | JsonSchemaConverter[];
|
|
208
232
|
}
|
|
209
233
|
/**
|
|
@@ -222,7 +246,7 @@ declare class SmartCoercionHandlerPlugin<T extends Context> implements StandardH
|
|
|
222
246
|
private coerceValue;
|
|
223
247
|
}
|
|
224
248
|
|
|
225
|
-
interface SmartCoercionLinkPluginOptions {
|
|
249
|
+
interface SmartCoercionLinkPluginOptions extends JsonSchemaCoercerOptions {
|
|
226
250
|
converters?: undefined | JsonSchemaConverter[];
|
|
227
251
|
}
|
|
228
252
|
/**
|
|
@@ -260,4 +284,4 @@ declare class StandardJsonSchemaConverter implements JsonSchemaConverter {
|
|
|
260
284
|
}
|
|
261
285
|
|
|
262
286
|
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
|
263
|
-
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
|
287
|
+
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaCoercerOptions, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setOwn, get, isPlainObject, tryOrUndefined, getOwn, toArray, isDeepEqual, omit
|
|
1
|
+
import { setOwn, get, DEFAULT_MAX_BIGINT_DIGITS, isPlainObject, tryOrUndefined, getOwn, toArray, isTypescriptObject, parseBigIntString, isDeepEqual, omit } from '@orpc/shared';
|
|
2
2
|
import { ORPCError, cloneORPCError } from '@orpc/client';
|
|
3
3
|
import { getProcedureContractOrThrow } from '@orpc/contract';
|
|
4
4
|
|
|
@@ -215,7 +215,7 @@ const NATIVE_TYPES = /* @__PURE__ */ new Map([
|
|
|
215
215
|
[JsonSchemaXNativeType.BigInt, {
|
|
216
216
|
types: ["string", "integer", "number"],
|
|
217
217
|
is: (value) => typeof value === "bigint",
|
|
218
|
-
coerce: (value) => typeof value === "string" ? stringToBigInt(value) : typeof value === "number" ? numberToBigInt(value) : value
|
|
218
|
+
coerce: (value, { maxBigIntDigits }) => typeof value === "string" ? stringToBigInt(value, maxBigIntDigits) : typeof value === "number" ? numberToBigInt(value) : value
|
|
219
219
|
}],
|
|
220
220
|
[JsonSchemaXNativeType.Url, {
|
|
221
221
|
types: ["string"],
|
|
@@ -238,21 +238,58 @@ const NATIVE_TYPES = /* @__PURE__ */ new Map([
|
|
|
238
238
|
function minSatisfaction(a, b) {
|
|
239
239
|
return a < b ? a : b;
|
|
240
240
|
}
|
|
241
|
+
const MIN_BUDGETED_VALUES = 100;
|
|
242
|
+
function createContext() {
|
|
243
|
+
return { rootSchema: true, memo: void 0, memoize: false, steps: 0, maxSteps: 0, input: void 0 };
|
|
244
|
+
}
|
|
245
|
+
class CoercionBudgetExceededError extends Error {
|
|
246
|
+
}
|
|
241
247
|
class JsonSchemaCoercer {
|
|
248
|
+
nativeCoerceOptions;
|
|
249
|
+
maxStepsPerValue;
|
|
250
|
+
/** Reused between calls, since building a context is slow until V8 warms up. */
|
|
251
|
+
idleContext = createContext();
|
|
252
|
+
constructor(options = {}) {
|
|
253
|
+
this.nativeCoerceOptions = {
|
|
254
|
+
maxBigIntDigits: options.maxBigIntDigits ?? DEFAULT_MAX_BIGINT_DIGITS
|
|
255
|
+
};
|
|
256
|
+
this.maxStepsPerValue = options.maxStepsPerValue ?? 1e3;
|
|
257
|
+
}
|
|
242
258
|
coerce([schema, optional], value) {
|
|
243
259
|
if (optional && value === void 0) {
|
|
244
260
|
return value;
|
|
245
261
|
}
|
|
246
|
-
const
|
|
247
|
-
|
|
262
|
+
const context = this.idleContext ?? createContext();
|
|
263
|
+
this.idleContext = void 0;
|
|
264
|
+
context.rootSchema = schema;
|
|
265
|
+
context.memoize = false;
|
|
266
|
+
context.steps = 0;
|
|
267
|
+
context.maxSteps = this.maxStepsPerValue * MIN_BUDGETED_VALUES;
|
|
268
|
+
context.input = value;
|
|
269
|
+
try {
|
|
270
|
+
const [, coerced] = this.coerceInternal(context, schema, value);
|
|
271
|
+
return coerced;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
if (error instanceof CoercionBudgetExceededError) {
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
276
|
+
throw error;
|
|
277
|
+
} finally {
|
|
278
|
+
context.memo = void 0;
|
|
279
|
+
context.input = void 0;
|
|
280
|
+
this.idleContext = context;
|
|
281
|
+
}
|
|
248
282
|
}
|
|
249
|
-
coerceInternal(
|
|
283
|
+
coerceInternal(context, schema, value, appliedRefs) {
|
|
284
|
+
if (++context.steps > context.maxSteps) {
|
|
285
|
+
this.extendBudget(context);
|
|
286
|
+
}
|
|
250
287
|
if (typeof schema === "boolean") {
|
|
251
288
|
return [schema ? SATISFIED : UNSATISFIED, value];
|
|
252
289
|
}
|
|
253
290
|
if (Array.isArray(schema.type)) {
|
|
254
291
|
return this.coerceInternal(
|
|
255
|
-
|
|
292
|
+
context,
|
|
256
293
|
{ anyOf: schema.type.map((type) => ({ ...schema, type })) },
|
|
257
294
|
value,
|
|
258
295
|
appliedRefs
|
|
@@ -261,12 +298,12 @@ class JsonSchemaCoercer {
|
|
|
261
298
|
let coerced = value;
|
|
262
299
|
let satisfied = SATISFIED;
|
|
263
300
|
if (typeof schema.$ref === "string") {
|
|
264
|
-
const resolved = schema.$ref.startsWith("#/") ? get(rootSchema, schema.$ref.slice("#/".length).split("/").map(decodeJsonPointerSegment)) : schema.$ref === "#" ? rootSchema : void 0;
|
|
301
|
+
const resolved = schema.$ref.startsWith("#/") ? get(context.rootSchema, schema.$ref.slice("#/".length).split("/").map(decodeJsonPointerSegment)) : schema.$ref === "#" ? context.rootSchema : void 0;
|
|
265
302
|
if (resolved !== void 0 && !appliedRefs?.has(resolved)) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
303
|
+
if (schema.type === "object" || schema.type === "array") {
|
|
304
|
+
context.memoize = true;
|
|
305
|
+
}
|
|
306
|
+
const [subSatisfied, subCoerced] = this.coerceRef(context, resolved, coerced, appliedRefs);
|
|
270
307
|
coerced = subCoerced;
|
|
271
308
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
272
309
|
}
|
|
@@ -292,7 +329,7 @@ class JsonSchemaCoercer {
|
|
|
292
329
|
const declaredNativeType = NATIVE_TYPES.get(schema["x-native-type"]);
|
|
293
330
|
const nativeType = schema.type === void 0 || declaredNativeType?.types.includes(schema.type) ? declaredNativeType : void 0;
|
|
294
331
|
if (nativeType && !nativeType.afterTypeCheck) {
|
|
295
|
-
coerced = nativeType.coerce(coerced);
|
|
332
|
+
coerced = nativeType.coerce(coerced, this.nativeCoerceOptions);
|
|
296
333
|
}
|
|
297
334
|
if (schema.type && !nativeType?.is(coerced)) {
|
|
298
335
|
switch (schema.type) {
|
|
@@ -346,7 +383,7 @@ class JsonSchemaCoercer {
|
|
|
346
383
|
satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
|
|
347
384
|
return item;
|
|
348
385
|
}
|
|
349
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
386
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, item);
|
|
350
387
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
351
388
|
if (subCoerced !== item) {
|
|
352
389
|
shouldUseCoercedItems = true;
|
|
@@ -383,7 +420,7 @@ class JsonSchemaCoercer {
|
|
|
383
420
|
if (subSchema === void 0) {
|
|
384
421
|
satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
|
|
385
422
|
} else {
|
|
386
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
423
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, value2);
|
|
387
424
|
coercedItems[key] = subCoerced;
|
|
388
425
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
389
426
|
if (subCoerced !== value2) {
|
|
@@ -407,24 +444,26 @@ class JsonSchemaCoercer {
|
|
|
407
444
|
}
|
|
408
445
|
if (nativeType) {
|
|
409
446
|
if (nativeType.afterTypeCheck) {
|
|
410
|
-
coerced = nativeType.coerce(coerced);
|
|
447
|
+
coerced = nativeType.coerce(coerced, this.nativeCoerceOptions);
|
|
411
448
|
}
|
|
412
449
|
if (!nativeType.is(coerced)) {
|
|
413
450
|
satisfied = UNSATISFIED;
|
|
414
451
|
}
|
|
415
452
|
}
|
|
416
453
|
if (schema.allOf) {
|
|
454
|
+
context.memoize = true;
|
|
417
455
|
for (const subSchema of schema.allOf) {
|
|
418
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
456
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, coerced, appliedRefs);
|
|
419
457
|
coerced = subCoerced;
|
|
420
458
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
421
459
|
}
|
|
422
460
|
}
|
|
423
461
|
for (const key of ["anyOf", "oneOf"]) {
|
|
424
462
|
if (schema[key]) {
|
|
463
|
+
context.memoize = true;
|
|
425
464
|
let best;
|
|
426
465
|
for (const subSchema of schema[key]) {
|
|
427
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
466
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, coerced, appliedRefs);
|
|
428
467
|
if (subSatisfied === UNSATISFIED) {
|
|
429
468
|
continue;
|
|
430
469
|
}
|
|
@@ -445,13 +484,64 @@ class JsonSchemaCoercer {
|
|
|
445
484
|
}
|
|
446
485
|
}
|
|
447
486
|
if (typeof schema.not !== "undefined") {
|
|
448
|
-
|
|
487
|
+
context.memoize = true;
|
|
488
|
+
const [notSatisfied] = this.coerceInternal(context, schema.not, coerced, appliedRefs);
|
|
449
489
|
if (notSatisfied !== UNSATISFIED) {
|
|
450
490
|
satisfied = UNSATISFIED;
|
|
451
491
|
}
|
|
452
492
|
}
|
|
453
493
|
return [satisfied, coerced];
|
|
454
494
|
}
|
|
495
|
+
coerceRef(context, resolved, value, appliedRefs) {
|
|
496
|
+
let memo;
|
|
497
|
+
if (context.memoize && !appliedRefs?.size && isTypescriptObject(value)) {
|
|
498
|
+
context.memo ??= /* @__PURE__ */ new Map();
|
|
499
|
+
memo = context.memo.get(resolved);
|
|
500
|
+
if (!memo) {
|
|
501
|
+
memo = /* @__PURE__ */ new Map();
|
|
502
|
+
context.memo.set(resolved, memo);
|
|
503
|
+
}
|
|
504
|
+
const cached = memo.get(value);
|
|
505
|
+
if (cached) {
|
|
506
|
+
return cached;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
appliedRefs ??= /* @__PURE__ */ new Set();
|
|
510
|
+
appliedRefs.add(resolved);
|
|
511
|
+
const result = this.coerceInternal(context, resolved, value, appliedRefs);
|
|
512
|
+
appliedRefs.delete(resolved);
|
|
513
|
+
memo?.set(value, result);
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
extendBudget(context) {
|
|
517
|
+
const limit = 2 * context.steps / this.maxStepsPerValue;
|
|
518
|
+
context.maxSteps = this.maxStepsPerValue * Math.max(countValues(context.input, limit), MIN_BUDGETED_VALUES);
|
|
519
|
+
if (context.steps > context.maxSteps) {
|
|
520
|
+
throw new CoercionBudgetExceededError();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function countValues(input, limit) {
|
|
525
|
+
const walked = /* @__PURE__ */ new Set();
|
|
526
|
+
const stack = [input];
|
|
527
|
+
let count = 1;
|
|
528
|
+
while (stack.length) {
|
|
529
|
+
const value = stack.pop();
|
|
530
|
+
if ((Array.isArray(value) || isPlainObject(value)) && !walked.has(value)) {
|
|
531
|
+
walked.add(value);
|
|
532
|
+
const items = Array.isArray(value) ? value : Object.values(value);
|
|
533
|
+
for (let i = 0; i < items.length; i++) {
|
|
534
|
+
if (++count >= limit) {
|
|
535
|
+
return count;
|
|
536
|
+
}
|
|
537
|
+
const item = items[i];
|
|
538
|
+
if (isTypescriptObject(item)) {
|
|
539
|
+
stack.push(item);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return count;
|
|
455
545
|
}
|
|
456
546
|
const NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
457
547
|
function stringToNumber(value) {
|
|
@@ -475,11 +565,8 @@ function stringToInteger(value) {
|
|
|
475
565
|
}
|
|
476
566
|
return num;
|
|
477
567
|
}
|
|
478
|
-
function stringToBigInt(value) {
|
|
479
|
-
|
|
480
|
-
return value;
|
|
481
|
-
}
|
|
482
|
-
return BigInt(value);
|
|
568
|
+
function stringToBigInt(value, maxDigits) {
|
|
569
|
+
return parseBigIntString(value, maxDigits) ?? value;
|
|
483
570
|
}
|
|
484
571
|
function numberToBigInt(value) {
|
|
485
572
|
if (!Number.isInteger(value)) {
|
|
@@ -497,7 +584,7 @@ function stringToBoolean(value) {
|
|
|
497
584
|
}
|
|
498
585
|
return value;
|
|
499
586
|
}
|
|
500
|
-
const DATE_TIME_PATTERN = /^(?!-0{6})(?:[+-]\d{2})?\d{4}-\d{2}-\d{2}(?:[T ]
|
|
587
|
+
const DATE_TIME_PATTERN = /^(?!-0{6})(?:[+-]\d{2})?\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
501
588
|
const DAYS_IN_MONTH = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
502
589
|
function stringToDate(value) {
|
|
503
590
|
if (!DATE_TIME_PATTERN.test(value)) {
|
|
@@ -902,7 +989,7 @@ class SmartCoercionHandlerPlugin {
|
|
|
902
989
|
...toArray(options.converters),
|
|
903
990
|
new StandardJsonSchemaConverter()
|
|
904
991
|
]);
|
|
905
|
-
this.coercer = new JsonSchemaCoercer();
|
|
992
|
+
this.coercer = new JsonSchemaCoercer(options);
|
|
906
993
|
}
|
|
907
994
|
init(options) {
|
|
908
995
|
return {
|
|
@@ -940,7 +1027,7 @@ class SmartCoercionLinkPlugin {
|
|
|
940
1027
|
...toArray(options.converters),
|
|
941
1028
|
new StandardJsonSchemaConverter()
|
|
942
1029
|
]);
|
|
943
|
-
this.coercer = new JsonSchemaCoercer();
|
|
1030
|
+
this.coercer = new JsonSchemaCoercer(options);
|
|
944
1031
|
}
|
|
945
1032
|
name = "~smart-coercion";
|
|
946
1033
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/json-schema",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.44",
|
|
5
5
|
"description": "JSON Schema conversion and smart request coercion for oRPC and OpenAPI",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": [
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@openapi-spec/types": "~0.3.0",
|
|
39
|
-
"@orpc/client": "2.0.0-beta.
|
|
40
|
-
"@orpc/contract": "2.0.0-beta.
|
|
41
|
-
"@orpc/server": "2.0.0-beta.
|
|
42
|
-
"@orpc/shared": "2.0.0-beta.
|
|
39
|
+
"@orpc/client": "2.0.0-beta.44",
|
|
40
|
+
"@orpc/contract": "2.0.0-beta.44",
|
|
41
|
+
"@orpc/server": "2.0.0-beta.44",
|
|
42
|
+
"@orpc/shared": "2.0.0-beta.44",
|
|
43
43
|
"@standard-schema/spec": "^1.1.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"zod": "^4.5
|
|
46
|
+
"zod": "^4.6.5"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"type:check": "tsc -b"
|