@orpc/json-schema 2.0.0-beta.4 → 2.0.0-beta.40

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/dist/index.mjs CHANGED
@@ -1,5 +1,4 @@
1
- import { get, isPlainObject, toArray, tryOrUndefined, isDeepEqual, omit, isTypescriptObject } from '@orpc/shared';
2
- export { Format as JsonSchemaFormat, TypeName as JsonSchemaType } from 'json-schema-typed/draft-2020-12';
1
+ import { get, isPlainObject, tryOrUndefined, getOwn, toArray, isDeepEqual, omit, isTypescriptObject } from '@orpc/shared';
3
2
  import { ORPCError, cloneORPCError } from '@orpc/client';
4
3
  import { getProcedureContractOrThrow } from '@orpc/contract';
5
4
 
@@ -59,6 +58,28 @@ function encodeJsonPointerSegment(segment) {
59
58
  function decodeJsonPointerSegment(segment) {
60
59
  return segment.replaceAll("~1", "/").replaceAll("~0", "~");
61
60
  }
61
+ function visitJsonSchemaRefs(value, visit, schemaLevel = true, seen = /* @__PURE__ */ new Set()) {
62
+ if (!value || typeof value !== "object" || seen.has(value)) {
63
+ return;
64
+ }
65
+ seen.add(value);
66
+ if (Array.isArray(value)) {
67
+ for (const item of value) {
68
+ visitJsonSchemaRefs(item, visit, schemaLevel, seen);
69
+ }
70
+ return;
71
+ }
72
+ for (const key of Object.keys(value)) {
73
+ const val = value[key];
74
+ if (key === "$ref" && typeof val === "string") {
75
+ visit(val);
76
+ } else if (!schemaLevel) {
77
+ visitJsonSchemaRefs(val, visit, true, seen);
78
+ } else if (JSON_SCHEMA_LOGIC_KEYWORDS.has(key) || JSON_SCHEMA_RECORD_KEYWORDS.has(key)) {
79
+ visitJsonSchemaRefs(val, visit, !JSON_SCHEMA_RECORD_KEYWORDS.has(key), seen);
80
+ }
81
+ }
82
+ }
62
83
  function mapJsonSchemaRefs(value, map, schemaLevel = true, path = []) {
63
84
  if (!value || typeof value !== "object") {
64
85
  return value;
@@ -67,7 +88,8 @@ function mapJsonSchemaRefs(value, map, schemaLevel = true, path = []) {
67
88
  return value.map((item, index) => mapJsonSchemaRefs(item, map, schemaLevel, [...path, index]));
68
89
  }
69
90
  const result = {};
70
- for (const [key, val] of Object.entries(value)) {
91
+ for (const key of Object.keys(value)) {
92
+ const val = value[key];
71
93
  if (key === "$ref" && typeof val === "string") {
72
94
  result[key] = map(val, [...path, key]);
73
95
  } else if (!schemaLevel) {
@@ -138,9 +160,40 @@ function findRecursiveJsonSchemaDefName(defs) {
138
160
  return `__schema${index}`;
139
161
  }
140
162
 
163
+ var JsonSchemaType = /* @__PURE__ */ ((JsonSchemaType2) => {
164
+ JsonSchemaType2["Array"] = "array";
165
+ JsonSchemaType2["Boolean"] = "boolean";
166
+ JsonSchemaType2["Integer"] = "integer";
167
+ JsonSchemaType2["Null"] = "null";
168
+ JsonSchemaType2["Number"] = "number";
169
+ JsonSchemaType2["Object"] = "object";
170
+ JsonSchemaType2["String"] = "string";
171
+ return JsonSchemaType2;
172
+ })(JsonSchemaType || {});
173
+ var JsonSchemaFormat = /* @__PURE__ */ ((JsonSchemaFormat2) => {
174
+ JsonSchemaFormat2["Date"] = "date";
175
+ JsonSchemaFormat2["DateTime"] = "date-time";
176
+ JsonSchemaFormat2["Duration"] = "duration";
177
+ JsonSchemaFormat2["Email"] = "email";
178
+ JsonSchemaFormat2["Hostname"] = "hostname";
179
+ JsonSchemaFormat2["IDNEmail"] = "idn-email";
180
+ JsonSchemaFormat2["IDNHostname"] = "idn-hostname";
181
+ JsonSchemaFormat2["IPv4"] = "ipv4";
182
+ JsonSchemaFormat2["IPv6"] = "ipv6";
183
+ JsonSchemaFormat2["IRI"] = "iri";
184
+ JsonSchemaFormat2["IRIReference"] = "iri-reference";
185
+ JsonSchemaFormat2["JSONPointer"] = "json-pointer";
186
+ JsonSchemaFormat2["RegEx"] = "regex";
187
+ JsonSchemaFormat2["RelativeJSONPointer"] = "relative-json-pointer";
188
+ JsonSchemaFormat2["Time"] = "time";
189
+ JsonSchemaFormat2["URI"] = "uri";
190
+ JsonSchemaFormat2["URIReference"] = "uri-reference";
191
+ JsonSchemaFormat2["URITemplate"] = "uri-template";
192
+ JsonSchemaFormat2["UUID"] = "uuid";
193
+ return JsonSchemaFormat2;
194
+ })(JsonSchemaFormat || {});
141
195
  var JsonSchemaXNativeType = /* @__PURE__ */ ((JsonSchemaXNativeType2) => {
142
196
  JsonSchemaXNativeType2["BigInt"] = "bigint";
143
- JsonSchemaXNativeType2["RegExp"] = "regexp";
144
197
  JsonSchemaXNativeType2["Date"] = "date";
145
198
  JsonSchemaXNativeType2["Url"] = "url";
146
199
  JsonSchemaXNativeType2["Set"] = "set";
@@ -148,7 +201,12 @@ var JsonSchemaXNativeType = /* @__PURE__ */ ((JsonSchemaXNativeType2) => {
148
201
  return JsonSchemaXNativeType2;
149
202
  })(JsonSchemaXNativeType || {});
150
203
 
151
- const FLEXIBLE_DATE_FORMAT_REGEX = /^[^-]+-[^-]+-[^-]+$/;
204
+ const UNSATISFIED = 0;
205
+ const LOOSELY_SATISFIED = 1;
206
+ const SATISFIED = 2;
207
+ function minSatisfaction(a, b) {
208
+ return a < b ? a : b;
209
+ }
152
210
  class JsonSchemaCoercer {
153
211
  coerce([schema, optional], value) {
154
212
  if (optional && value === void 0) {
@@ -157,25 +215,29 @@ class JsonSchemaCoercer {
157
215
  const [, coerced] = this.coerceInternal(schema, schema, value);
158
216
  return coerced;
159
217
  }
160
- coerceInternal(rootSchema, schema, value) {
218
+ coerceInternal(rootSchema, schema, value, appliedRefs) {
161
219
  if (typeof schema === "boolean") {
162
- return [schema, value];
220
+ return [schema ? SATISFIED : UNSATISFIED, value];
163
221
  }
164
222
  if (Array.isArray(schema.type)) {
165
223
  return this.coerceInternal(
166
224
  rootSchema,
167
225
  { anyOf: schema.type.map((type) => ({ ...schema, type })) },
168
- value
226
+ value,
227
+ appliedRefs
169
228
  );
170
229
  }
171
230
  let coerced = value;
172
- let satisfied = true;
231
+ let satisfied = SATISFIED;
173
232
  if (typeof schema.$ref === "string") {
174
233
  const resolved = schema.$ref.startsWith("#/") ? get(rootSchema, schema.$ref.slice("#/".length).split("/").map(decodeJsonPointerSegment)) : schema.$ref === "#" ? rootSchema : void 0;
175
- if (resolved !== void 0) {
176
- const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, resolved, coerced);
234
+ if (resolved !== void 0 && !appliedRefs?.has(resolved)) {
235
+ appliedRefs ??= /* @__PURE__ */ new Set();
236
+ appliedRefs.add(resolved);
237
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, resolved, coerced, appliedRefs);
238
+ appliedRefs.delete(resolved);
177
239
  coerced = subCoerced;
178
- satisfied = subSatisfied;
240
+ satisfied = minSatisfaction(satisfied, subSatisfied);
179
241
  }
180
242
  }
181
243
  const enumValues = schema.const !== void 0 ? [schema.const] : schema.enum;
@@ -189,24 +251,24 @@ class JsonSchemaCoercer {
189
251
  if (enumValues.includes(booleanValue)) {
190
252
  coerced = booleanValue;
191
253
  } else {
192
- satisfied = false;
254
+ satisfied = UNSATISFIED;
193
255
  }
194
256
  }
195
257
  } else {
196
- satisfied = false;
258
+ satisfied = UNSATISFIED;
197
259
  }
198
260
  }
199
261
  if (schema.type) {
200
262
  switch (schema.type) {
201
263
  case "null": {
202
264
  if (coerced !== null) {
203
- satisfied = false;
265
+ satisfied = UNSATISFIED;
204
266
  }
205
267
  break;
206
268
  }
207
269
  case "string": {
208
270
  if (typeof coerced !== "string") {
209
- satisfied = false;
271
+ satisfied = UNSATISFIED;
210
272
  }
211
273
  break;
212
274
  }
@@ -215,7 +277,7 @@ class JsonSchemaCoercer {
215
277
  coerced = stringToNumber(coerced);
216
278
  }
217
279
  if (typeof coerced !== "number") {
218
- satisfied = false;
280
+ satisfied = UNSATISFIED;
219
281
  }
220
282
  break;
221
283
  }
@@ -224,7 +286,7 @@ class JsonSchemaCoercer {
224
286
  coerced = stringToInteger(coerced);
225
287
  }
226
288
  if (typeof coerced !== "number" || !Number.isInteger(coerced)) {
227
- satisfied = false;
289
+ satisfied = UNSATISFIED;
228
290
  }
229
291
  break;
230
292
  }
@@ -233,7 +295,7 @@ class JsonSchemaCoercer {
233
295
  coerced = stringToBoolean(coerced);
234
296
  }
235
297
  if (typeof coerced !== "boolean") {
236
- satisfied = false;
298
+ satisfied = UNSATISFIED;
237
299
  }
238
300
  break;
239
301
  }
@@ -245,26 +307,24 @@ class JsonSchemaCoercer {
245
307
  const coercedItems = coerced.map((item, i) => {
246
308
  const subSchema = prefixItemSchemas[i] ?? itemSchema;
247
309
  if (subSchema === void 0) {
248
- satisfied = false;
310
+ satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
249
311
  return item;
250
312
  }
251
313
  const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, item);
252
- if (!subSatisfied) {
253
- satisfied = false;
254
- }
314
+ satisfied = minSatisfaction(satisfied, subSatisfied);
255
315
  if (subCoerced !== item) {
256
316
  shouldUseCoercedItems = true;
257
317
  }
258
318
  return subCoerced;
259
319
  });
260
320
  if (coercedItems.length < prefixItemSchemas.length) {
261
- satisfied = false;
321
+ satisfied = UNSATISFIED;
262
322
  }
263
323
  if (shouldUseCoercedItems) {
264
324
  coerced = coercedItems;
265
325
  }
266
326
  } else {
267
- satisfied = false;
327
+ satisfied = UNSATISFIED;
268
328
  }
269
329
  break;
270
330
  }
@@ -274,35 +334,36 @@ class JsonSchemaCoercer {
274
334
  }
275
335
  if (isPlainObject(coerced)) {
276
336
  let shouldUseCoercedItems = false;
277
- const coercedItems = {};
278
- const patternProperties = Object.entries(schema.patternProperties ?? {}).map(([key, value2]) => [new RegExp(key), value2]);
279
- for (const key in coerced) {
337
+ const coercedItems = { ...coerced };
338
+ const patternProperties = Object.entries(schema.patternProperties ?? {}).flatMap(([key, value2]) => {
339
+ const pattern = tryOrUndefined(() => new RegExp(key));
340
+ return pattern ? [[pattern, value2]] : [];
341
+ });
342
+ const propertySchemas = schema.properties ?? {};
343
+ for (const key of Object.keys(coerced)) {
280
344
  const value2 = coerced[key];
281
- const subSchema = schema.properties?.[key] ?? patternProperties.find(([pattern]) => pattern.test(key))?.[1] ?? schema.additionalProperties;
282
- if (value2 === void 0 && !schema.required?.includes(key)) {
283
- coercedItems[key] = value2;
284
- } else if (subSchema === void 0) {
285
- coercedItems[key] = value2;
286
- satisfied = false;
287
- } else {
288
- const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, value2);
289
- coercedItems[key] = subCoerced;
290
- if (!subSatisfied) {
291
- satisfied = false;
292
- }
293
- if (subCoerced !== value2) {
294
- shouldUseCoercedItems = true;
345
+ const subSchema = getOwn(propertySchemas, key) ?? patternProperties.find(([pattern]) => pattern.test(key))?.[1] ?? schema.additionalProperties;
346
+ if (value2 !== void 0 || schema.required?.includes(key)) {
347
+ if (subSchema === void 0) {
348
+ satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
349
+ } else {
350
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, value2);
351
+ coercedItems[key] = subCoerced;
352
+ satisfied = minSatisfaction(satisfied, subSatisfied);
353
+ if (subCoerced !== value2) {
354
+ shouldUseCoercedItems = true;
355
+ }
295
356
  }
296
357
  }
297
358
  }
298
359
  if (schema.required?.some((key) => !Object.hasOwn(coercedItems, key))) {
299
- satisfied = false;
360
+ satisfied = UNSATISFIED;
300
361
  }
301
362
  if (shouldUseCoercedItems) {
302
363
  coerced = coercedItems;
303
364
  }
304
365
  } else {
305
- satisfied = false;
366
+ satisfied = UNSATISFIED;
306
367
  }
307
368
  break;
308
369
  }
@@ -315,7 +376,7 @@ class JsonSchemaCoercer {
315
376
  coerced = stringToDate(coerced);
316
377
  }
317
378
  if (!(coerced instanceof Date)) {
318
- satisfied = false;
379
+ satisfied = UNSATISFIED;
319
380
  }
320
381
  break;
321
382
  }
@@ -329,16 +390,7 @@ class JsonSchemaCoercer {
329
390
  break;
330
391
  }
331
392
  if (typeof coerced !== "bigint") {
332
- satisfied = false;
333
- }
334
- break;
335
- }
336
- case JsonSchemaXNativeType.RegExp: {
337
- if (typeof coerced === "string") {
338
- coerced = stringToRegExp(coerced);
339
- }
340
- if (!(coerced instanceof RegExp)) {
341
- satisfied = false;
393
+ satisfied = UNSATISFIED;
342
394
  }
343
395
  break;
344
396
  }
@@ -347,7 +399,7 @@ class JsonSchemaCoercer {
347
399
  coerced = stringToURL(coerced);
348
400
  }
349
401
  if (!(coerced instanceof URL)) {
350
- satisfied = false;
402
+ satisfied = UNSATISFIED;
351
403
  }
352
404
  break;
353
405
  }
@@ -356,7 +408,7 @@ class JsonSchemaCoercer {
356
408
  coerced = arrayToSet(coerced);
357
409
  }
358
410
  if (!(coerced instanceof Set)) {
359
- satisfied = false;
411
+ satisfied = UNSATISFIED;
360
412
  }
361
413
  break;
362
414
  }
@@ -365,7 +417,7 @@ class JsonSchemaCoercer {
365
417
  coerced = arrayToMap(coerced);
366
418
  }
367
419
  if (!(coerced instanceof Map)) {
368
- satisfied = false;
420
+ satisfied = UNSATISFIED;
369
421
  }
370
422
  break;
371
423
  }
@@ -373,54 +425,78 @@ class JsonSchemaCoercer {
373
425
  }
374
426
  if (schema.allOf) {
375
427
  for (const subSchema of schema.allOf) {
376
- const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced);
428
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced, appliedRefs);
377
429
  coerced = subCoerced;
378
- if (!subSatisfied) {
379
- satisfied = false;
380
- }
430
+ satisfied = minSatisfaction(satisfied, subSatisfied);
381
431
  }
382
432
  }
