prisma-guard 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,12 @@ var CallerError = class extends Error {
26
26
  this.name = "CallerError";
27
27
  }
28
28
  };
29
+ function formatZodError(err) {
30
+ return err.issues.map((i) => {
31
+ const p = i.path.length > 0 ? `${i.path.join(".")}: ` : "";
32
+ return `${p}${i.message}`;
33
+ }).join("; ");
34
+ }
29
35
 
30
36
  // src/runtime/schema-builder.ts
31
37
  import { z as z3 } from "zod";
@@ -36,9 +42,15 @@ import { z as z2 } from "zod";
36
42
  // src/shared/scalar-base.ts
37
43
  import { z } from "zod";
38
44
  function isJsonSafe(value) {
39
- const stack = [value];
45
+ const stack = [{ tag: "visit", value }];
46
+ const ancestors = /* @__PURE__ */ new Set();
40
47
  while (stack.length > 0) {
41
- const current = stack.pop();
48
+ const entry = stack.pop();
49
+ if (entry.tag === "exit") {
50
+ ancestors.delete(entry.ref);
51
+ continue;
52
+ }
53
+ const current = entry.value;
42
54
  if (current === void 0)
43
55
  return false;
44
56
  if (current === null)
@@ -52,9 +64,13 @@ function isJsonSafe(value) {
52
64
  return false;
53
65
  continue;
54
66
  case "object": {
67
+ if (ancestors.has(current))
68
+ return false;
69
+ ancestors.add(current);
70
+ stack.push({ tag: "exit", ref: current });
55
71
  if (Array.isArray(current)) {
56
72
  for (let i = 0; i < current.length; i++) {
57
- stack.push(current[i]);
73
+ stack.push({ tag: "visit", value: current[i] });
58
74
  }
59
75
  continue;
60
76
  }
@@ -63,7 +79,7 @@ function isJsonSafe(value) {
63
79
  return false;
64
80
  const values = Object.values(current);
65
81
  for (let i = 0; i < values.length; i++) {
66
- stack.push(values[i]);
82
+ stack.push({ tag: "visit", value: values[i] });
67
83
  }
68
84
  continue;
69
85
  }
@@ -82,6 +98,10 @@ var SCALAR_BASE = {
82
98
  z.string().refine(
83
99
  (s) => /^-?(\d+\.?\d*|\.\d+)([eE]-?\d+)?$/.test(s),
84
100
  "Invalid decimal string"
101
+ ),
102
+ z.custom(
103
+ (v) => v !== null && typeof v === "object" && typeof v.toFixed === "function" && typeof v.toNumber === "function",
104
+ "Expected Decimal-compatible object"
85
105
  )
86
106
  ]),
87
107
  BigInt: () => z.union([
@@ -98,7 +118,7 @@ var SCALAR_BASE = {
98
118
  z.string().datetime({ offset: true }),
99
119
  z.string().datetime()
100
120
  ]).pipe(z.coerce.date()),
101
- Json: () => z.unknown().refine(isJsonSafe, "Value must be JSON-serializable (no undefined, functions, symbols, class instances, NaN, or Infinity)"),
121
+ Json: () => z.unknown().refine(isJsonSafe, "Value must be JSON-serializable (no undefined, functions, symbols, class instances, NaN, Infinity, or circular references)"),
102
122
  Bytes: () => z.union([
103
123
  z.string(),
104
124
  z.custom((v) => v instanceof Uint8Array)
@@ -238,6 +258,12 @@ function lruSet(cache, key, value, maxSize) {
238
258
  cache.delete(oldest);
239
259
  }
240
260
  }
261
+ function isZodSchema(value) {
262
+ if (value == null || typeof value !== "object")
263
+ return false;
264
+ const v = value;
265
+ return typeof v.parse === "function" && typeof v.optional === "function";
266
+ }
241
267
  function createSchemaBuilder(typeMap, zodChains, enumMap) {
242
268
  const chainCache = /* @__PURE__ */ new Map();
243
269
  function buildFieldSchema(model, field) {
@@ -281,7 +307,7 @@ function createSchemaBuilder(typeMap, zodChains, enumMap) {
281
307
  throw new ShapeError('InputOpts cannot define both "pick" and "omit"');
282
308
  }
283
309
  const mode = opts.mode ?? "create";
284
- const allowNull = opts.allowNull ?? false;
310
+ const allowNull = opts.allowNull ?? true;
285
311
  const modelFields = typeMap[model];
286
312
  if (!modelFields)
287
313
  throw new ShapeError(`Unknown model: ${model}`);
@@ -311,7 +337,21 @@ function createSchemaBuilder(typeMap, zodChains, enumMap) {
311
337
  const fieldMeta = modelFields[name];
312
338
  let fieldSchema;
313
339
  if (opts.refine?.[name]) {
314
- fieldSchema = opts.refine[name](buildBaseFieldSchema(model, name));
340
+ let refined;
341
+ try {
342
+ refined = opts.refine[name](buildBaseFieldSchema(model, name));
343
+ } catch (err) {
344
+ throw new ShapeError(
345
+ `Refine function for "${model}.${name}" threw: ${err.message}`,
346
+ { cause: err }
347
+ );
348
+ }
349
+ if (!isZodSchema(refined)) {
350
+ throw new ShapeError(
351
+ `Refine function for "${model}.${name}" must return a Zod schema`
352
+ );
353
+ }
354
+ fieldSchema = refined;
315
355
  } else {
316
356
  fieldSchema = buildFieldSchema(model, name);
317
357
  }
@@ -410,10 +450,12 @@ function createSchemaBuilder(typeMap, zodChains, enumMap) {
410
450
  schemaMap[relName] = relSchema;
411
451
  }
412
452
  if (opts._count) {
413
- const relationNames = Object.keys(modelFields).filter((n) => modelFields[n].isRelation);
453
+ const listRelationNames = Object.keys(modelFields).filter(
454
+ (n) => modelFields[n].isRelation && modelFields[n].isList
455
+ );
414
456
  if (opts._count === true) {
415
457
  const countFields = {};
416
- for (const relName of relationNames) {
458
+ for (const relName of listRelationNames) {
417
459
  countFields[relName] = z3.number().int().min(0);
418
460
  }
419
461
  schemaMap["_count"] = z3.object(countFields);
@@ -424,6 +466,8 @@ function createSchemaBuilder(typeMap, zodChains, enumMap) {
424
466
  throw new ShapeError(`Unknown field "${relName}" on model "${model}" in _count`);
425
467
  if (!modelFields[relName].isRelation)
426
468
  throw new ShapeError(`Field "${relName}" is not a relation on model "${model}" in _count`);
469
+ if (!modelFields[relName].isList)
470
+ throw new ShapeError(`Field "${relName}" is a to-one relation on model "${model}" in _count. Only to-many relations support _count.`);
427
471
  countFields[relName] = z3.number().int().min(0);
428
472
  }
429
473
  schemaMap["_count"] = z3.object(countFields);
@@ -439,7 +483,7 @@ function createSchemaBuilder(typeMap, zodChains, enumMap) {
439
483
  }
440
484
 
441
485
  // src/runtime/query-builder.ts
442
- import { z as z4 } from "zod";
486
+ import { z as z7 } from "zod";
443
487
 
444
488
  // src/shared/constants.ts
445
489
  var SHAPE_CONFIG_KEYS = /* @__PURE__ */ new Set([
@@ -463,6 +507,13 @@ var GUARD_SHAPE_KEYS = /* @__PURE__ */ new Set([
463
507
  "data",
464
508
  ...SHAPE_CONFIG_KEYS
465
509
  ]);
510
+ var COMBINATOR_KEYS = /* @__PURE__ */ new Set(["AND", "OR", "NOT"]);
511
+ var TO_MANY_RELATION_OPS = /* @__PURE__ */ new Set(["some", "every", "none"]);
512
+ var TO_ONE_RELATION_OPS = /* @__PURE__ */ new Set(["is", "isNot"]);
513
+ var ALL_RELATION_OPS = /* @__PURE__ */ new Set([...TO_MANY_RELATION_OPS, ...TO_ONE_RELATION_OPS]);
514
+ function toDelegateKey(modelName) {
515
+ return modelName[0].toLowerCase() + modelName.slice(1);
516
+ }
466
517
 
467
518
  // src/shared/match-caller.ts
468
519
  function matchCallerPattern(patterns, caller) {
@@ -498,130 +549,107 @@ function matchCallerPattern(patterns, caller) {
498
549
  return matches[0];
499
550
  }
500
551
 
552
+ // src/shared/is-plain-object.ts
553
+ function isPlainObject(v) {
554
+ if (typeof v !== "object" || v === null || Array.isArray(v))
555
+ return false;
556
+ const proto = Object.getPrototypeOf(v);
557
+ return proto === Object.prototype || proto === null;
558
+ }
559
+
501
560
  // src/runtime/policy.ts
502
561
  function requireContext(ctx, label) {
503
562
  if (ctx === void 0 || ctx === null) {
504
563
  throw new PolicyError(`Context required for ${label}`);
505
564
  }
506
565
  }
566
+ function validateContext(ctx) {
567
+ if (ctx === null || ctx === void 0) {
568
+ throw new PolicyError(
569
+ `guard.extension() context function must return a plain object, got ${String(ctx)}`
570
+ );
571
+ }
572
+ if (!isPlainObject(ctx)) {
573
+ throw new PolicyError(
574
+ `guard.extension() context function must return a plain object, got ${Array.isArray(ctx) ? "array" : typeof ctx}`
575
+ );
576
+ }
577
+ return ctx;
578
+ }
507
579
 
508
- // src/runtime/query-builder.ts
509
- var METHOD_ALLOWED_ARGS = {
510
- findMany: /* @__PURE__ */ new Set([
511
- "where",
512
- "include",
513
- "select",
514
- "orderBy",
515
- "cursor",
516
- "take",
517
- "skip",
518
- "distinct"
519
- ]),
520
- findFirst: /* @__PURE__ */ new Set([
521
- "where",
522
- "include",
523
- "select",
524
- "orderBy",
525
- "cursor",
526
- "take",
527
- "skip",
528
- "distinct"
529
- ]),
530
- findFirstOrThrow: /* @__PURE__ */ new Set([
531
- "where",
532
- "include",
533
- "select",
534
- "orderBy",
535
- "cursor",
536
- "take",
537
- "skip",
538
- "distinct"
539
- ]),
540
- findUnique: /* @__PURE__ */ new Set(["where", "include", "select"]),
541
- findUniqueOrThrow: /* @__PURE__ */ new Set(["where", "include", "select"]),
542
- count: /* @__PURE__ */ new Set(["where", "select", "cursor", "orderBy", "skip", "take"]),
543
- aggregate: /* @__PURE__ */ new Set([
544
- "where",
545
- "orderBy",
546
- "cursor",
547
- "take",
548
- "skip",
549
- "_count",
550
- "_avg",
551
- "_sum",
552
- "_min",
553
- "_max"
554
- ]),
555
- groupBy: /* @__PURE__ */ new Set([
556
- "where",
557
- "by",
558
- "having",
559
- "_count",
560
- "_avg",
561
- "_sum",
562
- "_min",
563
- "_max",
564
- "orderBy",
565
- "take",
566
- "skip"
567
- ])
568
- };
569
- var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
570
- "findUnique",
571
- "findUniqueOrThrow"
572
- ]);
573
- var STRING_MODE_OPS = /* @__PURE__ */ new Set([
574
- "contains",
575
- "startsWith",
576
- "endsWith",
577
- "equals"
578
- ]);
579
- var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
580
- var UNSUPPORTED_BY_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
581
- var KNOWN_NESTED_INCLUDE_KEYS = /* @__PURE__ */ new Set([
582
- "where",
583
- "include",
584
- "select",
585
- "orderBy",
586
- "cursor",
587
- "take",
588
- "skip"
589
- ]);
590
- var KNOWN_NESTED_SELECT_KEYS = /* @__PURE__ */ new Set([
591
- "select",
592
- "where",
593
- "orderBy",
594
- "cursor",
595
- "take",
596
- "skip"
597
- ]);
598
- var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
599
- function isPlainObject(v) {
600
- if (typeof v !== "object" || v === null || Array.isArray(v))
601
- return false;
602
- const proto = Object.getPrototypeOf(v);
603
- return proto === Object.prototype || proto === null;
580
+ // src/runtime/query-builder-where.ts
581
+ import { z as z4 } from "zod";
582
+
583
+ // src/runtime/query-builder-forced.ts
584
+ var EMPTY_WHERE_FORCED = { conditions: {}, relations: {} };
585
+ function hasWhereForced(f) {
586
+ return Object.keys(f.conditions).length > 0 || Object.keys(f.relations).length > 0;
604
587
  }
605
- function mergeForced(where, forced) {
606
- if (!where)
607
- return forced;
608
- return { AND: [where, forced] };
588
+ function mergeWhereForced(where, forced) {
589
+ if (!hasWhereForced(forced))
590
+ return where ?? {};
591
+ let result = where ? structuredClone(where) : {};
592
+ for (const [relName, opMap] of Object.entries(forced.relations)) {
593
+ if (!result[relName] || typeof result[relName] !== "object") {
594
+ result[relName] = {};
595
+ }
596
+ const relObj = result[relName];
597
+ for (const [op, nestedForced] of Object.entries(opMap)) {
598
+ relObj[op] = mergeWhereForced(
599
+ relObj[op],
600
+ nestedForced
601
+ );
602
+ }
603
+ }
604
+ if (Object.keys(forced.conditions).length > 0) {
605
+ const scalarClone = structuredClone(forced.conditions);
606
+ if (Object.keys(result).length === 0) {
607
+ result = scalarClone;
608
+ } else {
609
+ result = { AND: [result, scalarClone] };
610
+ }
611
+ }
612
+ return result;
609
613
  }
610
- function mergeUniqueForced(where, forced) {
611
- if (!where)
612
- return { ...forced };
613
- return { ...where, AND: [forced] };
614
+ function mergeUniqueWhereForced(where, forced) {
615
+ if (!hasWhereForced(forced))
616
+ return where ?? {};
617
+ let result = where ? { ...where } : {};
618
+ for (const [relName, opMap] of Object.entries(forced.relations)) {
619
+ if (!result[relName] || typeof result[relName] !== "object") {
620
+ result[relName] = {};
621
+ }
622
+ const relObj = result[relName];
623
+ for (const [op, nestedForced] of Object.entries(opMap)) {
624
+ relObj[op] = mergeWhereForced(
625
+ relObj[op],
626
+ nestedForced
627
+ );
628
+ }
629
+ }
630
+ if (Object.keys(forced.conditions).length > 0) {
631
+ const conditions = [structuredClone(forced.conditions)];
632
+ const existing = result.AND;
633
+ if (existing) {
634
+ if (Array.isArray(existing)) {
635
+ conditions.unshift(...existing);
636
+ } else {
637
+ conditions.unshift(existing);
638
+ }
639
+ }
640
+ result.AND = conditions;
641
+ }
642
+ return result;
614
643
  }
615
644
  function applyBuiltShape(built, body, isUniqueMethod) {
616
645
  const validated = built.zodSchema.parse(body);
617
- if (Object.keys(built.forcedWhere).length > 0) {
618
- const cloned = structuredClone(built.forcedWhere);
619
- validated.where = isUniqueMethod ? mergeUniqueForced(
646
+ if (hasWhereForced(built.forcedWhere)) {
647
+ validated.where = isUniqueMethod ? mergeUniqueWhereForced(
620
648
  validated.where,
621
- cloned
622
- ) : mergeForced(
649
+ built.forcedWhere
650
+ ) : mergeWhereForced(
623
651
  validated.where,
624
- cloned
652
+ built.forcedWhere
625
653
  );
626
654
  }
627
655
  if (Object.keys(built.forcedIncludeTree).length > 0) {
@@ -631,16 +659,14 @@ function applyBuiltShape(built, body, isUniqueMethod) {
631
659
  applyForcedTree(validated, "select", built.forcedSelectTree);
632
660
  }
633
661
  if (Object.keys(built.forcedIncludeCountWhere).length > 0) {
634
- const includeContainer = validated.include;
635
- if (includeContainer) {
636
- applyForcedCountWhere(includeContainer, built.forcedIncludeCountWhere);
637
- }
662
+ const ic = validated.include;
663
+ if (ic)
664
+ applyForcedCountWhere(ic, built.forcedIncludeCountWhere);
638
665
  }
639
666
  if (Object.keys(built.forcedSelectCountWhere).length > 0) {
640
- const selectContainer = validated.select;
641
- if (selectContainer) {
642
- applyForcedCountWhere(selectContainer, built.forcedSelectCountWhere);
643
- }
667
+ const sc = validated.select;
668
+ if (sc)
669
+ applyForcedCountWhere(sc, built.forcedSelectCountWhere);
644
670
  }
645
671
  return validated;
646
672
  }
@@ -654,8 +680,9 @@ function applyForcedTree(validated, key, tree) {
654
680
  continue;
655
681
  if (relVal === true) {
656
682
  const expanded = {};
657
- if (forced.where)
658
- expanded.where = structuredClone(forced.where);
683
+ if (forced.where && hasWhereForced(forced.where)) {
684
+ expanded.where = mergeWhereForced(void 0, forced.where);
685
+ }
659
686
  if (forced.include) {
660
687
  expanded.include = buildForcedOnlyContainer(forced.include);
661
688
  applyForcedTree(expanded, "include", forced.include);
@@ -666,10 +693,8 @@ function applyForcedTree(validated, key, tree) {
666
693
  }
667
694
  if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
668
695
  const countSelect = {};
669
- for (const [countRel, countForced] of Object.entries(
670
- forced._countWhere
671
- )) {
672
- countSelect[countRel] = { where: structuredClone(countForced) };
696
+ for (const [countRel, countForced] of Object.entries(forced._countWhere)) {
697
+ countSelect[countRel] = { where: mergeWhereForced(void 0, countForced) };
673
698
  }
674
699
  expanded._count = { select: countSelect };
675
700
  }
@@ -683,10 +708,10 @@ function applyForcedTree(validated, key, tree) {
683
708
  }
684
709
  if (isPlainObject(relVal)) {
685
710
  const relObj = relVal;
686
- if (forced.where) {
687
- relObj.where = mergeForced(
711
+ if (forced.where && hasWhereForced(forced.where)) {
712
+ relObj.where = mergeWhereForced(
688
713
  relObj.where,
689
- structuredClone(forced.where)
714
+ forced.where
690
715
  );
691
716
  }
692
717
  if (forced.include) {
@@ -714,18 +739,17 @@ function buildForcedOnlyContainer(tree) {
714
739
  const result = {};
715
740
  for (const [relName, forced] of Object.entries(tree)) {
716
741
  const nested = {};
717
- if (forced.where)
718
- nested.where = structuredClone(forced.where);
742
+ if (forced.where && hasWhereForced(forced.where)) {
743
+ nested.where = mergeWhereForced(void 0, forced.where);
744
+ }
719
745
  if (forced.include)
720
746
  nested.include = buildForcedOnlyContainer(forced.include);
721
747
  if (forced.select)
722
748
  nested.select = buildForcedOnlyContainer(forced.select);
723
749
  if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
724
750
  const countSelect = {};
725
- for (const [countRel, countForced] of Object.entries(
726
- forced._countWhere
727
- )) {
728
- countSelect[countRel] = { where: structuredClone(countForced) };
751
+ for (const [countRel, countForced] of Object.entries(forced._countWhere)) {
752
+ countSelect[countRel] = { where: mergeWhereForced(void 0, countForced) };
729
753
  }
730
754
  nested._count = { select: countSelect };
731
755
  }
@@ -747,12 +771,12 @@ function applyForcedCountWhere(container, forcedCountWhere) {
747
771
  if (relVal === void 0)
748
772
  continue;
749
773
  if (relVal === true) {
750
- selectObj[relName] = { where: structuredClone(forced) };
774
+ selectObj[relName] = { where: mergeWhereForced(void 0, forced) };
751
775
  } else if (isPlainObject(relVal)) {
752
776
  const relObj = relVal;
753
- relObj.where = mergeForced(
777
+ relObj.where = mergeWhereForced(
754
778
  relObj.where,
755
- structuredClone(forced)
779
+ forced
756
780
  );
757
781
  }
758
782
  }
@@ -789,17 +813,25 @@ function validateResolvedUniqueWhere(model, where, method, uniqueMap) {
789
813
  );
790
814
  }
791
815
  }
792
- function validateUniqueEquality(model, where, method, uniqueMap) {
816
+ function validateUniqueEquality(model, where, method, uniqueMap, typeMap) {
793
817
  const constraints = uniqueMap[model];
794
818
  if (!constraints || constraints.length === 0)
795
819
  return;
796
- const whereFields = new Set(Object.keys(where));
820
+ const combinators = /* @__PURE__ */ new Set(["AND", "OR", "NOT"]);
821
+ const whereFields = /* @__PURE__ */ new Set();
822
+ for (const key of Object.keys(where)) {
823
+ if (combinators.has(key))
824
+ continue;
825
+ if (typeMap && typeMap[model]?.[key]?.isRelation)
826
+ continue;
827
+ whereFields.add(key);
828
+ }
797
829
  const valid = constraints.some((constraint) => {
798
830
  if (!constraint.every((field) => whereFields.has(field)))
799
831
  return false;
800
832
  return constraint.every((field) => {
801
833
  const ops = where[field];
802
- if (!ops)
834
+ if (!ops || !isPlainObject(ops))
803
835
  return false;
804
836
  return Object.keys(ops).every((op) => op === "equals");
805
837
  });
@@ -811,191 +843,440 @@ function validateUniqueEquality(model, where, method, uniqueMap) {
811
843
  );
812
844
  }
813
845
  }
814
- function validateNestedKeys(keys, allowed, context) {
815
- for (const key of keys) {
816
- if (!allowed.has(key)) {
846
+
847
+ // src/runtime/query-builder-where.ts
848
+ var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
849
+ var STRING_MODE_OPS = /* @__PURE__ */ new Set(["contains", "startsWith", "endsWith", "equals"]);
850
+ function safeStringify(v) {
851
+ if (typeof v === "bigint")
852
+ return `${v}n`;
853
+ try {
854
+ return JSON.stringify(v);
855
+ } catch {
856
+ return String(v);
857
+ }
858
+ }
859
+ function forcedValuesEqual(a, b) {
860
+ if (a === b)
861
+ return true;
862
+ if (a === null || b === null)
863
+ return false;
864
+ if (typeof a !== typeof b)
865
+ return false;
866
+ if (typeof a === "bigint")
867
+ return a === b;
868
+ if (a instanceof Date && b instanceof Date)
869
+ return a.getTime() === b.getTime();
870
+ if (a instanceof RegExp && b instanceof RegExp) {
871
+ return a.source === b.source && a.flags === b.flags;
872
+ }
873
+ if (typeof a !== "object")
874
+ return false;
875
+ if (Array.isArray(a)) {
876
+ if (!Array.isArray(b))
877
+ return false;
878
+ if (a.length !== b.length)
879
+ return false;
880
+ return a.every((v, i) => forcedValuesEqual(v, b[i]));
881
+ }
882
+ if (!isPlainObject(a) || !isPlainObject(b))
883
+ return false;
884
+ const aKeys = Object.keys(a);
885
+ const bKeys = Object.keys(b);
886
+ if (aKeys.length !== bKeys.length)
887
+ return false;
888
+ return aKeys.every((k) => k in b && forcedValuesEqual(a[k], b[k]));
889
+ }
890
+ function mergeScalarConditions(target, source) {
891
+ for (const [field, ops] of Object.entries(source)) {
892
+ const existing = target[field];
893
+ if (existing === void 0) {
894
+ target[field] = ops;
895
+ continue;
896
+ }
897
+ if (field === "NOT") {
898
+ const existingArr = Array.isArray(existing) ? existing : [existing];
899
+ const sourceArr = Array.isArray(ops) ? ops : [ops];
900
+ target[field] = [...existingArr, ...sourceArr];
901
+ continue;
902
+ }
903
+ if (isPlainObject(existing) && isPlainObject(ops)) {
904
+ for (const [op, val] of Object.entries(ops)) {
905
+ if (op in existing) {
906
+ const existingVal = existing[op];
907
+ if (!forcedValuesEqual(existingVal, val)) {
908
+ throw new ShapeError(
909
+ `Conflicting forced where values for "${field}.${op}": shape defines both ${safeStringify(existingVal)} and ${safeStringify(val)}`
910
+ );
911
+ }
912
+ }
913
+ }
914
+ Object.assign(existing, ops);
915
+ continue;
916
+ }
917
+ if (!forcedValuesEqual(existing, ops)) {
817
918
  throw new ShapeError(
818
- `Unknown key "${key}" in ${context}. Allowed: ${[...allowed].join(", ")}`
919
+ `Conflicting forced where values for "${field}"`
819
920
  );
820
921
  }
821
922
  }
822
923
  }
823
- function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
824
- function isShapeConfig(obj) {
825
- if (!isPlainObject(obj))
826
- return false;
827
- const keys = Object.keys(obj);
828
- return keys.length === 0 || keys.every((k) => SHAPE_CONFIG_KEYS.has(k));
924
+ function mergeRelationForcedMaps(target, source) {
925
+ for (const [relName, ops] of Object.entries(source)) {
926
+ if (!target[relName]) {
927
+ target[relName] = ops;
928
+ continue;
929
+ }
930
+ for (const [op, forced] of Object.entries(ops)) {
931
+ if (!target[relName][op]) {
932
+ target[relName][op] = forced;
933
+ } else {
934
+ mergeScalarConditions(target[relName][op].conditions, forced.conditions);
935
+ mergeRelationForcedMaps(target[relName][op].relations, forced.relations);
936
+ }
937
+ }
829
938
  }
939
+ }
940
+ function createWhereBuilder(typeMap, enumMap) {
830
941
  function buildWhereSchema(model, whereConfig) {
831
942
  const modelFields = typeMap[model];
832
943
  if (!modelFields)
833
944
  throw new ShapeError(`Unknown model: ${model}`);
834
945
  const fieldSchemas = {};
835
- const forced = {};
836
- for (const [fieldName, operators] of Object.entries(whereConfig)) {
837
- const fieldMeta = modelFields[fieldName];
838
- if (!fieldMeta)
839
- throw new ShapeError(
840
- `Unknown field "${fieldName}" on model "${model}"`
946
+ const scalarConditions = {};
947
+ const relationForced = {};
948
+ for (const [key, value] of Object.entries(whereConfig)) {
949
+ if (COMBINATOR_KEYS.has(key)) {
950
+ processCombinator(
951
+ key,
952
+ value,
953
+ model,
954
+ fieldSchemas,
955
+ scalarConditions,
956
+ relationForced
841
957
  );
842
- if (fieldMeta.isRelation)
843
- throw new ShapeError(
844
- `Relation field "${fieldName}" cannot be used in where`
958
+ continue;
959
+ }
960
+ const fieldMeta = modelFields[key];
961
+ if (!fieldMeta)
962
+ throw new ShapeError(`Unknown field "${key}" on model "${model}"`);
963
+ if (fieldMeta.isRelation) {
964
+ processRelationFilter(
965
+ key,
966
+ value,
967
+ fieldMeta,
968
+ fieldSchemas,
969
+ relationForced
845
970
  );
971
+ continue;
972
+ }
846
973
  if (UNSUPPORTED_WHERE_TYPES.has(fieldMeta.type) && !fieldMeta.isList) {
847
974
  throw new ShapeError(
848
- `${fieldMeta.type} field "${fieldName}" cannot be used in where filters`
975
+ `${fieldMeta.type} field "${key}" cannot be used in where filters`
849
976
  );
850
977
  }
851
- const opSchemas = {};
852
- const fieldForced = {};
853
- let hasClientOps = false;
854
- let hasStringModeOp = false;
855
- const clientOpKeys = [];
856
- for (const [op, value] of Object.entries(operators)) {
857
- if (value === true) {
858
- opSchemas[op] = createOperatorSchema(
859
- fieldMeta,
860
- op,
861
- enumMap
862
- ).optional();
863
- hasClientOps = true;
864
- clientOpKeys.push(op);
865
- if (fieldMeta.type === "String" && !fieldMeta.isList && STRING_MODE_OPS.has(op)) {
866
- hasStringModeOp = true;
867
- }
868
- } else {
869
- const opSchema = createOperatorSchema(fieldMeta, op, enumMap);
870
- let parsed;
871
- try {
872
- parsed = opSchema.parse(value);
873
- } catch (err) {
874
- throw new ShapeError(
875
- `Invalid forced value for "${model}.${fieldName}.${op}": ${err.message}`
876
- );
978
+ processScalarField(key, value, model, fieldMeta, fieldSchemas, scalarConditions);
979
+ }
980
+ const schema = Object.keys(fieldSchemas).length > 0 ? z4.object(fieldSchemas).strict().optional() : null;
981
+ return {
982
+ schema,
983
+ forced: {
984
+ conditions: scalarConditions,
985
+ relations: relationForced
986
+ }
987
+ };
988
+ }
989
+ function processCombinator(key, value, model, fieldSchemas, parentConditions, parentRelations) {
990
+ if (!isPlainObject(value)) {
991
+ throw new ShapeError(`"${key}" in where shape must be an object defining allowed fields`);
992
+ }
993
+ const result = buildWhereSchema(model, value);
994
+ if (result.schema) {
995
+ if (key === "NOT") {
996
+ fieldSchemas[key] = z4.union([result.schema, z4.array(result.schema)]).optional();
997
+ } else {
998
+ fieldSchemas[key] = z4.array(result.schema).optional();
999
+ }
1000
+ }
1001
+ if (hasWhereForced(result.forced)) {
1002
+ if (key === "AND" || key === "OR") {
1003
+ mergeScalarConditions(parentConditions, result.forced.conditions);
1004
+ mergeRelationForcedMaps(parentRelations, result.forced.relations);
1005
+ } else {
1006
+ const notWhere = mergeWhereForced(void 0, result.forced);
1007
+ if (Object.keys(notWhere).length > 0) {
1008
+ const existing = parentConditions[key];
1009
+ if (existing) {
1010
+ parentConditions[key] = Array.isArray(existing) ? [...existing, notWhere] : [existing, notWhere];
1011
+ } else {
1012
+ parentConditions[key] = notWhere;
877
1013
  }
878
- fieldForced[op] = parsed;
879
1014
  }
880
1015
  }
881
- if (!hasClientOps && Object.keys(fieldForced).length === 0) {
1016
+ }
1017
+ }
1018
+ function processRelationFilter(key, value, fieldMeta, fieldSchemas, parentRelations) {
1019
+ if (!isPlainObject(value)) {
1020
+ throw new ShapeError(`Relation filter for "${key}" must be an object with operators (some, every, none, is, isNot)`);
1021
+ }
1022
+ const allowedOps = fieldMeta.isList ? TO_MANY_RELATION_OPS : TO_ONE_RELATION_OPS;
1023
+ const opSchemas = {};
1024
+ const opForced = {};
1025
+ let hasClientOps = false;
1026
+ for (const [op, opValue] of Object.entries(value)) {
1027
+ if (!allowedOps.has(op)) {
1028
+ const allowed = [...allowedOps].join(", ");
1029
+ throw new ShapeError(
1030
+ `Operator "${op}" not supported for ${fieldMeta.isList ? "to-many" : "to-one"} relation "${key}". Allowed: ${allowed}`
1031
+ );
1032
+ }
1033
+ if (!isPlainObject(opValue)) {
882
1034
  throw new ShapeError(
883
- `Empty operator config for where field "${fieldName}" on model "${model}". Define at least one operator.`
1035
+ `Relation filter operator "${op}" on "${key}" must be an object defining nested where fields`
884
1036
  );
885
1037
  }
886
- if (hasStringModeOp) {
887
- opSchemas["mode"] = z4.enum(["default", "insensitive"]).optional();
888
- }
889
- if (hasClientOps) {
890
- const opObj = z4.object(opSchemas).strict();
891
- fieldSchemas[fieldName] = opObj.refine(
892
- (v) => clientOpKeys.some(
893
- (k) => v[k] !== void 0
894
- ),
895
- {
896
- message: `At least one operator required for where field "${fieldName}"`
897
- }
898
- ).optional();
1038
+ const nested = buildWhereSchema(fieldMeta.type, opValue);
1039
+ if (nested.schema) {
1040
+ if (!hasWhereForced(nested.forced)) {
1041
+ opSchemas[op] = nested.schema.refine(
1042
+ (v) => v === void 0 || Object.keys(v).length > 0,
1043
+ { message: `Relation filter "${key}.${op}" requires at least one condition` }
1044
+ );
1045
+ } else {
1046
+ opSchemas[op] = nested.schema;
1047
+ }
1048
+ hasClientOps = true;
899
1049
  }
900
- if (Object.keys(fieldForced).length > 0) {
901
- forced[fieldName] = fieldForced;
1050
+ if (hasWhereForced(nested.forced)) {
1051
+ opForced[op] = nested.forced;
902
1052
  }
903
1053
  }
904
- const schema = Object.keys(fieldSchemas).length > 0 ? z4.object(fieldSchemas).strict().optional() : null;
905
- return { schema, forced };
1054
+ if (hasClientOps) {
1055
+ const clientOpKeys = Object.keys(opSchemas);
1056
+ const opObjSchema = z4.object(opSchemas).strict();
1057
+ if (Object.keys(opForced).length === 0) {
1058
+ fieldSchemas[key] = opObjSchema.refine(
1059
+ (v) => clientOpKeys.some((k) => v[k] !== void 0),
1060
+ { message: `At least one relation operator required for "${key}"` }
1061
+ ).optional();
1062
+ } else {
1063
+ fieldSchemas[key] = opObjSchema.optional();
1064
+ }
1065
+ }
1066
+ if (Object.keys(opForced).length > 0) {
1067
+ parentRelations[key] = opForced;
1068
+ }
906
1069
  }
907
- function buildCountFieldSchema(model, config, context) {
908
- if (config === true) {
909
- return z4.literal(true).optional();
1070
+ function processScalarField(fieldName, operators, model, fieldMeta, fieldSchemas, scalarConditions) {
1071
+ if (!isPlainObject(operators)) {
1072
+ throw new ShapeError(
1073
+ `Where config for scalar field "${fieldName}" on model "${model}" must be an object of operators`
1074
+ );
910
1075
  }
911
- const modelFields = typeMap[model];
912
- if (!modelFields)
913
- throw new ShapeError(`Unknown model: ${model}`);
914
- const fieldSchemas = {};
915
- for (const fieldName of Object.keys(config)) {
916
- if (fieldName !== "_all") {
917
- const fieldMeta = modelFields[fieldName];
918
- if (!fieldMeta)
919
- throw new ShapeError(
920
- `Unknown field "${fieldName}" on model "${model}" in ${context}`
921
- );
922
- if (fieldMeta.isRelation)
1076
+ const opSchemas = {};
1077
+ const fieldForced = {};
1078
+ let hasClientOps = false;
1079
+ let hasStringModeOp = false;
1080
+ const clientOpKeys = [];
1081
+ for (const [op, opValue] of Object.entries(operators)) {
1082
+ if (opValue === true) {
1083
+ opSchemas[op] = createOperatorSchema(fieldMeta, op, enumMap).optional();
1084
+ hasClientOps = true;
1085
+ clientOpKeys.push(op);
1086
+ if (fieldMeta.type === "String" && !fieldMeta.isList && STRING_MODE_OPS.has(op)) {
1087
+ hasStringModeOp = true;
1088
+ }
1089
+ } else {
1090
+ const opSchema = createOperatorSchema(fieldMeta, op, enumMap);
1091
+ let parsed;
1092
+ try {
1093
+ parsed = opSchema.parse(opValue);
1094
+ } catch (err) {
923
1095
  throw new ShapeError(
924
- `Relation field "${fieldName}" cannot be used in ${context}`
1096
+ `Invalid forced value for "${model}.${fieldName}.${op}": ${err.message}`
925
1097
  );
1098
+ }
1099
+ fieldForced[op] = parsed;
926
1100
  }
927
- fieldSchemas[fieldName] = z4.literal(true).optional();
928
1101
  }
929
- return z4.object(fieldSchemas).strict().optional();
1102
+ if (!hasClientOps && Object.keys(fieldForced).length === 0) {
1103
+ throw new ShapeError(
1104
+ `Empty operator config for where field "${fieldName}" on model "${model}". Define at least one operator.`
1105
+ );
1106
+ }
1107
+ if (hasStringModeOp) {
1108
+ opSchemas["mode"] = z4.enum(["default", "insensitive"]).optional();
1109
+ }
1110
+ if (hasClientOps) {
1111
+ const opObj = z4.object(opSchemas).strict();
1112
+ fieldSchemas[fieldName] = opObj.refine(
1113
+ (v) => clientOpKeys.some((k) => v[k] !== void 0),
1114
+ { message: `At least one operator required for where field "${fieldName}"` }
1115
+ ).optional();
1116
+ }
1117
+ if (Object.keys(fieldForced).length > 0) {
1118
+ scalarConditions[fieldName] = fieldForced;
1119
+ }
930
1120
  }
931
- function buildIncludeCountSchema(model, config) {
1121
+ return { buildWhereSchema };
1122
+ }
1123
+
1124
+ // src/runtime/query-builder-args.ts
1125
+ import { z as z5 } from "zod";
1126
+ var UNSUPPORTED_BY_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
1127
+ function createArgsBuilder(typeMap, enumMap, uniqueMap) {
1128
+ function buildOrderBySchema(model, orderByConfig) {
932
1129
  const modelFields = typeMap[model];
933
1130
  if (!modelFields)
934
1131
  throw new ShapeError(`Unknown model: ${model}`);
935
- if (config === true) {
936
- return { schema: z4.literal(true).optional(), forcedCountWhere: {} };
1132
+ const fieldSchemas = {};
1133
+ for (const fieldName of Object.keys(orderByConfig)) {
1134
+ const fieldMeta = modelFields[fieldName];
1135
+ if (!fieldMeta)
1136
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
1137
+ if (fieldMeta.isRelation)
1138
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in orderBy`);
1139
+ if (fieldMeta.type === "Json")
1140
+ throw new ShapeError(`Json field "${fieldName}" cannot be used in orderBy`);
1141
+ if (fieldMeta.isList)
1142
+ throw new ShapeError(`List field "${fieldName}" cannot be used in orderBy`);
1143
+ fieldSchemas[fieldName] = z5.enum(["asc", "desc"]).optional();
937
1144
  }
938
- if (!isPlainObject(config) || !("select" in config)) {
939
- throw new ShapeError(
940
- `Invalid _count config on model "${model}". Expected true or { select: { ... } }`
941
- );
1145
+ const fieldKeys = Object.keys(fieldSchemas);
1146
+ const singleSchema = z5.object(fieldSchemas).strict().refine(
1147
+ (v) => fieldKeys.some((k) => v[k] !== void 0),
1148
+ { message: "orderBy must specify at least one field" }
1149
+ );
1150
+ return z5.union([singleSchema, z5.array(singleSchema).min(1)]).optional();
1151
+ }
1152
+ function buildTakeSchema(config) {
1153
+ if (!Number.isFinite(config.max) || !Number.isInteger(config.max)) {
1154
+ throw new ShapeError(`take max must be a finite integer, got ${config.max}`);
942
1155
  }
943
- for (const key of Object.keys(config)) {
944
- if (key !== "select") {
945
- throw new ShapeError(
946
- `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
947
- );
948
- }
1156
+ if (config.max < 1) {
1157
+ throw new ShapeError(`take max must be at least 1, got ${config.max}`);
949
1158
  }
950
- const selectObj = config.select;
951
- const countSelectFields = {};
952
- const forcedCountWhere = {};
953
- for (const [fieldName, fieldConfig] of Object.entries(selectObj)) {
954
- const fieldMeta = modelFields[fieldName];
955
- if (!fieldMeta)
956
- throw new ShapeError(
957
- `Unknown field "${fieldName}" on model "${model}" in _count.select`
958
- );
959
- if (!fieldMeta.isRelation)
960
- throw new ShapeError(
961
- `Field "${fieldName}" is not a relation on model "${model}" in _count.select`
962
- );
963
- if (fieldConfig === true) {
964
- countSelectFields[fieldName] = z4.literal(true).optional();
965
- } else if (isPlainObject(fieldConfig)) {
966
- validateNestedKeys(
967
- Object.keys(fieldConfig),
968
- KNOWN_COUNT_SELECT_ENTRY_KEYS,
969
- `_count.select.${fieldName} on model "${model}"`
970
- );
971
- if (fieldConfig.where) {
972
- const relatedType = fieldMeta.type;
973
- const { schema: whereSchema, forced } = buildWhereSchema(
974
- relatedType,
975
- fieldConfig.where
976
- );
977
- const nestedSchemas = {};
978
- if (whereSchema)
979
- nestedSchemas["where"] = whereSchema;
980
- const nestedObj = z4.object(nestedSchemas).strict();
981
- countSelectFields[fieldName] = z4.union([z4.literal(true), nestedObj]).optional();
982
- if (Object.keys(forced).length > 0) {
983
- forcedCountWhere[fieldName] = forced;
984
- }
985
- } else {
986
- countSelectFields[fieldName] = z4.literal(true).optional();
987
- }
988
- } else {
1159
+ if (config.default !== void 0) {
1160
+ if (!Number.isFinite(config.default) || !Number.isInteger(config.default)) {
1161
+ throw new ShapeError(`take default must be a finite integer, got ${config.default}`);
1162
+ }
1163
+ if (config.default < 1) {
1164
+ throw new ShapeError(`take default must be at least 1, got ${config.default}`);
1165
+ }
1166
+ if (config.default > config.max) {
1167
+ throw new ShapeError("take default cannot exceed max");
1168
+ }
1169
+ return z5.number().int().min(1).max(config.max).default(config.default);
1170
+ }
1171
+ return z5.number().int().min(1).max(config.max).optional();
1172
+ }
1173
+ function buildCursorSchema(model, cursorConfig) {
1174
+ const modelFields = typeMap[model];
1175
+ if (!modelFields)
1176
+ throw new ShapeError(`Unknown model: ${model}`);
1177
+ const cursorFields = new Set(Object.keys(cursorConfig));
1178
+ const constraints = uniqueMap[model];
1179
+ if (constraints && constraints.length > 0) {
1180
+ const covered = constraints.some(
1181
+ (constraint) => constraint.every((field) => cursorFields.has(field))
1182
+ );
1183
+ if (!covered) {
1184
+ const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
989
1185
  throw new ShapeError(
990
- `Invalid config for _count.select.${fieldName} on model "${model}". Expected true or { where: { ... } }`
1186
+ `cursor on model "${model}" must cover a unique constraint: ${constraintDesc}`
991
1187
  );
992
1188
  }
993
1189
  }
994
- const selectSchema = z4.object(countSelectFields).strict();
995
- return {
996
- schema: z4.object({ select: selectSchema }).strict().optional(),
997
- forcedCountWhere
998
- };
1190
+ const fieldSchemas = {};
1191
+ for (const fieldName of Object.keys(cursorConfig)) {
1192
+ const fieldMeta = modelFields[fieldName];
1193
+ if (!fieldMeta)
1194
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in cursor`);
1195
+ if (fieldMeta.isRelation)
1196
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in cursor`);
1197
+ if (fieldMeta.isList)
1198
+ throw new ShapeError(`List field "${fieldName}" cannot be used in cursor`);
1199
+ fieldSchemas[fieldName] = createBaseType(fieldMeta, enumMap);
1200
+ }
1201
+ return z5.object(fieldSchemas).strict().optional();
1202
+ }
1203
+ function buildDistinctSchema(model, distinctConfig) {
1204
+ if (distinctConfig.length === 0) {
1205
+ throw new ShapeError("distinct must contain at least one field");
1206
+ }
1207
+ const modelFields = typeMap[model];
1208
+ if (!modelFields)
1209
+ throw new ShapeError(`Unknown model: ${model}`);
1210
+ for (const fieldName of distinctConfig) {
1211
+ const fieldMeta = modelFields[fieldName];
1212
+ if (!fieldMeta)
1213
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in distinct`);
1214
+ if (fieldMeta.isRelation)
1215
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in distinct`);
1216
+ if (fieldMeta.isList)
1217
+ throw new ShapeError(`List field "${fieldName}" cannot be used in distinct`);
1218
+ }
1219
+ const enumSchema = z5.enum(distinctConfig);
1220
+ return z5.union([enumSchema, z5.array(enumSchema).min(1)]).optional();
1221
+ }
1222
+ function buildBySchema(model, byConfig) {
1223
+ if (byConfig.length === 0) {
1224
+ throw new ShapeError('groupBy "by" must contain at least one field');
1225
+ }
1226
+ const modelFields = typeMap[model];
1227
+ if (!modelFields)
1228
+ throw new ShapeError(`Unknown model: ${model}`);
1229
+ for (const fieldName of byConfig) {
1230
+ const fieldMeta = modelFields[fieldName];
1231
+ if (!fieldMeta)
1232
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in by`);
1233
+ if (fieldMeta.isRelation)
1234
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in by`);
1235
+ if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
1236
+ throw new ShapeError(`${fieldMeta.type} field "${fieldName}" cannot be used in by`);
1237
+ }
1238
+ if (fieldMeta.isList)
1239
+ throw new ShapeError(`List field "${fieldName}" cannot be used in by`);
1240
+ }
1241
+ const enumSchema = z5.enum(byConfig);
1242
+ return z5.union([enumSchema, z5.array(enumSchema).min(1)]);
1243
+ }
1244
+ function buildHavingSchema(model, havingConfig) {
1245
+ const modelFields = typeMap[model];
1246
+ if (!modelFields)
1247
+ throw new ShapeError(`Unknown model: ${model}`);
1248
+ const fieldSchemas = {};
1249
+ for (const fieldName of Object.keys(havingConfig)) {
1250
+ const fieldMeta = modelFields[fieldName];
1251
+ if (!fieldMeta)
1252
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in having`);
1253
+ if (fieldMeta.isRelation)
1254
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in having`);
1255
+ if (fieldMeta.isList)
1256
+ throw new ShapeError(`List field "${fieldName}" cannot be used in having`);
1257
+ const ops = getSupportedOperators(fieldMeta);
1258
+ if (ops.length === 0) {
1259
+ throw new ShapeError(`${fieldMeta.type} field "${fieldName}" cannot be used in having filters`);
1260
+ }
1261
+ const opSchemas = {};
1262
+ const opKeys = [];
1263
+ for (const op of ops) {
1264
+ opSchemas[op] = createOperatorSchema(fieldMeta, op, enumMap).optional();
1265
+ opKeys.push(op);
1266
+ }
1267
+ if (fieldMeta.type === "String" && !fieldMeta.isList) {
1268
+ opSchemas["mode"] = z5.enum(["default", "insensitive"]).optional();
1269
+ }
1270
+ fieldSchemas[fieldName] = z5.object(opSchemas).strict().refine(
1271
+ (v) => opKeys.some((k) => v[k] !== void 0),
1272
+ { message: `At least one operator required for having field "${fieldName}"` }
1273
+ ).optional();
1274
+ }
1275
+ const havingFieldKeys = Object.keys(fieldSchemas);
1276
+ return z5.object(fieldSchemas).strict().refine(
1277
+ (v) => havingFieldKeys.some((k) => v[k] !== void 0),
1278
+ { message: "having must specify at least one field" }
1279
+ ).optional();
999
1280
  }
1000
1281
  function buildAggregateFieldSchema(model, opName, fieldConfig) {
1001
1282
  const modelFields = typeMap[model];
@@ -1006,18 +1287,14 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1006
1287
  const fieldSchemas = {};
1007
1288
  for (const fieldName of Object.keys(fieldConfig)) {
1008
1289
  if (fieldName === "_all" && opName === "_count") {
1009
- fieldSchemas[fieldName] = z4.literal(true).optional();
1290
+ fieldSchemas[fieldName] = z5.literal(true).optional();
1010
1291
  continue;
1011
1292
  }
1012
1293
  const fieldMeta = modelFields[fieldName];
1013
1294
  if (!fieldMeta)
1014
- throw new ShapeError(
1015
- `Unknown field "${fieldName}" on model "${model}" in ${opName}`
1016
- );
1295
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in ${opName}`);
1017
1296
  if (fieldMeta.isRelation)
1018
- throw new ShapeError(
1019
- `Relation field "${fieldName}" cannot be used in ${opName}`
1020
- );
1297
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in ${opName}`);
1021
1298
  if (isNumericOnly && !NUMERIC_TYPES.has(fieldMeta.type)) {
1022
1299
  throw new ShapeError(
1023
1300
  `Field "${fieldName}" (${fieldMeta.type}) cannot be used in ${opName}. Only numeric types (Int, Float, Decimal, BigInt) are supported.`
@@ -1028,96 +1305,180 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1028
1305
  `Field "${fieldName}" (${fieldMeta.type}) cannot be used in ${opName}. Only comparable types (Int, Float, Decimal, BigInt, String, DateTime) are supported.`
1029
1306
  );
1030
1307
  }
1031
- fieldSchemas[fieldName] = z4.literal(true).optional();
1308
+ fieldSchemas[fieldName] = z5.literal(true).optional();
1032
1309
  }
1033
- return z4.object(fieldSchemas).strict().optional();
1310
+ const aggFieldKeys = Object.keys(fieldSchemas);
1311
+ return z5.object(fieldSchemas).strict().refine(
1312
+ (v) => aggFieldKeys.some((k) => v[k] !== void 0),
1313
+ { message: `${opName} must specify at least one field` }
1314
+ ).optional();
1034
1315
  }
1035
- function buildBySchema(model, byConfig) {
1036
- if (byConfig.length === 0) {
1037
- throw new ShapeError('groupBy "by" must contain at least one field');
1316
+ function buildCountFieldSchema(model, config, context) {
1317
+ if (config === true) {
1318
+ return z5.literal(true).optional();
1038
1319
  }
1039
1320
  const modelFields = typeMap[model];
1040
1321
  if (!modelFields)
1041
1322
  throw new ShapeError(`Unknown model: ${model}`);
1042
- for (const fieldName of byConfig) {
1043
- const fieldMeta = modelFields[fieldName];
1044
- if (!fieldMeta)
1045
- throw new ShapeError(
1046
- `Unknown field "${fieldName}" on model "${model}" in by`
1047
- );
1048
- if (fieldMeta.isRelation)
1049
- throw new ShapeError(
1050
- `Relation field "${fieldName}" cannot be used in by`
1051
- );
1052
- if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
1053
- throw new ShapeError(
1054
- `${fieldMeta.type} field "${fieldName}" cannot be used in by`
1055
- );
1056
- }
1057
- if (fieldMeta.isList) {
1058
- throw new ShapeError(`List field "${fieldName}" cannot be used in by`);
1323
+ const fieldSchemas = {};
1324
+ for (const fieldName of Object.keys(config)) {
1325
+ if (fieldName !== "_all") {
1326
+ const fieldMeta = modelFields[fieldName];
1327
+ if (!fieldMeta)
1328
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in ${context}`);
1329
+ if (fieldMeta.isRelation)
1330
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in ${context}`);
1059
1331
  }
1332
+ fieldSchemas[fieldName] = z5.literal(true).optional();
1060
1333
  }
1061
- const enumSchema = z4.enum(byConfig);
1062
- return z4.union([enumSchema, z4.array(enumSchema).min(1)]);
1334
+ const countFieldKeys = Object.keys(fieldSchemas);
1335
+ return z5.object(fieldSchemas).strict().refine(
1336
+ (v) => countFieldKeys.some((k) => v[k] !== void 0),
1337
+ { message: `${context} must specify at least one field` }
1338
+ ).optional();
1063
1339
  }
1064
- function buildCursorSchema(model, cursorConfig) {
1340
+ function buildCountSelectSchema(model, selectConfig) {
1065
1341
  const modelFields = typeMap[model];
1066
1342
  if (!modelFields)
1067
1343
  throw new ShapeError(`Unknown model: ${model}`);
1068
- const cursorFields = new Set(Object.keys(cursorConfig));
1069
- const constraints = uniqueMap[model];
1070
- if (constraints && constraints.length > 0) {
1071
- const covered = constraints.some(
1072
- (constraint) => constraint.every((field) => cursorFields.has(field))
1073
- );
1074
- if (!covered) {
1075
- const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
1076
- throw new ShapeError(
1077
- `cursor on model "${model}" must cover a unique constraint: ${constraintDesc}`
1078
- );
1079
- }
1080
- }
1081
1344
  const fieldSchemas = {};
1082
- for (const fieldName of Object.keys(cursorConfig)) {
1345
+ for (const fieldName of Object.keys(selectConfig)) {
1346
+ if (fieldName === "_all") {
1347
+ fieldSchemas["_all"] = z5.literal(true).optional();
1348
+ continue;
1349
+ }
1083
1350
  const fieldMeta = modelFields[fieldName];
1084
1351
  if (!fieldMeta)
1085
- throw new ShapeError(
1086
- `Unknown field "${fieldName}" on model "${model}" in cursor`
1087
- );
1352
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in count select`);
1088
1353
  if (fieldMeta.isRelation)
1089
- throw new ShapeError(
1090
- `Relation field "${fieldName}" cannot be used in cursor`
1091
- );
1092
- if (fieldMeta.isList)
1093
- throw new ShapeError(
1094
- `List field "${fieldName}" cannot be used in cursor`
1095
- );
1096
- fieldSchemas[fieldName] = createBaseType(fieldMeta, enumMap);
1354
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in count select`);
1355
+ fieldSchemas[fieldName] = z5.literal(true).optional();
1097
1356
  }
1098
- return z4.object(fieldSchemas).strict().optional();
1357
+ const countSelectKeys = Object.keys(fieldSchemas);
1358
+ return z5.object(fieldSchemas).strict().refine(
1359
+ (v) => countSelectKeys.some((k) => v[k] !== void 0),
1360
+ { message: "count select must specify at least one field" }
1361
+ ).optional();
1099
1362
  }
1100
- function buildDistinctSchema(model, distinctConfig) {
1363
+ return {
1364
+ buildOrderBySchema,
1365
+ buildTakeSchema,
1366
+ buildCursorSchema,
1367
+ buildDistinctSchema,
1368
+ buildBySchema,
1369
+ buildHavingSchema,
1370
+ buildAggregateFieldSchema,
1371
+ buildCountFieldSchema,
1372
+ buildCountSelectSchema
1373
+ };
1374
+ }
1375
+
1376
+ // src/runtime/query-builder-projection.ts
1377
+ import { z as z6 } from "zod";
1378
+ var KNOWN_NESTED_INCLUDE_KEYS = /* @__PURE__ */ new Set([
1379
+ "where",
1380
+ "include",
1381
+ "select",
1382
+ "orderBy",
1383
+ "cursor",
1384
+ "take",
1385
+ "skip"
1386
+ ]);
1387
+ var KNOWN_NESTED_SELECT_KEYS = /* @__PURE__ */ new Set([
1388
+ "select",
1389
+ "where",
1390
+ "orderBy",
1391
+ "cursor",
1392
+ "take",
1393
+ "skip"
1394
+ ]);
1395
+ var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
1396
+ function validateNestedKeys(keys, allowed, context) {
1397
+ for (const key of keys) {
1398
+ if (!allowed.has(key)) {
1399
+ throw new ShapeError(
1400
+ `Unknown key "${key}" in ${context}. Allowed: ${[...allowed].join(", ")}`
1401
+ );
1402
+ }
1403
+ }
1404
+ }
1405
+ function createProjectionBuilder(typeMap, enumMap, deps) {
1406
+ function buildIncludeCountSchema(model, config) {
1101
1407
  const modelFields = typeMap[model];
1102
1408
  if (!modelFields)
1103
1409
  throw new ShapeError(`Unknown model: ${model}`);
1104
- for (const fieldName of distinctConfig) {
1105
- const fieldMeta = modelFields[fieldName];
1106
- if (!fieldMeta)
1410
+ if (config === true) {
1411
+ return { schema: z6.literal(true).optional(), forcedCountWhere: {} };
1412
+ }
1413
+ if (!isPlainObject(config) || !("select" in config)) {
1414
+ throw new ShapeError(
1415
+ `Invalid _count config on model "${model}". Expected true or { select: { ... } }`
1416
+ );
1417
+ }
1418
+ for (const key of Object.keys(config)) {
1419
+ if (key !== "select") {
1107
1420
  throw new ShapeError(
1108
- `Unknown field "${fieldName}" on model "${model}" in distinct`
1421
+ `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
1109
1422
  );
1110
- if (fieldMeta.isRelation)
1111
- throw new ShapeError(
1112
- `Relation field "${fieldName}" cannot be used in distinct`
1423
+ }
1424
+ }
1425
+ if (!isPlainObject(config.select)) {
1426
+ throw new ShapeError(
1427
+ `Invalid _count.select on model "${model}". Expected a plain object with relation field keys.`
1428
+ );
1429
+ }
1430
+ const selectObj = config.select;
1431
+ if (Object.keys(selectObj).length === 0) {
1432
+ throw new ShapeError(
1433
+ `Empty _count.select on model "${model}". Define at least one relation field.`
1434
+ );
1435
+ }
1436
+ const countSelectFields = {};
1437
+ const forcedCountWhere = {};
1438
+ for (const [fieldName, fieldConfig] of Object.entries(selectObj)) {
1439
+ const fieldMeta = modelFields[fieldName];
1440
+ if (!fieldMeta)
1441
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in _count.select`);
1442
+ if (!fieldMeta.isRelation)
1443
+ throw new ShapeError(`Field "${fieldName}" is not a relation on model "${model}" in _count.select`);
1444
+ if (!fieldMeta.isList)
1445
+ throw new ShapeError(`Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`);
1446
+ if (fieldConfig === true) {
1447
+ countSelectFields[fieldName] = z6.literal(true).optional();
1448
+ } else if (isPlainObject(fieldConfig)) {
1449
+ validateNestedKeys(
1450
+ Object.keys(fieldConfig),
1451
+ KNOWN_COUNT_SELECT_ENTRY_KEYS,
1452
+ `_count.select.${fieldName} on model "${model}"`
1113
1453
  );
1114
- if (fieldMeta.isList)
1454
+ if (fieldConfig.where) {
1455
+ const relatedType = fieldMeta.type;
1456
+ const { schema: whereSchema, forced } = deps.buildWhereSchema(
1457
+ relatedType,
1458
+ fieldConfig.where
1459
+ );
1460
+ const nestedSchemas = {};
1461
+ if (whereSchema)
1462
+ nestedSchemas["where"] = whereSchema;
1463
+ const nestedObj = z6.object(nestedSchemas).strict();
1464
+ countSelectFields[fieldName] = z6.union([z6.literal(true), nestedObj]).optional();
1465
+ if (hasWhereForced(forced)) {
1466
+ forcedCountWhere[fieldName] = forced;
1467
+ }
1468
+ } else {
1469
+ countSelectFields[fieldName] = z6.literal(true).optional();
1470
+ }
1471
+ } else {
1115
1472
  throw new ShapeError(
1116
- `List field "${fieldName}" cannot be used in distinct`
1473
+ `Invalid config for _count.select.${fieldName} on model "${model}". Expected true or { where: { ... } }`
1117
1474
  );
1475
+ }
1118
1476
  }
1119
- const enumSchema = z4.enum(distinctConfig);
1120
- return z4.union([enumSchema, z4.array(enumSchema).min(1)]).optional();
1477
+ const selectSchema = z6.object(countSelectFields).strict();
1478
+ return {
1479
+ schema: z6.object({ select: selectSchema }).strict().optional(),
1480
+ forcedCountWhere
1481
+ };
1121
1482
  }
1122
1483
  function buildIncludeSchema(model, includeConfig) {
1123
1484
  const modelFields = typeMap[model];
@@ -1128,10 +1489,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1128
1489
  let topLevelForcedCountWhere = {};
1129
1490
  for (const [relName, config] of Object.entries(includeConfig)) {
1130
1491
  if (relName === "_count") {
1131
- const countResult = buildIncludeCountSchema(
1132
- model,
1133
- config
1134
- );
1492
+ const countResult = buildIncludeCountSchema(model, config);
1135
1493
  fieldSchemas["_count"] = countResult.schema;
1136
1494
  topLevelForcedCountWhere = countResult.forcedCountWhere;
1137
1495
  continue;
@@ -1140,11 +1498,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1140
1498
  if (!fieldMeta)
1141
1499
  throw new ShapeError(`Unknown field "${relName}" on model "${model}"`);
1142
1500
  if (!fieldMeta.isRelation)
1143
- throw new ShapeError(
1144
- `Field "${relName}" is not a relation on model "${model}"`
1145
- );
1501
+ throw new ShapeError(`Field "${relName}" is not a relation on model "${model}"`);
1146
1502
  if (config === true) {
1147
- fieldSchemas[relName] = z4.literal(true).optional();
1503
+ fieldSchemas[relName] = z6.literal(true).optional();
1148
1504
  } else {
1149
1505
  validateNestedKeys(
1150
1506
  Object.keys(config),
@@ -1152,9 +1508,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1152
1508
  `nested include for "${relName}" on model "${model}"`
1153
1509
  );
1154
1510
  if (config.select && config.include) {
1155
- throw new ShapeError(
1156
- `Nested include for "${relName}" cannot define both "select" and "include".`
1157
- );
1511
+ throw new ShapeError(`Nested include for "${relName}" cannot define both "select" and "include".`);
1158
1512
  }
1159
1513
  if (!fieldMeta.isList) {
1160
1514
  if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
@@ -1166,13 +1520,13 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1166
1520
  const nestedSchemas = {};
1167
1521
  const relForced = {};
1168
1522
  if (config.where) {
1169
- const { schema: whereSchema, forced } = buildWhereSchema(
1523
+ const { schema: whereSchema, forced } = deps.buildWhereSchema(
1170
1524
  fieldMeta.type,
1171
1525
  config.where
1172
1526
  );
1173
1527
  if (whereSchema)
1174
1528
  nestedSchemas["where"] = whereSchema;
1175
- if (Object.keys(forced).length > 0)
1529
+ if (hasWhereForced(forced))
1176
1530
  relForced.where = forced;
1177
1531
  }
1178
1532
  if (config.include) {
@@ -1192,31 +1546,25 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1192
1546
  relForced._countWhere = nested.forcedCountWhere;
1193
1547
  }
1194
1548
  if (config.orderBy) {
1195
- nestedSchemas["orderBy"] = buildOrderBySchema(
1196
- fieldMeta.type,
1197
- config.orderBy
1198
- );
1549
+ nestedSchemas["orderBy"] = deps.buildOrderBySchema(fieldMeta.type, config.orderBy);
1199
1550
  }
1200
1551
  if (config.cursor) {
1201
- nestedSchemas["cursor"] = buildCursorSchema(
1202
- fieldMeta.type,
1203
- config.cursor
1204
- );
1552
+ nestedSchemas["cursor"] = deps.buildCursorSchema(fieldMeta.type, config.cursor);
1205
1553
  }
1206
1554
  if (config.take) {
1207
- nestedSchemas["take"] = buildTakeSchema(config.take);
1555
+ nestedSchemas["take"] = deps.buildTakeSchema(config.take);
1208
1556
  }
1209
1557
  if (config.skip) {
1210
- nestedSchemas["skip"] = z4.number().int().min(0).optional();
1558
+ nestedSchemas["skip"] = z6.number().int().min(0).optional();
1211
1559
  }
1212
- const nestedObj = z4.object(nestedSchemas).strict();
1213
- fieldSchemas[relName] = z4.union([z4.literal(true), nestedObj]).optional();
1560
+ const nestedObj = z6.object(nestedSchemas).strict();
1561
+ fieldSchemas[relName] = z6.union([z6.literal(true), nestedObj]).optional();
1214
1562
  if (Object.keys(relForced).length > 0)
1215
1563
  forcedTree[relName] = relForced;
1216
1564
  }
1217
1565
  }
1218
1566
  return {
1219
- schema: z4.object(fieldSchemas).strict().optional(),
1567
+ schema: z6.object(fieldSchemas).strict().optional(),
1220
1568
  forcedTree,
1221
1569
  forcedCountWhere: topLevelForcedCountWhere
1222
1570
  };
@@ -1230,26 +1578,19 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1230
1578
  let topLevelForcedCountWhere = {};
1231
1579
  for (const [fieldName, config] of Object.entries(selectConfig)) {
1232
1580
  if (fieldName === "_count") {
1233
- const countResult = buildIncludeCountSchema(
1234
- model,
1235
- config
1236
- );
1581
+ const countResult = buildIncludeCountSchema(model, config);
1237
1582
  fieldSchemas["_count"] = countResult.schema;
1238
1583
  topLevelForcedCountWhere = countResult.forcedCountWhere;
1239
1584
  continue;
1240
1585
  }
1241
1586
  const fieldMeta = modelFields[fieldName];
1242
1587
  if (!fieldMeta)
1243
- throw new ShapeError(
1244
- `Unknown field "${fieldName}" on model "${model}"`
1245
- );
1588
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
1246
1589
  if (config === true) {
1247
- fieldSchemas[fieldName] = z4.literal(true).optional();
1590
+ fieldSchemas[fieldName] = z6.literal(true).optional();
1248
1591
  } else {
1249
1592
  if (!fieldMeta.isRelation) {
1250
- throw new ShapeError(
1251
- `Nested select args only valid for relations, not scalar "${fieldName}"`
1252
- );
1593
+ throw new ShapeError(`Nested select args only valid for relations, not scalar "${fieldName}" on model "${model}"`);
1253
1594
  }
1254
1595
  validateNestedKeys(
1255
1596
  Object.keys(config),
@@ -1274,200 +1615,98 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1274
1615
  relForced._countWhere = nested.forcedCountWhere;
1275
1616
  }
1276
1617
  if (config.where) {
1277
- const { schema: whereSchema, forced } = buildWhereSchema(
1618
+ const { schema: whereSchema, forced } = deps.buildWhereSchema(
1278
1619
  fieldMeta.type,
1279
1620
  config.where
1280
1621
  );
1281
1622
  if (whereSchema)
1282
1623
  nestedSchemas["where"] = whereSchema;
1283
- if (Object.keys(forced).length > 0)
1624
+ if (hasWhereForced(forced))
1284
1625
  relForced.where = forced;
1285
1626
  }
1286
1627
  if (config.orderBy) {
1287
- nestedSchemas["orderBy"] = buildOrderBySchema(
1288
- fieldMeta.type,
1289
- config.orderBy
1290
- );
1628
+ nestedSchemas["orderBy"] = deps.buildOrderBySchema(fieldMeta.type, config.orderBy);
1291
1629
  }
1292
1630
  if (config.cursor) {
1293
- nestedSchemas["cursor"] = buildCursorSchema(
1294
- fieldMeta.type,
1295
- config.cursor
1296
- );
1631
+ nestedSchemas["cursor"] = deps.buildCursorSchema(fieldMeta.type, config.cursor);
1297
1632
  }
1298
1633
  if (config.take) {
1299
- nestedSchemas["take"] = buildTakeSchema(config.take);
1634
+ nestedSchemas["take"] = deps.buildTakeSchema(config.take);
1300
1635
  }
1301
1636
  if (config.skip) {
1302
- nestedSchemas["skip"] = z4.number().int().min(0).optional();
1637
+ nestedSchemas["skip"] = z6.number().int().min(0).optional();
1303
1638
  }
1304
- const nestedObj = z4.object(nestedSchemas).strict();
1305
- fieldSchemas[fieldName] = z4.union([z4.literal(true), nestedObj]).optional();
1639
+ const nestedObj = z6.object(nestedSchemas).strict();
1640
+ fieldSchemas[fieldName] = z6.union([z6.literal(true), nestedObj]).optional();
1306
1641
  if (Object.keys(relForced).length > 0)
1307
1642
  forcedTree[fieldName] = relForced;
1308
1643
  }
1309
1644
  }
1310
1645
  return {
1311
- schema: z4.object(fieldSchemas).strict().optional(),
1646
+ schema: z6.object(fieldSchemas).strict().optional(),
1312
1647
  forcedTree,
1313
1648
  forcedCountWhere: topLevelForcedCountWhere
1314
1649
  };
1315
1650
  }
1316
- function buildOrderBySchema(model, orderByConfig) {
1317
- const modelFields = typeMap[model];
1318
- if (!modelFields)
1319
- throw new ShapeError(`Unknown model: ${model}`);
1320
- const fieldSchemas = {};
1321
- for (const fieldName of Object.keys(orderByConfig)) {
1322
- const fieldMeta = modelFields[fieldName];
1323
- if (!fieldMeta)
1324
- throw new ShapeError(
1325
- `Unknown field "${fieldName}" on model "${model}"`
1326
- );
1327
- if (fieldMeta.isRelation)
1328
- throw new ShapeError(
1329
- `Relation field "${fieldName}" cannot be used in orderBy`
1330
- );
1331
- if (fieldMeta.type === "Json")
1332
- throw new ShapeError(
1333
- `Json field "${fieldName}" cannot be used in orderBy`
1334
- );
1335
- if (fieldMeta.isList)
1336
- throw new ShapeError(
1337
- `List field "${fieldName}" cannot be used in orderBy`
1338
- );
1339
- fieldSchemas[fieldName] = z4.enum(["asc", "desc"]).optional();
1340
- }
1341
- const singleSchema = z4.object(fieldSchemas).strict();
1342
- return z4.union([singleSchema, z4.array(singleSchema)]).optional();
1343
- }
1344
- function buildTakeSchema(config) {
1345
- if (!Number.isFinite(config.max) || !Number.isInteger(config.max)) {
1346
- throw new ShapeError(
1347
- `take max must be a finite integer, got ${config.max}`
1348
- );
1349
- }
1350
- if (config.max < 1) {
1351
- throw new ShapeError(`take max must be at least 1, got ${config.max}`);
1352
- }
1353
- if (config.default !== void 0) {
1354
- if (!Number.isFinite(config.default) || !Number.isInteger(config.default)) {
1355
- throw new ShapeError(
1356
- `take default must be a finite integer, got ${config.default}`
1357
- );
1358
- }
1359
- if (config.default < 1) {
1360
- throw new ShapeError(
1361
- `take default must be at least 1, got ${config.default}`
1362
- );
1363
- }
1364
- if (config.default > config.max) {
1365
- throw new ShapeError("take default cannot exceed max");
1366
- }
1367
- return z4.number().int().min(1).max(config.max).default(config.default);
1368
- }
1369
- return z4.number().int().min(1).max(config.max).optional();
1370
- }
1371
- function buildHavingSchema(model, havingConfig) {
1372
- const modelFields = typeMap[model];
1373
- if (!modelFields)
1374
- throw new ShapeError(`Unknown model: ${model}`);
1375
- const fieldSchemas = {};
1376
- for (const fieldName of Object.keys(havingConfig)) {
1377
- const fieldMeta = modelFields[fieldName];
1378
- if (!fieldMeta)
1379
- throw new ShapeError(
1380
- `Unknown field "${fieldName}" on model "${model}" in having`
1381
- );
1382
- if (fieldMeta.isRelation)
1383
- throw new ShapeError(
1384
- `Relation field "${fieldName}" cannot be used in having`
1385
- );
1386
- if (fieldMeta.isList)
1387
- throw new ShapeError(
1388
- `List field "${fieldName}" cannot be used in having`
1389
- );
1390
- const ops = getSupportedOperators(fieldMeta);
1391
- if (ops.length === 0) {
1392
- throw new ShapeError(
1393
- `${fieldMeta.type} field "${fieldName}" cannot be used in having filters`
1394
- );
1395
- }
1396
- const opSchemas = {};
1397
- const opKeys = [];
1398
- for (const op of ops) {
1399
- opSchemas[op] = createOperatorSchema(fieldMeta, op, enumMap).optional();
1400
- opKeys.push(op);
1401
- }
1402
- if (fieldMeta.type === "String" && !fieldMeta.isList) {
1403
- opSchemas["mode"] = z4.enum(["default", "insensitive"]).optional();
1404
- }
1405
- fieldSchemas[fieldName] = z4.object(opSchemas).strict().refine(
1406
- (v) => opKeys.some((k) => v[k] !== void 0),
1407
- {
1408
- message: `At least one operator required for having field "${fieldName}"`
1409
- }
1410
- ).optional();
1411
- }
1412
- return z4.object(fieldSchemas).strict().optional();
1413
- }
1414
- function buildCountSelectSchema(model, selectConfig) {
1415
- const modelFields = typeMap[model];
1416
- if (!modelFields)
1417
- throw new ShapeError(`Unknown model: ${model}`);
1418
- const fieldSchemas = {};
1419
- for (const fieldName of Object.keys(selectConfig)) {
1420
- if (fieldName === "_all") {
1421
- fieldSchemas["_all"] = z4.literal(true).optional();
1422
- continue;
1423
- }
1424
- const fieldMeta = modelFields[fieldName];
1425
- if (!fieldMeta)
1426
- throw new ShapeError(
1427
- `Unknown field "${fieldName}" on model "${model}" in count select`
1428
- );
1429
- if (fieldMeta.isRelation)
1430
- throw new ShapeError(
1431
- `Relation field "${fieldName}" cannot be used in count select`
1432
- );
1433
- fieldSchemas[fieldName] = z4.literal(true).optional();
1434
- }
1435
- return z4.object(fieldSchemas).strict().optional();
1651
+ return { buildIncludeSchema, buildSelectSchema, buildIncludeCountSchema };
1652
+ }
1653
+
1654
+ // src/runtime/query-builder.ts
1655
+ var METHOD_ALLOWED_ARGS = {
1656
+ findMany: /* @__PURE__ */ new Set(["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"]),
1657
+ findFirst: /* @__PURE__ */ new Set(["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"]),
1658
+ findFirstOrThrow: /* @__PURE__ */ new Set(["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"]),
1659
+ findUnique: /* @__PURE__ */ new Set(["where", "include", "select"]),
1660
+ findUniqueOrThrow: /* @__PURE__ */ new Set(["where", "include", "select"]),
1661
+ count: /* @__PURE__ */ new Set(["where", "select", "cursor", "orderBy", "skip", "take"]),
1662
+ aggregate: /* @__PURE__ */ new Set(["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"]),
1663
+ groupBy: /* @__PURE__ */ new Set(["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"])
1664
+ };
1665
+ var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set(["findUnique", "findUniqueOrThrow"]);
1666
+ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1667
+ const whereBuilder = createWhereBuilder(typeMap, enumMap);
1668
+ const argsBuilder = createArgsBuilder(typeMap, enumMap, uniqueMap);
1669
+ const projectionBuilder = createProjectionBuilder(typeMap, enumMap, {
1670
+ buildWhereSchema: whereBuilder.buildWhereSchema,
1671
+ buildOrderBySchema: argsBuilder.buildOrderBySchema,
1672
+ buildCursorSchema: argsBuilder.buildCursorSchema,
1673
+ buildTakeSchema: argsBuilder.buildTakeSchema
1674
+ });
1675
+ function isShapeConfig(obj) {
1676
+ if (!isPlainObject(obj))
1677
+ return false;
1678
+ const keys = Object.keys(obj);
1679
+ return keys.length === 0 || keys.every((k) => SHAPE_CONFIG_KEYS.has(k));
1436
1680
  }
1437
1681
  function validateShapeArgs(method, shape) {
1438
1682
  const allowed = METHOD_ALLOWED_ARGS[method];
1439
1683
  for (const key of Object.keys(shape)) {
1440
- if (!SHAPE_CONFIG_KEYS.has(key)) {
1684
+ if (!SHAPE_CONFIG_KEYS.has(key))
1441
1685
  throw new ShapeError(`Unknown shape config key "${key}"`);
1442
- }
1443
- if (!allowed.has(key)) {
1686
+ if (!allowed.has(key))
1444
1687
  throw new ShapeError(`Arg "${key}" not allowed for method "${method}"`);
1445
- }
1688
+ }
1689
+ if (UNIQUE_WHERE_METHODS.has(method) && !shape.where) {
1690
+ throw new ShapeError(`${method} shape must define "where"`);
1446
1691
  }
1447
1692
  if (shape.include && shape.select) {
1448
- throw new ShapeError(
1449
- 'Shape config cannot define both "include" and "select".'
1450
- );
1693
+ throw new ShapeError('Shape config cannot define both "include" and "select".');
1451
1694
  }
1452
- if (method === "groupBy" && !shape.by) {
1695
+ if (method === "groupBy" && !shape.by)
1453
1696
  throw new ShapeError('groupBy shape must define "by"');
1454
- }
1455
1697
  if (method === "groupBy" && (shape.include || shape.select)) {
1456
1698
  throw new ShapeError('groupBy does not support "include" or "select"');
1457
1699
  }
1458
1700
  if (method === "aggregate" && (shape.include || shape.select)) {
1459
1701
  throw new ShapeError('aggregate does not support "include" or "select"');
1460
1702
  }
1461
- if (method === "count" && shape.include) {
1703
+ if (method === "count" && shape.include)
1462
1704
  throw new ShapeError('count does not support "include"');
1463
- }
1464
1705
  if (method === "groupBy" && shape.orderBy) {
1465
1706
  const bySet = new Set(shape.by);
1466
1707
  for (const fieldName of Object.keys(shape.orderBy)) {
1467
1708
  if (!bySet.has(fieldName)) {
1468
- throw new ShapeError(
1469
- `orderBy field "${fieldName}" must be included in "by" for groupBy`
1470
- );
1709
+ throw new ShapeError(`orderBy field "${fieldName}" must be included in "by" for groupBy`);
1471
1710
  }
1472
1711
  }
1473
1712
  }
@@ -1475,9 +1714,7 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1475
1714
  const bySet = new Set(shape.by);
1476
1715
  for (const fieldName of Object.keys(shape.having)) {
1477
1716
  if (!bySet.has(fieldName)) {
1478
- throw new ShapeError(
1479
- `having field "${fieldName}" must be included in "by" for groupBy`
1480
- );
1717
+ throw new ShapeError(`having field "${fieldName}" must be included in "by" for groupBy`);
1481
1718
  }
1482
1719
  }
1483
1720
  }
@@ -1487,97 +1724,76 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1487
1724
  return;
1488
1725
  if (!shape.where)
1489
1726
  return;
1490
- validateUniqueEquality(model, shape.where, method, uniqueMap);
1727
+ validateUniqueEquality(model, shape.where, method, uniqueMap, typeMap);
1728
+ }
1729
+ function resolveAndValidateShape(shapeOrFn, ctx) {
1730
+ if (typeof shapeOrFn === "function") {
1731
+ requireContext(ctx, "shape function");
1732
+ const result = shapeOrFn(ctx);
1733
+ if (!isPlainObject(result)) {
1734
+ throw new ShapeError("Dynamic shape function must return a plain object");
1735
+ }
1736
+ return result;
1737
+ }
1738
+ return shapeOrFn;
1491
1739
  }
1492
1740
  function buildShapeZodSchema(model, method, shape) {
1493
1741
  validateShapeArgs(method, shape);
1494
1742
  validateUniqueWhere(model, method, shape);
1495
1743
  const schemaFields = {};
1496
- let forcedWhere = {};
1744
+ let forcedWhere = EMPTY_WHERE_FORCED;
1497
1745
  let forcedIncludeTree = {};
1498
1746
  let forcedSelectTree = {};
1499
1747
  let forcedIncludeCountWhere = {};
1500
1748
  let forcedSelectCountWhere = {};
1501
1749
  if (shape.where) {
1502
- const { schema, forced } = buildWhereSchema(model, shape.where);
1750
+ const { schema, forced } = whereBuilder.buildWhereSchema(model, shape.where);
1503
1751
  if (schema)
1504
1752
  schemaFields["where"] = schema;
1505
1753
  forcedWhere = forced;
1506
1754
  }
1507
1755
  if (shape.include) {
1508
- const result = buildIncludeSchema(model, shape.include);
1756
+ const result = projectionBuilder.buildIncludeSchema(model, shape.include);
1509
1757
  schemaFields["include"] = result.schema;
1510
1758
  forcedIncludeTree = result.forcedTree;
1511
1759
  forcedIncludeCountWhere = result.forcedCountWhere;
1512
1760
  }
1513
1761
  if (shape.select) {
1514
1762
  if (method === "count") {
1515
- schemaFields["select"] = buildCountSelectSchema(model, shape.select);
1763
+ schemaFields["select"] = argsBuilder.buildCountSelectSchema(model, shape.select);
1516
1764
  } else {
1517
- const result = buildSelectSchema(model, shape.select);
1765
+ const result = projectionBuilder.buildSelectSchema(model, shape.select);
1518
1766
  schemaFields["select"] = result.schema;
1519
1767
  forcedSelectTree = result.forcedTree;
1520
1768
  forcedSelectCountWhere = result.forcedCountWhere;
1521
1769
  }
1522
1770
  }
1523
- if (shape.orderBy) {
1524
- schemaFields["orderBy"] = buildOrderBySchema(model, shape.orderBy);
1525
- }
1526
- if (shape.cursor) {
1527
- schemaFields["cursor"] = buildCursorSchema(model, shape.cursor);
1528
- }
1529
- if (shape.take) {
1530
- schemaFields["take"] = buildTakeSchema(shape.take);
1531
- }
1532
- if (shape.skip) {
1533
- schemaFields["skip"] = z4.number().int().min(0).optional();
1534
- }
1535
- if (shape.distinct) {
1536
- schemaFields["distinct"] = buildDistinctSchema(model, shape.distinct);
1537
- }
1538
- if (shape._count) {
1539
- schemaFields["_count"] = buildCountFieldSchema(
1540
- model,
1541
- shape._count,
1542
- "_count"
1543
- );
1544
- }
1545
- if (shape._avg) {
1546
- schemaFields["_avg"] = buildAggregateFieldSchema(
1547
- model,
1548
- "_avg",
1549
- shape._avg
1550
- );
1551
- }
1552
- if (shape._sum) {
1553
- schemaFields["_sum"] = buildAggregateFieldSchema(
1554
- model,
1555
- "_sum",
1556
- shape._sum
1557
- );
1558
- }
1559
- if (shape._min) {
1560
- schemaFields["_min"] = buildAggregateFieldSchema(
1561
- model,
1562
- "_min",
1563
- shape._min
1564
- );
1565
- }
1566
- if (shape._max) {
1567
- schemaFields["_max"] = buildAggregateFieldSchema(
1568
- model,
1569
- "_max",
1570
- shape._max
1571
- );
1572
- }
1573
- if (shape.by) {
1574
- schemaFields["by"] = buildBySchema(model, shape.by);
1575
- }
1576
- if (shape.having) {
1577
- schemaFields["having"] = buildHavingSchema(model, shape.having);
1578
- }
1771
+ if (shape.orderBy)
1772
+ schemaFields["orderBy"] = argsBuilder.buildOrderBySchema(model, shape.orderBy);
1773
+ if (shape.cursor)
1774
+ schemaFields["cursor"] = argsBuilder.buildCursorSchema(model, shape.cursor);
1775
+ if (shape.take)
1776
+ schemaFields["take"] = argsBuilder.buildTakeSchema(shape.take);
1777
+ if (shape.skip)
1778
+ schemaFields["skip"] = z7.number().int().min(0).optional();
1779
+ if (shape.distinct)
1780
+ schemaFields["distinct"] = argsBuilder.buildDistinctSchema(model, shape.distinct);
1781
+ if (shape._count)
1782
+ schemaFields["_count"] = argsBuilder.buildCountFieldSchema(model, shape._count, "_count");
1783
+ if (shape._avg)
1784
+ schemaFields["_avg"] = argsBuilder.buildAggregateFieldSchema(model, "_avg", shape._avg);
1785
+ if (shape._sum)
1786
+ schemaFields["_sum"] = argsBuilder.buildAggregateFieldSchema(model, "_sum", shape._sum);
1787
+ if (shape._min)
1788
+ schemaFields["_min"] = argsBuilder.buildAggregateFieldSchema(model, "_min", shape._min);
1789
+ if (shape._max)
1790
+ schemaFields["_max"] = argsBuilder.buildAggregateFieldSchema(model, "_max", shape._max);
1791
+ if (shape.by)
1792
+ schemaFields["by"] = argsBuilder.buildBySchema(model, shape.by);
1793
+ if (shape.having)
1794
+ schemaFields["having"] = argsBuilder.buildHavingSchema(model, shape.having);
1579
1795
  return {
1580
- zodSchema: z4.object(schemaFields).strict(),
1796
+ zodSchema: z7.object(schemaFields).strict(),
1581
1797
  forcedWhere,
1582
1798
  forcedIncludeTree,
1583
1799
  forcedSelectTree,
@@ -1592,30 +1808,20 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1592
1808
  return { key: matched, shape: shapes[matched] };
1593
1809
  }
1594
1810
  function buildQuerySchema(model, method, config) {
1595
- const isSingleShape2 = typeof config === "function" || isShapeConfig(config);
1811
+ const isSingle = typeof config === "function" || isShapeConfig(config);
1596
1812
  const builtCache = /* @__PURE__ */ new Map();
1597
- if (isSingleShape2 && typeof config !== "function") {
1598
- const built = buildShapeZodSchema(model, method, config);
1599
- builtCache.set("_default", built);
1813
+ if (isSingle && typeof config !== "function") {
1814
+ builtCache.set("_default", buildShapeZodSchema(model, method, config));
1600
1815
  }
1601
- if (!isSingleShape2) {
1816
+ if (!isSingle) {
1602
1817
  for (const key of Object.keys(config)) {
1603
1818
  if (SHAPE_CONFIG_KEYS.has(key)) {
1604
- throw new ShapeError(
1605
- `Caller key "${key}" collides with reserved shape config key. Rename the caller path.`
1606
- );
1819
+ throw new ShapeError(`Caller key "${key}" collides with reserved shape config key. Rename the caller path.`);
1607
1820
  }
1608
1821
  }
1609
- for (const [key, shapeOrFn] of Object.entries(
1610
- config
1611
- )) {
1822
+ for (const [key, shapeOrFn] of Object.entries(config)) {
1612
1823
  if (typeof shapeOrFn !== "function") {
1613
- const built = buildShapeZodSchema(
1614
- model,
1615
- method,
1616
- shapeOrFn
1617
- );
1618
- builtCache.set(key, built);
1824
+ builtCache.set(key, buildShapeZodSchema(model, method, shapeOrFn));
1619
1825
  }
1620
1826
  }
1621
1827
  }
@@ -1626,45 +1832,41 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1626
1832
  ),
1627
1833
  parse(body, opts) {
1628
1834
  let built;
1629
- if (isSingleShape2) {
1835
+ if (isSingle) {
1630
1836
  if (typeof config === "function") {
1631
- requireContext(opts?.ctx, "shape function");
1632
- const resolvedShape = config(opts.ctx);
1633
- built = buildShapeZodSchema(model, method, resolvedShape);
1837
+ const resolved = resolveAndValidateShape(config, opts?.ctx);
1838
+ built = buildShapeZodSchema(model, method, resolved);
1634
1839
  } else {
1635
1840
  built = builtCache.get("_default");
1636
1841
  }
1637
1842
  } else {
1638
- if (!isPlainObject(body)) {
1843
+ if (!isPlainObject(body))
1639
1844
  throw new ShapeError("Request body must be an object");
1845
+ if ("caller" in body) {
1846
+ throw new CallerError(
1847
+ "Pass caller via opts.caller, not in the request body."
1848
+ );
1640
1849
  }
1641
- const caller = body.caller;
1850
+ const caller = opts?.caller;
1642
1851
  if (typeof caller !== "string") {
1643
- throw new CallerError('Missing "caller" field in request body');
1852
+ const allowed = Object.keys(config);
1853
+ throw new CallerError(
1854
+ `Missing caller. This query uses named shape routing with keys: ${allowed.map((k) => `"${k}"`).join(", ")}. Provide caller via opts.caller.`
1855
+ );
1644
1856
  }
1645
- const matched = matchCaller(
1646
- config,
1647
- caller
1648
- );
1857
+ const matched = matchCaller(config, caller);
1649
1858
  if (!matched) {
1650
- const allowed = Object.keys(
1651
- config
1652
- );
1859
+ const allowed = Object.keys(config);
1653
1860
  throw new CallerError(
1654
1861
  `Unknown caller: "${caller}". Allowed: ${allowed.map((k) => `"${k}"`).join(", ")}`
1655
1862
  );
1656
1863
  }
1657
- const shapeKey = matched.key;
1658
- const shapeOrFn = matched.shape;
1659
- if (typeof shapeOrFn === "function") {
1660
- requireContext(opts?.ctx, "shape function");
1661
- const resolvedShape = shapeOrFn(opts.ctx);
1662
- built = buildShapeZodSchema(model, method, resolvedShape);
1864
+ if (typeof matched.shape === "function") {
1865
+ const resolved = resolveAndValidateShape(matched.shape, opts?.ctx);
1866
+ built = buildShapeZodSchema(model, method, resolved);
1663
1867
  } else {
1664
- built = builtCache.get(shapeKey);
1868
+ built = builtCache.get(matched.key);
1665
1869
  }
1666
- const { caller: _, ...rest } = body;
1667
- body = rest;
1668
1870
  }
1669
1871
  return applyBuiltShape(built, body, isUnique);
1670
1872
  }
@@ -1673,9 +1875,9 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
1673
1875
  return {
1674
1876
  buildQuerySchema,
1675
1877
  buildShapeZodSchema,
1676
- buildWhereSchema,
1677
- buildIncludeSchema,
1678
- buildSelectSchema
1878
+ buildWhereSchema: whereBuilder.buildWhereSchema,
1879
+ buildIncludeSchema: projectionBuilder.buildIncludeSchema,
1880
+ buildSelectSchema: projectionBuilder.buildSelectSchema
1679
1881
  };
1680
1882
  }
1681
1883
 
@@ -2005,9 +2207,14 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log)
2005
2207
  }
2006
2208
 
2007
2209
  // src/runtime/model-guard.ts
2008
- import { z as z5 } from "zod";
2210
+ import { z as z9 } from "zod";
2211
+
2212
+ // src/runtime/model-guard-data.ts
2213
+ import { z as z8 } from "zod";
2009
2214
  var ALLOWED_BODY_KEYS_CREATE = /* @__PURE__ */ new Set(["data"]);
2010
2215
  var ALLOWED_BODY_KEYS_CREATE_PROJECTION = /* @__PURE__ */ new Set(["data", "select", "include"]);
2216
+ var ALLOWED_BODY_KEYS_CREATE_MANY = /* @__PURE__ */ new Set(["data", "skipDuplicates"]);
2217
+ var ALLOWED_BODY_KEYS_CREATE_MANY_PROJECTION = /* @__PURE__ */ new Set(["data", "select", "include", "skipDuplicates"]);
2011
2218
  var ALLOWED_BODY_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
2012
2219
  var ALLOWED_BODY_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set(["data", "where", "select", "include"]);
2013
2220
  var ALLOWED_BODY_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
@@ -2018,28 +2225,11 @@ var VALID_SHAPE_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
2018
2225
  var VALID_SHAPE_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set(["data", "where", "select", "include"]);
2019
2226
  var VALID_SHAPE_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
2020
2227
  var VALID_SHAPE_KEYS_DELETE_PROJECTION = /* @__PURE__ */ new Set(["where", "select", "include"]);
2021
- var UNIQUE_MUTATION_METHODS = /* @__PURE__ */ new Set(["update", "delete"]);
2022
- var UNIQUE_READ_METHODS = /* @__PURE__ */ new Set(["findUnique", "findUniqueOrThrow"]);
2023
- var BULK_MUTATION_METHODS = /* @__PURE__ */ new Set([
2024
- "updateMany",
2025
- "updateManyAndReturn",
2026
- "deleteMany"
2027
- ]);
2028
- var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
2029
- "create",
2030
- "update",
2031
- "delete",
2032
- "createManyAndReturn",
2033
- "updateManyAndReturn"
2034
- ]);
2035
- function isGuardShape(obj) {
2036
- if (!isPlainObject(obj))
2228
+ function isZodSchema2(value) {
2229
+ if (value == null || typeof value !== "object")
2037
2230
  return false;
2038
- const keys = Object.keys(obj);
2039
- return keys.length === 0 || keys.every((k) => GUARD_SHAPE_KEYS.has(k));
2040
- }
2041
- function isSingleShape(input) {
2042
- return typeof input === "function" || isGuardShape(input);
2231
+ const v = value;
2232
+ return typeof v.parse === "function" && typeof v.optional === "function";
2043
2233
  }
2044
2234
  function validateMutationBodyKeys(body, allowed, method) {
2045
2235
  for (const key of Object.keys(body)) {
@@ -2059,197 +2249,258 @@ function validateMutationShapeKeys(shape, allowed, method) {
2059
2249
  }
2060
2250
  }
2061
2251
  }
2062
- function formatZodError(err) {
2063
- return err.issues.map((i) => {
2064
- const p = i.path.length > 0 ? `${i.path.join(".")}: ` : "";
2065
- return `${p}${i.message}`;
2066
- }).join("; ");
2067
- }
2068
- function createModelGuardExtension(config) {
2069
- const { typeMap, enumMap, zodChains, uniqueMap, scopeMap, contextFn } = config;
2070
- const wrapZodErrors = config.wrapZodErrors ?? false;
2071
- const schemaBuilder = createSchemaBuilder(typeMap, zodChains, enumMap);
2072
- const queryBuilder = createQueryBuilder(typeMap, enumMap, uniqueMap);
2073
- const modelScopeFks = /* @__PURE__ */ new Map();
2074
- for (const [model, entries] of Object.entries(scopeMap)) {
2075
- const fks = /* @__PURE__ */ new Set();
2076
- for (const entry of entries) {
2077
- fks.add(entry.fk);
2078
- }
2079
- modelScopeFks.set(model, fks);
2080
- }
2081
- function validateCreateCompleteness(modelName, dataConfig) {
2082
- const modelFields = typeMap[modelName];
2083
- if (!modelFields)
2084
- return;
2085
- const fks = modelScopeFks.get(modelName) ?? /* @__PURE__ */ new Set();
2086
- for (const [fieldName, meta] of Object.entries(modelFields)) {
2087
- if (meta.isRelation)
2088
- continue;
2089
- if (meta.isUpdatedAt)
2090
- continue;
2091
- if (meta.hasDefault)
2092
- continue;
2093
- if (!meta.isRequired)
2094
- continue;
2095
- if (fieldName in dataConfig)
2096
- continue;
2097
- if (fks.has(fieldName))
2098
- continue;
2099
- throw new ShapeError(
2100
- `Required field "${fieldName}" on model "${modelName}" is missing from create data shape, has no default, and is not a scope FK`
2101
- );
2102
- }
2252
+ function validateCreateCompleteness(modelName, dataConfig, typeMap, scopeFks, zodDefaults) {
2253
+ const modelFields = typeMap[modelName];
2254
+ if (!modelFields)
2255
+ return;
2256
+ const zodDefaultFields = zodDefaults[modelName];
2257
+ const zodDefaultSet = zodDefaultFields ? new Set(zodDefaultFields) : void 0;
2258
+ for (const [fieldName, meta] of Object.entries(modelFields)) {
2259
+ if (meta.isRelation)
2260
+ continue;
2261
+ if (meta.isUpdatedAt)
2262
+ continue;
2263
+ if (meta.hasDefault)
2264
+ continue;
2265
+ if (!meta.isRequired)
2266
+ continue;
2267
+ if (fieldName in dataConfig)
2268
+ continue;
2269
+ if (scopeFks.has(fieldName))
2270
+ continue;
2271
+ if (zodDefaultSet && zodDefaultSet.has(fieldName))
2272
+ continue;
2273
+ throw new ShapeError(
2274
+ `Required field "${fieldName}" on model "${modelName}" is missing from create data shape, has no default, and is not a scope FK`
2275
+ );
2103
2276
  }
2104
- function buildDataSchema(model, dataConfig, mode) {
2105
- const modelFields = typeMap[model];
2106
- if (!modelFields)
2107
- throw new ShapeError(`Unknown model: ${model}`);
2108
- const schemaMap = {};
2109
- const forced = {};
2110
- for (const [fieldName, value] of Object.entries(dataConfig)) {
2111
- const fieldMeta = modelFields[fieldName];
2112
- if (!fieldMeta)
2113
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
2114
- if (fieldMeta.isRelation)
2115
- throw new ShapeError(`Relation field "${fieldName}" cannot be used in data shape`);
2116
- if (fieldMeta.isUpdatedAt)
2117
- throw new ShapeError(`updatedAt field "${fieldName}" cannot be used in data shape`);
2118
- if (typeof value === "function") {
2119
- let baseSchema = schemaBuilder.buildBaseFieldSchema(model, fieldName);
2120
- let fieldSchema;
2121
- try {
2122
- fieldSchema = value(baseSchema);
2123
- } catch (err) {
2124
- throw new ShapeError(
2125
- `Invalid inline refine for "${model}.${fieldName}": ${err.message}`,
2126
- { cause: err }
2127
- );
2277
+ }
2278
+ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder) {
2279
+ const modelFields = typeMap[model];
2280
+ if (!modelFields)
2281
+ throw new ShapeError(`Unknown model: ${model}`);
2282
+ const schemaMap = {};
2283
+ const forced = {};
2284
+ for (const [fieldName, value] of Object.entries(dataConfig)) {
2285
+ const fieldMeta = modelFields[fieldName];
2286
+ if (!fieldMeta)
2287
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
2288
+ if (fieldMeta.isRelation)
2289
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in data shape`);
2290
+ if (fieldMeta.isUpdatedAt)
2291
+ throw new ShapeError(`updatedAt field "${fieldName}" cannot be used in data shape`);
2292
+ if (typeof value === "function") {
2293
+ let baseSchema = schemaBuilder.buildBaseFieldSchema(model, fieldName);
2294
+ let refined;
2295
+ try {
2296
+ refined = value(baseSchema);
2297
+ } catch (err) {
2298
+ throw new ShapeError(
2299
+ `Invalid inline refine for "${model}.${fieldName}": ${err.message}`,
2300
+ { cause: err }
2301
+ );
2302
+ }
2303
+ if (!isZodSchema2(refined)) {
2304
+ throw new ShapeError(`Inline refine for "${model}.${fieldName}" must return a Zod schema`);
2305
+ }
2306
+ let fieldSchema = refined;
2307
+ if (mode === "create") {
2308
+ if (!fieldMeta.isRequired) {
2309
+ fieldSchema = fieldSchema.nullable().optional();
2310
+ } else if (fieldMeta.hasDefault) {
2311
+ fieldSchema = fieldSchema.optional();
2128
2312
  }
2129
- if (mode === "create") {
2130
- if (!fieldMeta.isRequired || fieldMeta.hasDefault) {
2131
- fieldSchema = fieldSchema.optional();
2132
- }
2313
+ } else {
2314
+ if (!fieldMeta.isRequired) {
2315
+ fieldSchema = fieldSchema.nullable().optional();
2133
2316
  } else {
2134
- if (!fieldMeta.isRequired) {
2135
- fieldSchema = fieldSchema.nullable().optional();
2136
- } else {
2137
- fieldSchema = fieldSchema.optional();
2138
- }
2317
+ fieldSchema = fieldSchema.optional();
2139
2318
  }
2140
- schemaMap[fieldName] = fieldSchema;
2141
- } else if (value === true) {
2142
- let fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
2143
- if (mode === "create") {
2144
- if (!fieldMeta.isRequired || fieldMeta.hasDefault) {
2145
- fieldSchema = fieldSchema.optional();
2146
- }
2147
- } else {
2148
- if (!fieldMeta.isRequired) {
2149
- fieldSchema = fieldSchema.nullable().optional();
2150
- } else {
2151
- fieldSchema = fieldSchema.optional();
2152
- }
2319
+ }
2320
+ schemaMap[fieldName] = fieldSchema;
2321
+ } else if (value === true) {
2322
+ let fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
2323
+ if (mode === "create") {
2324
+ if (!fieldMeta.isRequired) {
2325
+ fieldSchema = fieldSchema.nullable().optional();
2326
+ } else if (fieldMeta.hasDefault) {
2327
+ fieldSchema = fieldSchema.optional();
2153
2328
  }
2154
- schemaMap[fieldName] = fieldSchema;
2155
2329
  } else {
2156
- let fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
2157
2330
  if (!fieldMeta.isRequired) {
2158
- fieldSchema = fieldSchema.nullable();
2159
- }
2160
- let parsed;
2161
- try {
2162
- parsed = fieldSchema.parse(value);
2163
- } catch (err) {
2164
- throw new ShapeError(
2165
- `Invalid forced data value for "${model}.${fieldName}": ${err.message}`
2166
- );
2331
+ fieldSchema = fieldSchema.nullable().optional();
2332
+ } else {
2333
+ fieldSchema = fieldSchema.optional();
2167
2334
  }
2168
- forced[fieldName] = parsed;
2169
2335
  }
2170
- }
2171
- return {
2172
- schema: z5.object(schemaMap).strict(),
2173
- forced
2174
- };
2175
- }
2176
- function resolveShape(input, body) {
2177
- if (isSingleShape(input)) {
2178
- const wasDynamic2 = typeof input === "function";
2179
- const shape2 = wasDynamic2 ? input(contextFn()) : input;
2180
- const parsed2 = body === void 0 || body === null ? {} : requireBody(body);
2181
- if ("caller" in parsed2) {
2182
- throw new CallerError(
2183
- 'Named shape routing is not configured on this guard. Remove "caller" from the request body or use a named shape map.'
2184
- );
2185
- }
2186
- return { shape: shape2, body: parsed2, matchedKey: "_default", wasDynamic: wasDynamic2 };
2187
- }
2188
- const namedMap = input;
2189
- for (const key of Object.keys(namedMap)) {
2190
- if (GUARD_SHAPE_KEYS.has(key)) {
2191
- throw new ShapeError(
2192
- `Caller key "${key}" collides with reserved shape config key. Rename the caller path.`
2193
- );
2336
+ schemaMap[fieldName] = fieldSchema;
2337
+ } else {
2338
+ let fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
2339
+ if (!fieldMeta.isRequired) {
2340
+ fieldSchema = fieldSchema.nullable();
2194
2341
  }
2195
- const val = namedMap[key];
2196
- if (typeof val !== "function" && !isGuardShape(val)) {
2342
+ let parsed;
2343
+ try {
2344
+ parsed = fieldSchema.parse(value);
2345
+ } catch (err) {
2197
2346
  throw new ShapeError(
2198
- `Named shape value for "${key}" must be a guard shape object or function`
2347
+ `Invalid forced data value for "${model}.${fieldName}": ${err.message}`
2199
2348
  );
2200
2349
  }
2350
+ forced[fieldName] = parsed;
2201
2351
  }
2202
- const parsed = requireBody(body);
2203
- const caller = parsed.caller;
2204
- if (typeof caller !== "string") {
2205
- throw new CallerError('Missing "caller" field in request body');
2352
+ }
2353
+ return {
2354
+ schema: z8.object(schemaMap).strict(),
2355
+ forced
2356
+ };
2357
+ }
2358
+ function validateAndMergeData(bodyData, cached, method) {
2359
+ if (bodyData === void 0 || bodyData === null) {
2360
+ throw new ShapeError(`${method} requires "data" in request body`);
2361
+ }
2362
+ const validated = cached.schema.parse(bodyData);
2363
+ return { ...validated, ...cached.forced };
2364
+ }
2365
+ function hasDataRefines(dataConfig) {
2366
+ for (const value of Object.values(dataConfig)) {
2367
+ if (typeof value === "function")
2368
+ return true;
2369
+ }
2370
+ return false;
2371
+ }
2372
+
2373
+ // src/runtime/model-guard-resolve.ts
2374
+ function isGuardShape(obj) {
2375
+ if (!isPlainObject(obj))
2376
+ return false;
2377
+ const keys = Object.keys(obj);
2378
+ return keys.length === 0 || keys.every((k) => GUARD_SHAPE_KEYS.has(k));
2379
+ }
2380
+ function isSingleShape(input) {
2381
+ return typeof input === "function" || isGuardShape(input);
2382
+ }
2383
+ function requireBody(body) {
2384
+ if (!isPlainObject(body))
2385
+ throw new ShapeError("Request body must be an object");
2386
+ return body;
2387
+ }
2388
+ function resolveDynamicShape(fn, contextFn) {
2389
+ const ctx = validateContext(contextFn());
2390
+ let result;
2391
+ try {
2392
+ result = fn(ctx);
2393
+ } catch (err) {
2394
+ throw new ShapeError(
2395
+ `Dynamic shape function threw: ${err.message}`,
2396
+ { cause: err }
2397
+ );
2398
+ }
2399
+ if (!isPlainObject(result)) {
2400
+ throw new ShapeError("Dynamic shape function must return a plain object");
2401
+ }
2402
+ return result;
2403
+ }
2404
+ function resolveShape(input, body, contextFn, caller) {
2405
+ if (isSingleShape(input)) {
2406
+ const wasDynamic2 = typeof input === "function";
2407
+ const shape2 = wasDynamic2 ? resolveDynamicShape(input, contextFn) : input;
2408
+ const parsed2 = body === void 0 || body === null ? {} : requireBody(body);
2409
+ return { shape: shape2, body: parsed2, matchedKey: "_default", wasDynamic: wasDynamic2 };
2410
+ }
2411
+ const namedMap = input;
2412
+ for (const key of Object.keys(namedMap)) {
2413
+ if (GUARD_SHAPE_KEYS.has(key)) {
2414
+ throw new ShapeError(
2415
+ `Caller key "${key}" collides with reserved shape config key. Rename the caller path.`
2416
+ );
2206
2417
  }
2207
- const patterns = Object.keys(namedMap);
2208
- const matched = matchCallerPattern(patterns, caller);
2209
- if (!matched) {
2210
- throw new CallerError(
2211
- `Unknown caller: "${caller}". Allowed: ${patterns.map((k) => `"${k}"`).join(", ")}`
2418
+ const val = namedMap[key];
2419
+ if (typeof val !== "function" && !isGuardShape(val)) {
2420
+ throw new ShapeError(
2421
+ `Named shape value for "${key}" must be a guard shape object or function`
2212
2422
  );
2213
2423
  }
2214
- const shapeOrFn = namedMap[matched];
2215
- const wasDynamic = typeof shapeOrFn === "function";
2216
- const shape = wasDynamic ? shapeOrFn(contextFn()) : shapeOrFn;
2217
- const { caller: _, ...rest } = parsed;
2218
- return { shape, body: rest, matchedKey: matched, wasDynamic };
2219
2424
  }
2220
- function requireBody(body) {
2221
- if (!isPlainObject(body))
2222
- throw new ShapeError("Request body must be an object");
2223
- return body;
2425
+ const parsed = requireBody(body);
2426
+ if ("caller" in parsed) {
2427
+ throw new CallerError(
2428
+ "Pass caller as second argument to .guard() or via context function, not in the request body."
2429
+ );
2430
+ }
2431
+ if (typeof caller !== "string") {
2432
+ const patterns2 = Object.keys(namedMap);
2433
+ throw new CallerError(
2434
+ `Missing caller. This guard uses named shape routing with keys: ${patterns2.map((k) => `"${k}"`).join(", ")}. Provide caller as second argument to .guard() or set "caller" in the context function.`
2435
+ );
2224
2436
  }
2225
- function validateAndMergeData(bodyData, cached, method) {
2226
- if (bodyData === void 0 || bodyData === null) {
2227
- throw new ShapeError(`${method} requires "data" in request body`);
2228
- }
2229
- const validated = cached.schema.parse(bodyData);
2230
- return { ...validated, ...cached.forced };
2437
+ const patterns = Object.keys(namedMap);
2438
+ const matched = matchCallerPattern(patterns, caller);
2439
+ if (!matched) {
2440
+ throw new CallerError(
2441
+ `Unknown caller: "${caller}". Allowed: ${patterns.map((k) => `"${k}"`).join(", ")}`
2442
+ );
2443
+ }
2444
+ const shapeOrFn = namedMap[matched];
2445
+ const wasDynamic = typeof shapeOrFn === "function";
2446
+ const shape = wasDynamic ? resolveDynamicShape(shapeOrFn, contextFn) : shapeOrFn;
2447
+ return { shape, body: parsed, matchedKey: matched, wasDynamic };
2448
+ }
2449
+
2450
+ // src/runtime/model-guard.ts
2451
+ var UNIQUE_MUTATION_METHODS = /* @__PURE__ */ new Set(["update", "delete"]);
2452
+ var UNIQUE_READ_METHODS = /* @__PURE__ */ new Set(["findUnique", "findUniqueOrThrow"]);
2453
+ var BULK_MUTATION_METHODS = /* @__PURE__ */ new Set([
2454
+ "updateMany",
2455
+ "updateManyAndReturn",
2456
+ "deleteMany"
2457
+ ]);
2458
+ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
2459
+ "create",
2460
+ "update",
2461
+ "delete",
2462
+ "createManyAndReturn",
2463
+ "updateManyAndReturn"
2464
+ ]);
2465
+ var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set([
2466
+ "createMany",
2467
+ "createManyAndReturn"
2468
+ ]);
2469
+ function createModelGuardExtension(config) {
2470
+ const { typeMap, enumMap, zodChains, zodDefaults, uniqueMap, scopeMap, contextFn } = config;
2471
+ const wrapZodErrors = config.wrapZodErrors ?? false;
2472
+ const schemaBuilder = createSchemaBuilder(typeMap, zodChains, enumMap);
2473
+ const queryBuilder = createQueryBuilder(typeMap, enumMap, uniqueMap);
2474
+ const modelScopeFks = /* @__PURE__ */ new Map();
2475
+ for (const [model, entries] of Object.entries(scopeMap)) {
2476
+ const fks = /* @__PURE__ */ new Set();
2477
+ for (const entry of entries)
2478
+ fks.add(entry.fk);
2479
+ modelScopeFks.set(model, fks);
2231
2480
  }
2232
2481
  function maybeValidateUniqueWhere(modelName, shape, method) {
2233
2482
  if (!UNIQUE_MUTATION_METHODS.has(method))
2234
2483
  return;
2235
2484
  if (!shape.where)
2236
2485
  return;
2237
- validateUniqueEquality(modelName, shape.where, method, uniqueMap);
2486
+ validateUniqueEquality(modelName, shape.where, method, uniqueMap, typeMap);
2238
2487
  }
2239
- function hasDataRefines(dataConfig) {
2240
- for (const value of Object.values(dataConfig)) {
2241
- if (typeof value === "function")
2242
- return true;
2243
- }
2244
- return false;
2245
- }
2246
- function createGuardedMethods(modelName, modelDelegate, input) {
2488
+ function createGuardedMethods(modelName, modelDelegate, input, explicitCaller) {
2247
2489
  function callDelegate(method, args) {
2248
2490
  if (typeof modelDelegate[method] !== "function") {
2249
2491
  throw new ShapeError(`Method "${method}" is not available on this model`);
2250
2492
  }
2251
2493
  return modelDelegate[method](args);
2252
2494
  }
2495
+ function resolveCaller() {
2496
+ if (explicitCaller !== void 0)
2497
+ return explicitCaller;
2498
+ const ctx = validateContext(contextFn());
2499
+ const c = ctx.caller;
2500
+ if (typeof c === "string")
2501
+ return c;
2502
+ return void 0;
2503
+ }
2253
2504
  const readShapeCache = /* @__PURE__ */ new Map();
2254
2505
  const dataSchemaCache = /* @__PURE__ */ new Map();
2255
2506
  const whereBuiltCache = /* @__PURE__ */ new Map();
@@ -2272,11 +2523,11 @@ function createModelGuardExtension(config) {
2272
2523
  const cached = dataSchemaCache.get(cacheKey);
2273
2524
  if (cached)
2274
2525
  return cached;
2275
- const built = buildDataSchema(modelName, dataConfig, mode);
2526
+ const built = buildDataSchema(modelName, dataConfig, mode, typeMap, schemaBuilder);
2276
2527
  dataSchemaCache.set(cacheKey, built);
2277
2528
  return built;
2278
2529
  }
2279
- return buildDataSchema(modelName, dataConfig, mode);
2530
+ return buildDataSchema(modelName, dataConfig, mode, typeMap, schemaBuilder);
2280
2531
  }
2281
2532
  function getWhereBuilt(whereConfig, matchedKey, wasDynamic) {
2282
2533
  if (!wasDynamic) {
@@ -2317,7 +2568,7 @@ function createModelGuardExtension(config) {
2317
2568
  forcedSelectCountWhere = result.forcedCountWhere;
2318
2569
  }
2319
2570
  return {
2320
- zodSchema: z5.object(schemaFields).strict(),
2571
+ zodSchema: z9.object(schemaFields).strict(),
2321
2572
  forcedIncludeTree,
2322
2573
  forcedSelectTree,
2323
2574
  forcedIncludeCountWhere,
@@ -2383,8 +2634,8 @@ function createModelGuardExtension(config) {
2383
2634
  if (built.schema) {
2384
2635
  validatedWhere = built.schema.parse(bodyWhere);
2385
2636
  }
2386
- if (Object.keys(built.forced).length > 0) {
2387
- return preserveUnique ? mergeUniqueForced(validatedWhere, built.forced) : mergeForced(validatedWhere, built.forced);
2637
+ if (hasWhereForced(built.forced)) {
2638
+ return preserveUnique ? mergeUniqueWhereForced(validatedWhere, built.forced) : mergeWhereForced(validatedWhere, built.forced);
2388
2639
  }
2389
2640
  return validatedWhere ?? {};
2390
2641
  }
@@ -2397,14 +2648,15 @@ function createModelGuardExtension(config) {
2397
2648
  }
2398
2649
  function makeReadMethod(method) {
2399
2650
  return (body) => {
2400
- const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2401
- if (shape.data) {
2651
+ const caller = resolveCaller();
2652
+ const resolved = resolveShape(input, body, contextFn, caller);
2653
+ if (resolved.shape.data) {
2402
2654
  throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
2403
2655
  }
2404
- const { data: _, ...queryShape } = shape;
2405
- const built = getReadShape(method, queryShape, matchedKey, wasDynamic);
2656
+ const { data: _, ...queryShape } = resolved.shape;
2657
+ const built = getReadShape(method, queryShape, resolved.matchedKey, resolved.wasDynamic);
2406
2658
  const isUnique = UNIQUE_READ_METHODS.has(method);
2407
- const args = applyBuiltShape(built, parsed, isUnique);
2659
+ const args = applyBuiltShape(built, resolved.body, isUnique);
2408
2660
  if (isUnique && args.where) {
2409
2661
  validateResolvedUniqueWhere(
2410
2662
  modelName,
@@ -2417,33 +2669,51 @@ function createModelGuardExtension(config) {
2417
2669
  };
2418
2670
  }
2419
2671
  function makeCreateMethod(method) {
2672
+ const isBatch = BATCH_CREATE_METHODS.has(method);
2420
2673
  const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
2421
- const allowedBodyKeys = supportsProjection ? ALLOWED_BODY_KEYS_CREATE_PROJECTION : ALLOWED_BODY_KEYS_CREATE;
2674
+ let allowedBodyKeys;
2675
+ if (isBatch && supportsProjection) {
2676
+ allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_MANY_PROJECTION;
2677
+ } else if (isBatch) {
2678
+ allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_MANY;
2679
+ } else if (supportsProjection) {
2680
+ allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE_PROJECTION;
2681
+ } else {
2682
+ allowedBodyKeys = ALLOWED_BODY_KEYS_CREATE;
2683
+ }
2422
2684
  const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_CREATE_PROJECTION : VALID_SHAPE_KEYS_CREATE;
2423
2685
  return (body) => {
2424
- const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2425
- if (!shape.data)
2686
+ const caller = resolveCaller();
2687
+ const resolved = resolveShape(input, body, contextFn, caller);
2688
+ if (!resolved.shape.data)
2426
2689
  throw new ShapeError(`Guard shape requires "data" for ${method}`);
2427
- validateMutationShapeKeys(shape, allowedShapeKeys, method);
2428
- validateMutationBodyKeys(parsed, allowedBodyKeys, method);
2429
- validateCreateCompleteness(modelName, shape.data);
2430
- const dataSchema = getDataSchema("create", shape.data, matchedKey, wasDynamic);
2690
+ validateMutationShapeKeys(resolved.shape, allowedShapeKeys, method);
2691
+ validateMutationBodyKeys(resolved.body, allowedBodyKeys, method);
2692
+ const fks = modelScopeFks.get(modelName) ?? /* @__PURE__ */ new Set();
2693
+ validateCreateCompleteness(modelName, resolved.shape.data, typeMap, fks, zodDefaults);
2694
+ const dataSchema = getDataSchema("create", resolved.shape.data, resolved.matchedKey, resolved.wasDynamic);
2431
2695
  let args;
2432
2696
  if (method === "create") {
2433
- const data = validateAndMergeData(parsed.data, dataSchema, method);
2697
+ const data = validateAndMergeData(resolved.body.data, dataSchema, method);
2434
2698
  args = { data };
2435
2699
  } else {
2436
- if (!Array.isArray(parsed.data))
2700
+ if (!Array.isArray(resolved.body.data))
2437
2701
  throw new ShapeError(`${method} expects data to be an array`);
2438
- if (parsed.data.length === 0)
2702
+ if (resolved.body.data.length === 0)
2439
2703
  throw new ShapeError(`${method} received empty data array`);
2440
- const data = parsed.data.map(
2704
+ const data = resolved.body.data.map(
2441
2705
  (item) => validateAndMergeData(item, dataSchema, method)
2442
2706
  );
2443
2707
  args = { data };
2444
2708
  }
2709
+ if (isBatch && resolved.body.skipDuplicates !== void 0) {
2710
+ if (typeof resolved.body.skipDuplicates !== "boolean") {
2711
+ throw new ShapeError(`${method} skipDuplicates must be a boolean`);
2712
+ }
2713
+ args.skipDuplicates = resolved.body.skipDuplicates;
2714
+ }
2445
2715
  if (supportsProjection) {
2446
- const projectionArgs = resolveProjection(shape, parsed, method, matchedKey, wasDynamic);
2716
+ const projectionArgs = resolveProjection(resolved.shape, resolved.body, method, resolved.matchedKey, resolved.wasDynamic);
2447
2717
  Object.assign(args, projectionArgs);
2448
2718
  }
2449
2719
  return callDelegate(method, args);
@@ -2456,18 +2726,19 @@ function createModelGuardExtension(config) {
2456
2726
  const allowedBodyKeys = supportsProjection ? ALLOWED_BODY_KEYS_UPDATE_PROJECTION : ALLOWED_BODY_KEYS_UPDATE;
2457
2727
  const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_UPDATE_PROJECTION : VALID_SHAPE_KEYS_UPDATE;
2458
2728
  return (body) => {
2459
- const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2460
- if (!shape.data)
2729
+ const caller = resolveCaller();
2730
+ const resolved = resolveShape(input, body, contextFn, caller);
2731
+ if (!resolved.shape.data)
2461
2732
  throw new ShapeError(`Guard shape requires "data" for ${method}`);
2462
- validateMutationShapeKeys(shape, allowedShapeKeys, method);
2463
- validateMutationBodyKeys(parsed, allowedBodyKeys, method);
2464
- if (isBulk && !shape.where) {
2733
+ validateMutationShapeKeys(resolved.shape, allowedShapeKeys, method);
2734
+ validateMutationBodyKeys(resolved.body, allowedBodyKeys, method);
2735
+ if (isBulk && !resolved.shape.where) {
2465
2736
  throw new ShapeError(`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`);
2466
2737
  }
2467
- maybeValidateUniqueWhere(modelName, shape, method);
2468
- const dataSchema = getDataSchema("update", shape.data, matchedKey, wasDynamic);
2469
- const data = validateAndMergeData(parsed.data, dataSchema, method);
2470
- const where = isUniqueWhere ? requireWhere(shape, parsed.where, method, true, matchedKey, wasDynamic) : buildWhereFromShape(shape, parsed.where, false, matchedKey, wasDynamic);
2738
+ maybeValidateUniqueWhere(modelName, resolved.shape, method);
2739
+ const dataSchema = getDataSchema("update", resolved.shape.data, resolved.matchedKey, resolved.wasDynamic);
2740
+ const data = validateAndMergeData(resolved.body.data, dataSchema, method);
2741
+ const where = isUniqueWhere ? requireWhere(resolved.shape, resolved.body.where, method, true, resolved.matchedKey, resolved.wasDynamic) : buildWhereFromShape(resolved.shape, resolved.body.where, false, resolved.matchedKey, resolved.wasDynamic);
2471
2742
  if (isBulk && Object.keys(where).length === 0) {
2472
2743
  throw new ShapeError(`${method} requires at least one where condition`);
2473
2744
  }
@@ -2476,7 +2747,7 @@ function createModelGuardExtension(config) {
2476
2747
  }
2477
2748
  const args = { data, where };
2478
2749
  if (supportsProjection) {
2479
- const projectionArgs = resolveProjection(shape, parsed, method, matchedKey, wasDynamic);
2750
+ const projectionArgs = resolveProjection(resolved.shape, resolved.body, method, resolved.matchedKey, resolved.wasDynamic);
2480
2751
  Object.assign(args, projectionArgs);
2481
2752
  }
2482
2753
  return callDelegate(method, args);
@@ -2489,16 +2760,17 @@ function createModelGuardExtension(config) {
2489
2760
  const allowedBodyKeys = supportsProjection ? ALLOWED_BODY_KEYS_DELETE_PROJECTION : ALLOWED_BODY_KEYS_DELETE;
2490
2761
  const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_DELETE_PROJECTION : VALID_SHAPE_KEYS_DELETE;
2491
2762
  return (body) => {
2492
- const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2493
- if (shape.data)
2763
+ const caller = resolveCaller();
2764
+ const resolved = resolveShape(input, body, contextFn, caller);
2765
+ if (resolved.shape.data)
2494
2766
  throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
2495
- validateMutationShapeKeys(shape, allowedShapeKeys, method);
2496
- validateMutationBodyKeys(parsed, allowedBodyKeys, method);
2497
- if (isBulk && !shape.where) {
2767
+ validateMutationShapeKeys(resolved.shape, allowedShapeKeys, method);
2768
+ validateMutationBodyKeys(resolved.body, allowedBodyKeys, method);
2769
+ if (isBulk && !resolved.shape.where) {
2498
2770
  throw new ShapeError(`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`);
2499
2771
  }
2500
- maybeValidateUniqueWhere(modelName, shape, method);
2501
- const where = isUniqueWhere ? requireWhere(shape, parsed.where, method, true, matchedKey, wasDynamic) : buildWhereFromShape(shape, parsed.where, false, matchedKey, wasDynamic);
2772
+ maybeValidateUniqueWhere(modelName, resolved.shape, method);
2773
+ const where = isUniqueWhere ? requireWhere(resolved.shape, resolved.body.where, method, true, resolved.matchedKey, resolved.wasDynamic) : buildWhereFromShape(resolved.shape, resolved.body.where, false, resolved.matchedKey, resolved.wasDynamic);
2502
2774
  if (isBulk && Object.keys(where).length === 0) {
2503
2775
  throw new ShapeError(`${method} requires at least one where condition`);
2504
2776
  }
@@ -2507,7 +2779,7 @@ function createModelGuardExtension(config) {
2507
2779
  }
2508
2780
  const args = { where };
2509
2781
  if (supportsProjection) {
2510
- const projectionArgs = resolveProjection(shape, parsed, method, matchedKey, wasDynamic);
2782
+ const projectionArgs = resolveProjection(resolved.shape, resolved.body, method, resolved.matchedKey, resolved.wasDynamic);
2511
2783
  Object.assign(args, projectionArgs);
2512
2784
  }
2513
2785
  return callDelegate(method, args);
@@ -2539,7 +2811,7 @@ function createModelGuardExtension(config) {
2539
2811
  try {
2540
2812
  return fn(body);
2541
2813
  } catch (err) {
2542
- if (err instanceof z5.ZodError) {
2814
+ if (err instanceof z9.ZodError) {
2543
2815
  throw new ShapeError(
2544
2816
  `Validation failed: ${formatZodError(err)}`,
2545
2817
  { cause: err }
@@ -2553,16 +2825,16 @@ function createModelGuardExtension(config) {
2553
2825
  }
2554
2826
  return {
2555
2827
  $allModels: {
2556
- guard(input) {
2828
+ guard(input, caller) {
2557
2829
  const modelName = this.$name;
2558
- const delegateKey = modelName[0].toLowerCase() + modelName.slice(1);
2830
+ const delegateKey = toDelegateKey(modelName);
2559
2831
  const modelDelegate = this.$parent[delegateKey];
2560
2832
  if (!modelDelegate) {
2561
2833
  throw new ShapeError(
2562
2834
  `Could not resolve Prisma delegate for model "${modelName}" (key: "${delegateKey}")`
2563
2835
  );
2564
2836
  }
2565
- const methods = createGuardedMethods(modelName, modelDelegate, input);
2837
+ const methods = createGuardedMethods(modelName, modelDelegate, input, caller);
2566
2838
  if (!wrapZodErrors)
2567
2839
  return methods;
2568
2840
  return wrapMethods(methods);
@@ -2572,12 +2844,6 @@ function createModelGuardExtension(config) {
2572
2844
  }
2573
2845
 
2574
2846
  // src/runtime/guard.ts
2575
- function formatZodError2(err) {
2576
- return err.issues.map((i) => {
2577
- const p = i.path.length > 0 ? `${i.path.join(".")}: ` : "";
2578
- return `${p}${i.message}`;
2579
- }).join("; ");
2580
- }
2581
2847
  function createGuard(config) {
2582
2848
  const schemaBuilder = createSchemaBuilder(
2583
2849
  config.typeMap,
@@ -2593,7 +2859,7 @@ function createGuard(config) {
2593
2859
  const wrapZodErrors = config.wrapZodErrors ?? false;
2594
2860
  function rethrowZod(err) {
2595
2861
  if (err instanceof ZodError) {
2596
- throw new ShapeError(`Validation failed: ${formatZodError2(err)}`, { cause: err });
2862
+ throw new ShapeError(`Validation failed: ${formatZodError(err)}`, { cause: err });
2597
2863
  }
2598
2864
  throw err;
2599
2865
  }
@@ -2630,16 +2896,24 @@ function createGuard(config) {
2630
2896
  };
2631
2897
  },
2632
2898
  extension: (contextFn) => {
2899
+ const scopeRoots = /* @__PURE__ */ new Set();
2900
+ for (const entries of Object.values(config.scopeMap)) {
2901
+ for (const entry of entries) {
2902
+ scopeRoots.add(entry.root);
2903
+ }
2904
+ }
2633
2905
  const scopeCtxFn = () => {
2634
- const ctx = contextFn();
2906
+ const ctx = validateContext(contextFn());
2635
2907
  const scopeCtx = {};
2636
2908
  for (const key of Object.keys(ctx)) {
2909
+ if (!scopeRoots.has(key))
2910
+ continue;
2637
2911
  const val = ctx[key];
2638
2912
  if (typeof val === "string" || typeof val === "number" || typeof val === "bigint") {
2639
2913
  scopeCtx[key] = val;
2640
2914
  } else if (val !== null && val !== void 0) {
2641
2915
  log.warn(
2642
- `prisma-guard: Context key "${key}" has non-primitive value (${typeof val}). Only string, number, and bigint values are used for scope context.`
2916
+ `prisma-guard: Scope root "${key}" has non-primitive value (${typeof val}). Only string, number, and bigint values are used for scope context.`
2643
2917
  );
2644
2918
  }
2645
2919
  }
@@ -2655,6 +2929,7 @@ function createGuard(config) {
2655
2929
  typeMap: config.typeMap,
2656
2930
  enumMap: config.enumMap,
2657
2931
  zodChains: config.zodChains,
2932
+ zodDefaults: config.zodDefaults ?? {},
2658
2933
  uniqueMap: config.uniqueMap ?? {},
2659
2934
  scopeMap: config.scopeMap,
2660
2935
  contextFn,