383
433
  for (const key of ["anyOf", "oneOf"]) {
384
434
  if (schema[key]) {
385
- let bestOptions;
435
+ let best;
386
436
  for (const subSchema of schema[key]) {
387
- const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced);
388
- if (subSatisfied) {
389
- if (!bestOptions || subCoerced === coerced) {
390
- bestOptions = { coerced: subCoerced, satisfied: subSatisfied };
391
- }
392
- if (subCoerced === coerced) {
393
- break;
394
- }
437
+ const [subSatisfied, subCoerced] = this.coerceInternal(rootSchema, subSchema, coerced, appliedRefs);
438
+ if (subSatisfied === UNSATISFIED) {
439
+ continue;
440
+ }
441
+ if (subCoerced === coerced) {
442
+ best = { satisfied: subSatisfied, value: subCoerced };
443
+ break;
395
444
  }
445
+ if (!best || subSatisfied > best.satisfied) {
446
+ best = { satisfied: subSatisfied, value: subCoerced };
447
+ }
448
+ }
449
+ if (best) {
450
+ coerced = best.value;
451
+ satisfied = minSatisfaction(satisfied, best.satisfied);
452
+ } else {
453
+ satisfied = UNSATISFIED;
396
454
  }
397
- coerced = bestOptions ? bestOptions.coerced : coerced;
398
- satisfied = bestOptions ? bestOptions.satisfied : false;
399
455
  }
400
456
  }
401
457
  if (typeof schema.not !== "undefined") {
402
- const [notSatisfied] = this.coerceInternal(rootSchema, schema.not, coerced);
403
- if (notSatisfied) {
404
- satisfied = false;
458
+ const [notSatisfied] = this.coerceInternal(rootSchema, schema.not, coerced, appliedRefs);
459
+ if (notSatisfied !== UNSATISFIED) {
460
+ satisfied = UNSATISFIED;
405
461
  }
406
462
  }
407
463
  return [satisfied, coerced];
408
464
  }
409
465
  }
466
+ const NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
410
467
  function stringToNumber(value) {
411
- const num = Number.parseFloat(value);
412
- if (Number.isNaN(num) || num !== Number(value)) {
468
+ if (!NUMBER_PATTERN.test(value)) {
469
+ return value;
470
+ }
471
+ const num = Number(value);
472
+ if (num < Number.MIN_SAFE_INTEGER || num > Number.MAX_SAFE_INTEGER) {
413
473
  return value;
414
474
  }
415
475
  return num;
416
476
  }
477
+ const INTEGER_PATTERN = /^-?(?:0|[1-9]\d*)$/;
417
478
  function stringToInteger(value) {
418
- const num = Number.parseInt(value);
419
- if (Number.isNaN(num) || num !== Number(value)) {
479
+ if (!INTEGER_PATTERN.test(value)) {
480
+ return value;
481
+ }
482
+ const num = Number(value);
483
+ if (!Number.isSafeInteger(num)) {
420
484
  return value;
421
485
  }
422
486
  return num;
423
487
  }
488
+ function stringToBigInt(value) {
489
+ if (!INTEGER_PATTERN.test(value)) {
490
+ return value;
491
+ }
492
+ return BigInt(value);
493
+ }
494
+ function numberToBigInt(value) {
495
+ if (!Number.isInteger(value)) {
496
+ return value;
497
+ }
498
+ return BigInt(value);
499
+ }
424
500
  function stringToBoolean(value) {
425
501
  const lower = value.toLowerCase();
426
502
  if (lower === "false" || lower === "off") {
@@ -431,27 +507,17 @@ function stringToBoolean(value) {
431
507
  }
432
508
  return value;
433
509
  }
434
- function stringToBigInt(value) {
435
- return tryOrUndefined(() => BigInt(value)) ?? value;
436
- }
437
- function numberToBigInt(value) {
438
- return tryOrUndefined(() => BigInt(value)) ?? value;
439
- }
510
+ const DATE_TIME_PATTERN = /^[+-]?\d{4,6}-\d{1,2}-\d{1,2}(?:[T ].*)?$/;
440
511
  function stringToDate(value) {
512
+ if (!DATE_TIME_PATTERN.test(value)) {
513
+ return value;
514
+ }
441
515
  const date = new Date(value);
442
- if (Number.isNaN(date.getTime()) || !FLEXIBLE_DATE_FORMAT_REGEX.test(value)) {
516
+ if (Number.isNaN(date.getTime())) {
443
517
  return value;
444
518
  }
445
519
  return date;
446
520
  }
447
- function stringToRegExp(value) {
448
- const match = value.match(/^\/(.*)\/([a-z]*)$/);
449
- if (match) {
450
- const [, pattern, flags] = match;
451
- return tryOrUndefined(() => new RegExp(pattern, flags)) ?? value;
452
- }
453
- return value;
454
- }
455
521
  function stringToURL(value) {
456
522
  return tryOrUndefined(() => new URL(value)) ?? value;
457
523
  }
@@ -513,148 +579,85 @@ function ensureJsonSchemaObject(schema) {
513
579
  return schema;
514
580
  }
515
581
 
582
+ function promoteJsonSchemaDefs(schema, mergedDefs, basePath) {
583
+ const { $defs, ...rootBody } = schema;
584
+ const renameMap = /* @__PURE__ */ new Map();
585
+ const mapRef = (ref) => {
586
+ if (ref === "#") {
587
+ return basePath;
588
+ }
589
+ if (ref.startsWith("#/$defs/")) {
590
+ const [encodedName, ...segments] = ref.slice("#/$defs/".length).split("/");
591
+ const newName = renameMap.get(decodeJsonPointerSegment(encodedName));
592
+ return newName === void 0 ? ref : ["#/$defs", encodeJsonPointerSegment(newName), ...segments].join("/");
593
+ }
594
+ if (ref.startsWith("#/") && get(rootBody, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
595
+ return `${basePath}/${ref.slice(2)}`;
596
+ }
597
+ return ref;
598
+ };
599
+ const defs = Object.entries($defs ?? {}).filter(([, def]) => def !== void 0);
600
+ if (defs.length > 0) {
601
+ const promoted = /* @__PURE__ */ new Map();
602
+ const reserved = /* @__PURE__ */ new Set([...mergedDefs.keys(), ...defs.map(([name]) => name)]);
603
+ for (let changed = true; changed; ) {
604
+ changed = false;
605
+ for (const [name, def] of defs) {
606
+ const body = mapJsonSchemaRefs(def, mapRef);
607
+ promoted.set(name, body);
608
+ if (renameMap.has(name) || !mergedDefs.has(name) || isDeepEqual(mergedDefs.get(name), body)) {
609
+ continue;
610
+ }
611
+ let counter = 2;
612
+ while (reserved.has(`${name}${counter}`)) {
613
+ counter++;
614
+ }
615
+ reserved.add(`${name}${counter}`);
616
+ renameMap.set(name, `${name}${counter}`);
617
+ changed = true;
618
+ }
619
+ }
620
+ for (const [name, body] of promoted) {
621
+ mergedDefs.set(renameMap.get(name) ?? name, body);
622
+ }
623
+ }
624
+ return mapJsonSchemaRefs(rootBody, mapRef);
625
+ }
516
626
  function combineJsonSchemasWithComposition(keyword, schemas) {
517
627
  if (schemas.length <= 1) {
518
628
  return schemas[0] ?? true;
519
629
  }
520
- const mergedDefs = {};
630
+ const mergedDefs = /* @__PURE__ */ new Map();
521
631
  const compositionBranches = [];
522
632
  for (let i = 0; i < schemas.length; i++) {
523
633
  const schema = schemas[i];
524
- if (typeof schema === "boolean") {
525
- compositionBranches.push(schema);
526
- continue;
527
- }
528
- const { $defs, ...rest } = schema;
529
- const renameMap = {};
530
- const promotedNames = /* @__PURE__ */ new Set();
531
- if ($defs) {
532
- for (const [name, def] of Object.entries($defs)) {
533
- if (def === void 0)
534
- continue;
535
- promotedNames.add(name);
536
- if (name in mergedDefs) {
537
- if (isDeepEqual(mergedDefs[name], def)) {
538
- continue;
539
- }
540
- let counter = 2;
541
- let newName = `${name}${counter}`;
542
- while (newName in mergedDefs) {
543
- counter++;
544
- newName = `${name}${counter}`;
545
- }
546
- mergedDefs[newName] = def;
547
- renameMap[name] = newName;
548
- } else {
549
- mergedDefs[name] = def;
550
- }
551
- }
552
- }
553
- compositionBranches.push(mapJsonSchemaRefs(
554
- rest,
555
- (ref) => {
556
- if (ref === "#") {
557
- return `#/${keyword}/${i}`;
558
- }
559
- if (ref.startsWith("#/$defs/")) {
560
- const afterPrefix = ref.slice("#/$defs/".length);
561
- const slashIdx = afterPrefix.indexOf("/");
562
- const encodedSegment = slashIdx === -1 ? afterPrefix : afterPrefix.slice(0, slashIdx);
563
- const rest2 = slashIdx === -1 ? "" : afterPrefix.slice(slashIdx);
564
- const defName = decodeJsonPointerSegment(encodedSegment);
565
- if (!promotedNames.has(defName)) {
566
- return ref;
567
- }
568
- if (defName in renameMap) {
569
- return `#/$defs/${encodeJsonPointerSegment(renameMap[defName])}${rest2}`;
570
- }
571
- return ref;
572
- }
573
- if (ref.startsWith("#/") && get(rest, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
574
- return `#/${keyword}/${i}/${ref.slice(2)}`;
575
- }
576
- return ref;
577
- }
578
- ));
634
+ compositionBranches.push(typeof schema === "boolean" ? schema : promoteJsonSchemaDefs(schema, mergedDefs, `#/${keyword}/${i}`));
579
635
  }
580
636
  const result = { [keyword]: compositionBranches };
581
- if (Object.keys(mergedDefs).length > 0) {
582
- result.$defs = mergedDefs;
637
+ if (mergedDefs.size > 0) {
638
+ result.$defs = Object.fromEntries(mergedDefs);
583
639
  }
584
640
  return result;
585
641
  }
586
642
  function combineJsonObjectSchemaEntries(entries) {
587
- const properties = {};
643
+ const properties = /* @__PURE__ */ new Map();
588
644
  const required = [];
589
- const mergedDefs = {};
645
+ const mergedDefs = /* @__PURE__ */ new Map();
590
646
  for (const [name, propertySchema, optional] of entries) {
591
647
  if (!optional) {
592
648
  required.push(name);
593
649
  }
594
- if (typeof propertySchema === "boolean") {
595
- properties[name] = propertySchema;
596
- continue;
597
- }
598
- const { $defs, ...rest } = propertySchema;
599
- const renameMap = {};
600
- const promotedNames = /* @__PURE__ */ new Set();
601
- if ($defs) {
602
- for (const [defName, def] of Object.entries($defs)) {
603
- if (def === void 0) {
604
- continue;
605
- }
606
- promotedNames.add(defName);
607
- if (defName in mergedDefs) {
608
- if (isDeepEqual(mergedDefs[defName], def)) {
609
- continue;
610
- }
611
- let counter = 2;
612
- let newName = `${defName}${counter}`;
613
- while (newName in mergedDefs) {
614
- counter++;
615
- newName = `${defName}${counter}`;
616
- }
617
- mergedDefs[newName] = def;
618
- renameMap[defName] = newName;
619
- } else {
620
- mergedDefs[defName] = def;
621
- }
622
- }
623
- }
624
- const propertyPathPrefix = `#/properties/${encodeJsonPointerSegment(name)}`;
625
- properties[name] = mapJsonSchemaRefs(rest, (ref) => {
626
- if (ref.startsWith("#/$defs/")) {
627
- const afterPrefix = ref.slice("#/$defs/".length);
628
- const slashIdx = afterPrefix.indexOf("/");
629
- const encodedSegment = slashIdx === -1 ? afterPrefix : afterPrefix.slice(0, slashIdx);
630
- const refRest = slashIdx === -1 ? "" : afterPrefix.slice(slashIdx);
631
- const defName = decodeJsonPointerSegment(encodedSegment);
632
- if (!promotedNames.has(defName)) {
633
- return ref;
634
- }
635
- if (defName in renameMap) {
636
- return `#/$defs/${encodeJsonPointerSegment(renameMap[defName])}${refRest}`;
637
- }
638
- return ref;
639
- }
640
- if (ref === "#") {
641
- return propertyPathPrefix;
642
- }
643
- if (ref.startsWith("#/") && get(rest, ref.slice(2).split("/").map(decodeJsonPointerSegment)) !== void 0) {
644
- return `${propertyPathPrefix}/${ref.slice(2)}`;
645
- }
646
- return ref;
647
- });
650
+ properties.set(name, typeof propertySchema === "boolean" ? propertySchema : promoteJsonSchemaDefs(propertySchema, mergedDefs, `#/properties/${encodeJsonPointerSegment(name)}`));
648
651
  }
649
652
  const schema = {
650
653
  type: "object",
651
- properties
654
+ properties: Object.fromEntries(properties)
652
655
  };
653
656
  if (required.length > 0) {
654
657
  schema.required = required;
655
658
  }
656
- if (Object.keys(mergedDefs).length > 0) {
657
- schema.$defs = mergedDefs;
659
+ if (mergedDefs.size > 0) {
660
+ schema.$defs = Object.fromEntries(mergedDefs);
658
661
  }
659
662
  return schema;
660
663
  }
@@ -774,7 +777,7 @@ function flattenJsonUnionSchemaInternal(schema, resolvingRefs) {
774
777
  }
775
778
  const resolved = resolveJsonSchemaRootLocalRef(schema);
776
779
  if (resolved !== schema) {
777
- const result = flattenJsonUnionSchemaInternal(resolved, resolvingRefs.add(schema.$ref));
780
+ const result = flattenJsonUnionSchemaInternal(resolved, new Set(resolvingRefs).add(schema.$ref));
778
781
  if (result.length > 1) {
779
782
  return result;
780
783
  }
@@ -844,13 +847,14 @@ class DelegatingJsonSchemaConverter {
844
847
  constructor(converters = []) {
845
848
  this.converters = converters;
846
849
  }
847
- async convert(schema, direction) {
850
+ convert(schema, direction) {
848
851
  for (const converter of this.converters) {
849
- if (await converter.condition(schema, direction)) {
852
+ if (converter.condition(schema, direction)) {
850
853
  return converter.convert(schema, direction);
851
854
  }
852
855
  }
853
- const optional = !(await schema?.["~standard"].validate(void 0))?.issues?.length;
856
+ const result = schema?.["~standard"].validate(void 0);
857
+ const optional = result instanceof Promise ? false : !result?.issues?.length;
854
858
  if (schema && "jsonSchema" in schema["~standard"] && schema["~standard"].jsonSchema) {
855
859
  try {
856
860
  return [
@@ -907,23 +911,23 @@ class SmartCoercionHandlerPlugin {
907
911
  return {
908
912
  ...options,
909
913
  clientInterceptors: [
910
- async ({ next, input, ...interceptorOptions }) => {
914
+ ({ next, input, ...interceptorOptions }) => {
911
915
  const inputSchemas = interceptorOptions.procedure["~orpc"].inputSchemas;
912
916
  if (!inputSchemas) {
913
917
  return next();
914
918
  }
915
- const coercedInput = await this.coerceValue(inputSchemas, input);
919
+ const coercedInput = this.coerceValue(inputSchemas, input);
916
920
  return next({ ...interceptorOptions, input: coercedInput });
917
921
  },
918
922
  ...toArray(options.clientInterceptors)
919
923
  ]
920
924
  };
921
925
  }
922
- async coerceValue(schemas, value) {
926
+ coerceValue(schemas, value) {
923
927
  for (const schema of schemas) {
924
928
  let converted = this.cache.get(schema);
925
929
  if (!converted) {
926
- converted = await this.converter.convert(schema, "input");
930
+ converted = this.converter.convert(schema, "input");
927
931
  this.cache.set(schema, converted);
928
932
  }
929
933
  value = this.coercer.coerce(converted, value);
@@ -962,30 +966,30 @@ class SmartCoercionLinkPlugin {
962
966
  if (!outputSchemas) {
963
967
  return output;
964
968
  }
965
- const coercedOutput = await this.coerceValue(outputSchemas, output);
969
+ const coercedOutput = this.coerceValue(outputSchemas, output);
966
970
  return coercedOutput;
967
971
  } catch (error) {
968
972
  if (!(error instanceof ORPCError) || !error.defined) {
969
973
  throw error;
970
974
  }
971
975
  const errorMap = procedure["~orpc"].errorMap;
972
- const dataSchema = errorMap[error.code]?.data;
976
+ const dataSchema = getOwn(errorMap, error.code)?.data;
973
977
  if (!dataSchema) {
974
978
  throw error;
975
979
  }
976
980
  const cloned = cloneORPCError(error);
977
- cloned.data = await this.coerceValue([dataSchema], cloned.data);
981
+ cloned.data = this.coerceValue([dataSchema], cloned.data);
978
982
  throw cloned;
979
983
  }
980
984
  }
981
985
  ]
982
986
  };
983
987
  }
984
- async coerceValue(schemas, value) {
988
+ coerceValue(schemas, value) {
985
989
  for (const schema of schemas) {
986
990
  let converted = this.cache.get(schema);
987
991
  if (!converted) {
988
- converted = await this.converter.convert(schema, "output");
992
+ converted = this.converter.convert(schema, "output");
989
993
  this.cache.set(schema, converted);
990
994
  }
991
995
  value = this.coercer.coerce(converted, value);
@@ -994,4 +998,4 @@ class SmartCoercionLinkPlugin {
994
998
  }
995
999
  }
996
1000
 
997
- export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef };
1001
+ export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };