prisma-guard 1.20.0 → 1.21.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.
@@ -57,11 +57,92 @@ var CallerError = class extends Error {
57
57
  this.name = "CallerError";
58
58
  }
59
59
  };
60
+ function formatIssue(issue) {
61
+ const path = issue.path.length > 0 ? `${issue.path.join(".")}: ` : "";
62
+ const code = issue.code;
63
+ if (code === "invalid_union") {
64
+ const unionErrors = issue.unionErrors;
65
+ if (unionErrors && unionErrors.length > 0) {
66
+ const branches = unionErrors.map((ue, i) => {
67
+ const nested = ue.issues.map(formatIssue).join(", ");
68
+ return `branch ${i + 1}: [${nested}]`;
69
+ }).join(" | ");
70
+ return `${path}No matching variant (${branches})`;
71
+ }
72
+ return `${path}No matching variant`;
73
+ }
74
+ if (issue.code === "unrecognized_keys") {
75
+ const keys = issue.keys;
76
+ if (keys && keys.length > 0) {
77
+ return `${path}Unrecognized key(s): ${keys.join(", ")}`;
78
+ }
79
+ }
80
+ if (issue.code === "invalid_type") {
81
+ const expected = issue.expected;
82
+ const received = issue.received;
83
+ if (expected && received) {
84
+ return `${path}Expected ${expected}, received ${received}`;
85
+ }
86
+ }
87
+ if (code === "invalid_enum_value") {
88
+ const options = issue.options;
89
+ if (options) {
90
+ return `${path}Invalid value. Expected one of: ${options.join(", ")}`;
91
+ }
92
+ }
93
+ if (code === "too_small") {
94
+ const minimum = issue.minimum;
95
+ const type = issue.type;
96
+ if (type === "string" && minimum !== void 0) {
97
+ return `${path}String must contain at least ${minimum} character(s)`;
98
+ }
99
+ if (type === "array" && minimum !== void 0) {
100
+ return `${path}Array must contain at least ${minimum} element(s)`;
101
+ }
102
+ if (type === "number" && minimum !== void 0) {
103
+ return `${path}Number must be >= ${minimum}`;
104
+ }
105
+ return `${path}${issue.message}`;
106
+ }
107
+ if (code === "too_big") {
108
+ const maximum = issue.maximum;
109
+ const type = issue.type;
110
+ if (type === "string" && maximum !== void 0) {
111
+ return `${path}String must contain at most ${maximum} character(s)`;
112
+ }
113
+ if (type === "array" && maximum !== void 0) {
114
+ return `${path}Array must contain at most ${maximum} element(s)`;
115
+ }
116
+ if (type === "number" && maximum !== void 0) {
117
+ return `${path}Number must be <= ${maximum}`;
118
+ }
119
+ return `${path}${issue.message}`;
120
+ }
121
+ if (code === "invalid_format") {
122
+ const format = issue.format;
123
+ if (format) {
124
+ return `${path}Invalid ${format} format`;
125
+ }
126
+ }
127
+ if (code === "invalid_value") {
128
+ const values = issue.values;
129
+ if (values) {
130
+ return `${path}Invalid value. Expected one of: ${values.join(", ")}`;
131
+ }
132
+ }
133
+ return `${path}${issue.message}`;
134
+ }
60
135
  function formatZodError(err) {
61
- return err.issues.map((i) => {
62
- const p = i.path.length > 0 ? `${i.path.join(".")}: ` : "";
63
- return `${p}${i.message}`;
64
- }).join("; ");
136
+ return err.issues.map(formatIssue).join("; ");
137
+ }
138
+ function wrapParseError(err, context) {
139
+ if (err instanceof ShapeError) {
140
+ throw new ShapeError(`${context}: ${err.message}`, { cause: err });
141
+ }
142
+ if (err && typeof err === "object" && "issues" in err) {
143
+ throw new ShapeError(`${context}: ${formatZodError(err)}`, { cause: err });
144
+ }
145
+ throw err;
65
146
  }
66
147
 
67
148
  // src/shared/scalar-base.ts
@@ -207,15 +288,19 @@ function coerceToArray(value) {
207
288
  return value;
208
289
  const keys = Object.keys(value);
209
290
  if (keys.length === 0)
210
- return [];
291
+ return value;
211
292
  const allNumeric = keys.every((k) => /^\d+$/.test(k));
212
293
  if (!allNumeric)
213
294
  return value;
214
- const sorted = keys.map(Number).sort((a, b) => a - b);
295
+ const indices = keys.map(Number).sort((a, b) => a - b);
296
+ for (let i = 0; i < indices.length; i++) {
297
+ if (indices[i] !== i)
298
+ return value;
299
+ }
215
300
  const obj = value;
216
- const result = [];
217
- for (const idx of sorted) {
218
- result.push(obj[String(idx)]);
301
+ const result = new Array(indices.length);
302
+ for (let i = 0; i < indices.length; i++) {
303
+ result[i] = obj[String(i)];
219
304
  }
220
305
  return result;
221
306
  }
@@ -233,7 +318,8 @@ var SCALAR_OPERATORS = {
233
318
  "gt",
234
319
  "gte",
235
320
  "lt",
236
- "lte"
321
+ "lte",
322
+ "search"
237
323
  ]),
238
324
  Int: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
239
325
  Float: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
@@ -335,7 +421,7 @@ function createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase
335
421
  }
336
422
  function createJsonOperatorSchema(fieldMeta, operator) {
337
423
  const jsonValue = import_zod2.z.unknown();
338
- if (operator === "equals" || operator === "not") {
424
+ if (operator === "equals") {
339
425
  return !fieldMeta.isRequired ? import_zod2.z.union([jsonValue, import_zod2.z.null()]) : jsonValue;
340
426
  }
341
427
  if (operator === "path") {
@@ -351,6 +437,29 @@ function createJsonOperatorSchema(fieldMeta, operator) {
351
437
  `Operator "${operator}" not supported for Json fields`
352
438
  );
353
439
  }
440
+ function buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase) {
441
+ const allOps = getSupportedOperators(fieldMeta);
442
+ const nestedOps = allOps.filter((o) => o !== "not");
443
+ if (nestedOps.length === 0)
444
+ return scalarSchema;
445
+ const nestedSchemas = {};
446
+ for (const op of nestedOps) {
447
+ nestedSchemas[op] = createOperatorSchema(
448
+ fieldMeta,
449
+ op,
450
+ enumMap,
451
+ scalarBase
452
+ ).optional();
453
+ }
454
+ const nestedKeys = Object.keys(nestedSchemas);
455
+ const nestedObj = import_zod2.z.object(nestedSchemas).strict().refine(
456
+ (v) => nestedKeys.some(
457
+ (k) => v[k] !== void 0
458
+ ),
459
+ { message: "not filter must specify at least one operator" }
460
+ );
461
+ return import_zod2.z.union([scalarSchema, nestedObj]);
462
+ }
354
463
  function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
355
464
  if (fieldMeta.isList) {
356
465
  return createScalarListOperatorSchema(
@@ -371,9 +480,13 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
371
480
  );
372
481
  }
373
482
  const enumSchema = import_zod2.z.enum(values);
374
- if (operator === "equals" || operator === "not") {
483
+ if (operator === "equals") {
375
484
  return !fieldMeta.isRequired ? import_zod2.z.union([enumSchema, import_zod2.z.null()]) : enumSchema;
376
485
  }
486
+ if (operator === "not") {
487
+ const scalarSchema = !fieldMeta.isRequired ? import_zod2.z.union([enumSchema, import_zod2.z.null()]) : enumSchema;
488
+ return buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase);
489
+ }
377
490
  const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([enumSchema, import_zod2.z.null()]) : enumSchema;
378
491
  return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(itemSchema));
379
492
  }
@@ -384,6 +497,11 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
384
497
  `Operator "${operator}" not supported for type "Json"`
385
498
  );
386
499
  }
500
+ if (operator === "not") {
501
+ const jsonValue = import_zod2.z.unknown();
502
+ const scalarSchema = !fieldMeta.isRequired ? import_zod2.z.union([jsonValue, import_zod2.z.null()]) : jsonValue;
503
+ return buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase);
504
+ }
387
505
  return createJsonOperatorSchema(fieldMeta, operator);
388
506
  }
389
507
  const supportedOps = SCALAR_OPERATORS[fieldMeta.type];
@@ -406,9 +524,13 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
406
524
  }
407
525
  const scalar = factory();
408
526
  const coerced = wrapWithInputCoercion(fieldMeta.type, false, scalar);
409
- if (operator === "equals" || operator === "not") {
527
+ if (operator === "equals") {
410
528
  return !fieldMeta.isRequired ? import_zod2.z.union([coerced, import_zod2.z.null()]) : coerced;
411
529
  }
530
+ if (operator === "not") {
531
+ const scalarSchema = !fieldMeta.isRequired ? import_zod2.z.union([coerced, import_zod2.z.null()]) : coerced;
532
+ return buildNotFilterSchema(fieldMeta, scalarSchema, enumMap, scalarBase);
533
+ }
412
534
  if (operator === "in" || operator === "notIn") {
413
535
  const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([coerced, import_zod2.z.null()]) : coerced;
414
536
  return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(itemSchema));
@@ -817,6 +939,8 @@ function deepClone(value) {
817
939
  return new Date(value.getTime());
818
940
  if (value instanceof Uint8Array)
819
941
  return value.slice();
942
+ if (value instanceof RegExp)
943
+ return new RegExp(value.source, value.flags);
820
944
  if (Array.isArray(value))
821
945
  return value.map(deepClone);
822
946
  const proto = Object.getPrototypeOf(value);
@@ -834,7 +958,10 @@ function deepClone(value) {
834
958
  }
835
959
 
836
960
  // src/runtime/query-builder-forced.ts
837
- var EMPTY_WHERE_FORCED = { conditions: {}, relations: {} };
961
+ var EMPTY_WHERE_FORCED = {
962
+ conditions: {},
963
+ relations: {}
964
+ };
838
965
  function hasWhereForced(f) {
839
966
  return Object.keys(f.conditions).length > 0 || Object.keys(f.relations).length > 0;
840
967
  }
@@ -894,7 +1021,7 @@ function mergeUniqueWhereForced(where, forced) {
894
1021
  }
895
1022
  return result;
896
1023
  }
897
- function applyBuiltShape(built, body, isUniqueMethod) {
1024
+ function applyBuiltShape(built, body, isUniqueMethod, modelName) {
898
1025
  let parseable = body;
899
1026
  const hasWhereInSchema = "where" in built.zodSchema.shape;
900
1027
  if (isPlainObject(body)) {
@@ -920,7 +1047,20 @@ function applyBuiltShape(built, body, isUniqueMethod) {
920
1047
  }
921
1048
  }
922
1049
  }
923
- const validated = built.zodSchema.parse(parseable);
1050
+ let validated;
1051
+ try {
1052
+ validated = built.zodSchema.parse(parseable);
1053
+ } catch (err) {
1054
+ if (err instanceof ShapeError)
1055
+ throw err;
1056
+ if (err && typeof err === "object" && "issues" in err) {
1057
+ const context = modelName ? `Invalid query on model "${modelName}"` : "Invalid query";
1058
+ throw new ShapeError(`${context}: ${formatZodError(err)}`, {
1059
+ cause: err
1060
+ });
1061
+ }
1062
+ throw err;
1063
+ }
924
1064
  if (hasWhereForced(built.forcedWhere)) {
925
1065
  validated.where = isUniqueMethod ? mergeUniqueWhereForced(
926
1066
  validated.where,
@@ -1295,7 +1435,8 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1295
1435
  model,
1296
1436
  fieldSchemas,
1297
1437
  relationForced,
1298
- currentDepth
1438
+ currentDepth,
1439
+ scalarConditions
1299
1440
  );
1300
1441
  continue;
1301
1442
  }
@@ -1377,7 +1518,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1377
1518
  }
1378
1519
  }
1379
1520
  }
1380
- function processRelationFilter(key, value, fieldMeta, model, fieldSchemas, parentRelations, depth) {
1521
+ function processRelationFilter(key, value, fieldMeta, model, fieldSchemas, parentRelations, depth, parentConditions) {
1381
1522
  if (!isPlainObject(value)) {
1382
1523
  throw new ShapeError(
1383
1524
  `Relation filter for "${key}" must be an object with operators (some, every, none, is, isNot)`
@@ -1392,6 +1533,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1392
1533
  const opSchemas = {};
1393
1534
  const opForced = {};
1394
1535
  let hasClientOps = false;
1536
+ let hasForcedNull = false;
1395
1537
  for (const [op, opValue] of Object.entries(value)) {
1396
1538
  if (!allowedOps.has(op)) {
1397
1539
  const allowed = [...allowedOps].join(", ");
@@ -1399,9 +1541,24 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1399
1541
  `Operator "${op}" not supported for ${fieldMeta.isList ? "to-many" : "to-one"} relation "${key}". Allowed: ${allowed}`
1400
1542
  );
1401
1543
  }
1544
+ if (opValue === null) {
1545
+ if (!TO_ONE_RELATION_OPS.has(op)) {
1546
+ throw new ShapeError(
1547
+ `Null value for operator "${op}" is only valid on to-one relation operators (is, isNot), not on "${key}"`
1548
+ );
1549
+ }
1550
+ const existing = parentConditions[key];
1551
+ if (existing && isPlainObject(existing)) {
1552
+ existing[op] = null;
1553
+ } else {
1554
+ parentConditions[key] = { [op]: null };
1555
+ }
1556
+ hasForcedNull = true;
1557
+ continue;
1558
+ }
1402
1559
  if (!isPlainObject(opValue)) {
1403
1560
  throw new ShapeError(
1404
- `Relation filter operator "${op}" on "${key}" must be an object defining nested where fields`
1561
+ `Relation filter operator "${op}" on "${key}" must be an object defining nested where fields, or null for to-one existence checks`
1405
1562
  );
1406
1563
  }
1407
1564
  const nested = buildWhereSchema(fieldMeta.type, opValue, depth + 1);
@@ -1427,7 +1584,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1427
1584
  opForced[op] = nested.forced;
1428
1585
  }
1429
1586
  }
1430
- if (!hasClientOps && Object.keys(opForced).length === 0) {
1587
+ if (!hasClientOps && Object.keys(opForced).length === 0 && !hasForcedNull) {
1431
1588
  throw new ShapeError(
1432
1589
  `Relation filter for "${key}" on model "${model}" produced no conditions. Define at least one nested field in the operator shape.`
1433
1590
  );
@@ -1435,7 +1592,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1435
1592
  if (hasClientOps) {
1436
1593
  const clientOpKeys = Object.keys(opSchemas);
1437
1594
  const opObjSchema = import_zod4.z.object(opSchemas).strict();
1438
- if (Object.keys(opForced).length === 0) {
1595
+ if (Object.keys(opForced).length === 0 && !hasForcedNull) {
1439
1596
  fieldSchemas[key] = opObjSchema.refine(
1440
1597
  (v) => clientOpKeys.some(
1441
1598
  (k) => v[k] !== void 0
@@ -1737,25 +1894,26 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
1737
1894
  return import_zod5.z.union([singleSchema, import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(singleSchema).min(1))]).optional();
1738
1895
  }
1739
1896
  function buildTakeSchema(config) {
1740
- if (!Number.isFinite(config.max) || !Number.isInteger(config.max)) {
1741
- throw new ShapeError(`take max must be a finite integer, got ${config.max}`);
1897
+ const normalized = typeof config === "number" ? { max: config, default: config } : config;
1898
+ if (!Number.isFinite(normalized.max) || !Number.isInteger(normalized.max)) {
1899
+ throw new ShapeError(`take max must be a finite integer, got ${normalized.max}`);
1742
1900
  }
1743
- if (config.max < 1) {
1744
- throw new ShapeError(`take max must be at least 1, got ${config.max}`);
1901
+ if (normalized.max < 1) {
1902
+ throw new ShapeError(`take max must be at least 1, got ${normalized.max}`);
1745
1903
  }
1746
- if (config.default !== void 0) {
1747
- if (!Number.isFinite(config.default) || !Number.isInteger(config.default)) {
1748
- throw new ShapeError(`take default must be a finite integer, got ${config.default}`);
1904
+ if (normalized.default !== void 0) {
1905
+ if (!Number.isFinite(normalized.default) || !Number.isInteger(normalized.default)) {
1906
+ throw new ShapeError(`take default must be a finite integer, got ${normalized.default}`);
1749
1907
  }
1750
- if (config.default < 1) {
1751
- throw new ShapeError(`take default must be at least 1, got ${config.default}`);
1908
+ if (normalized.default < 1) {
1909
+ throw new ShapeError(`take default must be at least 1, got ${normalized.default}`);
1752
1910
  }
1753
- if (config.default > config.max) {
1911
+ if (normalized.default > normalized.max) {
1754
1912
  throw new ShapeError("take default cannot exceed max");
1755
1913
  }
1756
- return import_zod5.z.number().int().min(1).max(config.max).default(config.default);
1914
+ return import_zod5.z.number().int().min(1).max(normalized.max).default(normalized.default);
1757
1915
  }
1758
- return import_zod5.z.number().int().min(1).max(config.max).optional();
1916
+ return import_zod5.z.number().int().min(1).max(normalized.max).optional();
1759
1917
  }
1760
1918
  function buildCursorSchema(model, cursorConfig) {
1761
1919
  const modelFields = typeMap[model];
@@ -1862,10 +2020,21 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
1862
2020
  ).optional();
1863
2021
  }
1864
2022
  const havingFieldKeys = Object.keys(fieldSchemas);
1865
- return import_zod5.z.object(fieldSchemas).strict().refine(
1866
- (v) => havingFieldKeys.some((k) => v[k] !== void 0),
1867
- { message: "having must specify at least one field" }
1868
- ).optional();
2023
+ const havingSchema = import_zod5.z.lazy(() => {
2024
+ const allSchemas = { ...fieldSchemas };
2025
+ allSchemas["AND"] = import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(havingSchema).min(1)).optional();
2026
+ allSchemas["OR"] = import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(havingSchema).min(1)).optional();
2027
+ allSchemas["NOT"] = import_zod5.z.union([
2028
+ havingSchema,
2029
+ import_zod5.z.preprocess(coerceToArray, import_zod5.z.array(havingSchema).min(1))
2030
+ ]).optional();
2031
+ const allKeys = [...havingFieldKeys, "AND", "OR", "NOT"];
2032
+ return import_zod5.z.object(allSchemas).strict().refine(
2033
+ (v) => allKeys.some((k) => v[k] !== void 0),
2034
+ { message: "having must specify at least one field or combinator" }
2035
+ );
2036
+ });
2037
+ return havingSchema.optional();
1869
2038
  }
1870
2039
  function buildAggregateFieldSchema(model, opName, fieldConfig) {
1871
2040
  const modelFields = typeMap[model];
@@ -2637,6 +2806,17 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2637
2806
  return null;
2638
2807
  return { key: matched, shape: shapes[matched] };
2639
2808
  }
2809
+ function resolveDefaultShape(config, model, method, normalizedBody, opts, builtCache, isUnique) {
2810
+ const shapeOrFn = config["default"];
2811
+ let built;
2812
+ if (typeof shapeOrFn === "function") {
2813
+ const resolved = resolveAndValidateShape(shapeOrFn, opts?.ctx);
2814
+ built = buildShapeZodSchema(model, method, resolved);
2815
+ } else {
2816
+ built = builtCache.get("default");
2817
+ }
2818
+ return applyBuiltShape(built, normalizedBody, isUnique);
2819
+ }
2640
2820
  function buildQuerySchema(model, method, config) {
2641
2821
  const isSingle = typeof config === "function" || isShapeConfig(config);
2642
2822
  const builtCache = /* @__PURE__ */ new Map();
@@ -2688,23 +2868,39 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2688
2868
  "Pass caller via opts.caller, not in the request body."
2689
2869
  );
2690
2870
  }
2871
+ const namedConfig = config;
2691
2872
  const caller = opts?.caller;
2692
2873
  if (typeof caller !== "string") {
2693
- const allowed = Object.keys(
2694
- config
2695
- );
2874
+ if ("default" in namedConfig) {
2875
+ return resolveDefaultShape(
2876
+ namedConfig,
2877
+ model,
2878
+ method,
2879
+ normalizedBody,
2880
+ opts,
2881
+ builtCache,
2882
+ isUnique
2883
+ );
2884
+ }
2885
+ const allowed = Object.keys(namedConfig);
2696
2886
  throw new CallerError(
2697
2887
  `Missing caller. This query uses named shape routing with keys: ${allowed.map((k) => `"${k}"`).join(", ")}. Provide caller via opts.caller.`
2698
2888
  );
2699
2889
  }
2700
- const matched = matchCaller(
2701
- config,
2702
- caller
2703
- );
2890
+ const matched = matchCaller(namedConfig, caller);
2704
2891
  if (!matched) {
2705
- const allowed = Object.keys(
2706
- config
2707
- );
2892
+ if ("default" in namedConfig) {
2893
+ return resolveDefaultShape(
2894
+ namedConfig,
2895
+ model,
2896
+ method,
2897
+ normalizedBody,
2898
+ opts,
2899
+ builtCache,
2900
+ isUnique
2901
+ );
2902
+ }
2903
+ const allowed = Object.keys(namedConfig);
2708
2904
  throw new CallerError(
2709
2905
  `Unknown caller: "${caller}". Allowed: ${allowed.map((k) => `"${k}"`).join(", ")}`
2710
2906
  );
@@ -2737,23 +2933,10 @@ var READ_OPS = /* @__PURE__ */ new Set([
2737
2933
  "findFirstOrThrow",
2738
2934
  "count"
2739
2935
  ]);
2740
- var AGGREGATE_OPS = /* @__PURE__ */ new Set([
2741
- "aggregate",
2742
- "groupBy"
2743
- ]);
2744
- var FIND_UNIQUE_OPS = /* @__PURE__ */ new Set([
2745
- "findUnique",
2746
- "findUniqueOrThrow"
2747
- ]);
2748
- var CREATE_OPS = /* @__PURE__ */ new Set([
2749
- "create",
2750
- "createMany",
2751
- "createManyAndReturn"
2752
- ]);
2753
- var UNIQUE_MUTATION_OPS = /* @__PURE__ */ new Set([
2754
- "update",
2755
- "delete"
2756
- ]);
2936
+ var AGGREGATE_OPS = /* @__PURE__ */ new Set(["aggregate", "groupBy"]);
2937
+ var FIND_UNIQUE_OPS = /* @__PURE__ */ new Set(["findUnique", "findUniqueOrThrow"]);
2938
+ var CREATE_OPS = /* @__PURE__ */ new Set(["create", "createMany", "createManyAndReturn"]);
2939
+ var UNIQUE_MUTATION_OPS = /* @__PURE__ */ new Set(["update", "delete"]);
2757
2940
  var MULTI_MUTATION_OPS = /* @__PURE__ */ new Set([
2758
2941
  "updateMany",
2759
2942
  "updateManyAndReturn",
@@ -2882,7 +3065,9 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2882
3065
  for (const s of presentScopes) {
2883
3066
  validateScopeValue(s.root, ctx[s.root]);
2884
3067
  }
2885
- const presentConditions = presentScopes.map((s) => ({ [s.fk]: ctx[s.root] }));
3068
+ const presentConditions = presentScopes.map((s) => ({
3069
+ [s.fk]: ctx[s.root]
3070
+ }));
2886
3071
  const missingRoots = scopes.filter((s) => ctx[s.root] == null).map((s) => s.root);
2887
3072
  const isMutation = CREATE_OPS.has(operation) || UNIQUE_MUTATION_OPS.has(operation) || MULTI_MUTATION_OPS.has(operation) || operation === "upsert";
2888
3073
  if (missingRoots.length > 0) {
@@ -2912,14 +3097,32 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2912
3097
  throw new ShapeError(`upsert expects create to be an object`);
2913
3098
  }
2914
3099
  nextArgs.create = { ...args.create };
2915
- enforceDataScope(nextArgs.create, scopes, overrides, log, model, operation, onScopeRelationWrite, "create");
3100
+ enforceDataScope(
3101
+ nextArgs.create,
3102
+ scopes,
3103
+ overrides,
3104
+ log,
3105
+ model,
3106
+ operation,
3107
+ onScopeRelationWrite,
3108
+ "create"
3109
+ );
2916
3110
  }
2917
3111
  if (args.update !== void 0 && args.update !== null) {
2918
3112
  if (typeof args.update !== "object" || Array.isArray(args.update)) {
2919
3113
  throw new ShapeError(`upsert expects update to be an object`);
2920
3114
  }
2921
3115
  nextArgs.update = { ...args.update };
2922
- enforceDataScope(nextArgs.update, scopes, overrides, log, model, operation, onScopeRelationWrite, "mutate");
3116
+ enforceDataScope(
3117
+ nextArgs.update,
3118
+ scopes,
3119
+ overrides,
3120
+ log,
3121
+ model,
3122
+ operation,
3123
+ onScopeRelationWrite,
3124
+ "mutate"
3125
+ );
2923
3126
  }
2924
3127
  return query(nextArgs);
2925
3128
  }
@@ -2929,7 +3132,15 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2929
3132
  `Scoped model "${model}" does not allow ${operation} via scope extension (findUniqueMode is "reject"). Use findFirst with explicit where conditions instead.`
2930
3133
  );
2931
3134
  }
2932
- return handleFindUnique(args, query, conditions, scopes, operation, log);
3135
+ return handleFindUnique(
3136
+ args,
3137
+ query,
3138
+ conditions,
3139
+ scopes,
3140
+ operation,
3141
+ log,
3142
+ model
3143
+ );
2933
3144
  }
2934
3145
  if (READ_OPS.has(operation)) {
2935
3146
  nextArgs.where = buildAndConditions(args.where, conditions);
@@ -2957,7 +3168,16 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2957
3168
  }
2958
3169
  nextArgs.data = args.data.map((d) => {
2959
3170
  const item = { ...d };
2960
- enforceDataScope(item, scopes, overrides, log, model, operation, onScopeRelationWrite, "create");
3171
+ enforceDataScope(
3172
+ item,
3173
+ scopes,
3174
+ overrides,
3175
+ log,
3176
+ model,
3177
+ operation,
3178
+ onScopeRelationWrite,
3179
+ "create"
3180
+ );
2961
3181
  return item;
2962
3182
  });
2963
3183
  } else {
@@ -2965,7 +3185,16 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2965
3185
  throw new ShapeError(`${operation} expects data to be an object`);
2966
3186
  }
2967
3187
  nextArgs.data = { ...args.data };
2968
- enforceDataScope(nextArgs.data, scopes, overrides, log, model, operation, onScopeRelationWrite, "create");
3188
+ enforceDataScope(
3189
+ nextArgs.data,
3190
+ scopes,
3191
+ overrides,
3192
+ log,
3193
+ model,
3194
+ operation,
3195
+ onScopeRelationWrite,
3196
+ "create"
3197
+ );
2969
3198
  }
2970
3199
  return query(nextArgs);
2971
3200
  }
@@ -2976,7 +3205,16 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2976
3205
  throw new ShapeError(`${operation} expects data to be an object`);
2977
3206
  }
2978
3207
  nextArgs.data = { ...args.data };
2979
- enforceDataScope(nextArgs.data, scopes, overrides, log, model, operation, onScopeRelationWrite, "mutate");
3208
+ enforceDataScope(
3209
+ nextArgs.data,
3210
+ scopes,
3211
+ overrides,
3212
+ log,
3213
+ model,
3214
+ operation,
3215
+ onScopeRelationWrite,
3216
+ "mutate"
3217
+ );
2980
3218
  }
2981
3219
  return query(nextArgs);
2982
3220
  }
@@ -2987,7 +3225,16 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2987
3225
  throw new ShapeError(`${operation} expects data to be an object`);
2988
3226
  }
2989
3227
  nextArgs.data = { ...args.data };
2990
- enforceDataScope(nextArgs.data, scopes, overrides, log, model, operation, onScopeRelationWrite, "mutate");
3228
+ enforceDataScope(
3229
+ nextArgs.data,
3230
+ scopes,
3231
+ overrides,
3232
+ log,
3233
+ model,
3234
+ operation,
3235
+ onScopeRelationWrite,
3236
+ "mutate"
3237
+ );
2991
3238
  }
2992
3239
  return query(nextArgs);
2993
3240
  }
@@ -2998,7 +3245,7 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
2998
3245
  }
2999
3246
  };
3000
3247
  }
3001
- async function handleFindUnique(args, query, conditions, scopes, operation, log) {
3248
+ async function handleFindUnique(args, query, conditions, scopes, operation, log, model) {
3002
3249
  const nextArgs = { ...args };
3003
3250
  const injectedFks = [];
3004
3251
  const originalSelect = args?.select;
@@ -3016,7 +3263,9 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log)
3016
3263
  if (result === null)
3017
3264
  return result;
3018
3265
  if (typeof result !== "object" || result === null) {
3019
- throw new ShapeError("findUnique result must be an object or null");
3266
+ throw new ShapeError(
3267
+ `${operation} on model "${model}" returned a non-object, non-null result`
3268
+ );
3020
3269
  }
3021
3270
  const resultObj = result;
3022
3271
  let verifyObj = resultObj;
@@ -3025,22 +3274,29 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log)
3025
3274
  const where = args?.where;
3026
3275
  if (!where || typeof where !== "object" || Array.isArray(where)) {
3027
3276
  throw new PolicyError(
3028
- `prisma-guard: Cannot verify scope \u2014 missing FK fields (${missingFks.join(", ")}) and findUnique args.where is not a valid object.`
3277
+ `prisma-guard: Cannot verify scope on model "${model}" for ${operation} \u2014 missing FK fields (${missingFks.join(", ")}) in result and args.where is not a valid object. Ensure the where clause is a plain object so the verification query can re-fetch FK values.`
3029
3278
  );
3030
3279
  }
3031
3280
  let verifyResult;
3032
3281
  try {
3033
3282
  verifyResult = await query({ where, select: buildFkSelect(fks) });
3034
3283
  } catch (err) {
3284
+ log.warn(
3285
+ `prisma-guard: Scope verification re-query failed for ${operation} on model "${model}": ${err?.message ?? String(err)}`
3286
+ );
3035
3287
  throw new PolicyError(
3036
- `prisma-guard: Scope verification query failed for findUnique: ${err?.message ?? String(err)}`
3288
+ `prisma-guard: Scope verification re-query failed for ${operation} on model "${model}". The re-query to fetch FK fields (${fks.join(", ")}) returned a database error. Check server logs for the underlying cause.`
3037
3289
  );
3038
3290
  }
3039
3291
  if (verifyResult === null) {
3040
- throw new PolicyError("prisma-guard: Scope verification query returned null for an existing findUnique result");
3292
+ throw new PolicyError(
3293
+ `prisma-guard: Scope verification re-query on model "${model}" returned null for an existing ${operation} result. The record may have been deleted between the original query and verification.`
3294
+ );
3041
3295
  }
3042
3296
  if (typeof verifyResult !== "object" || verifyResult === null) {
3043
- throw new PolicyError("prisma-guard: Scope verification result must be an object");
3297
+ throw new PolicyError(
3298
+ `prisma-guard: Scope verification re-query on model "${model}" returned a non-object result.`
3299
+ );
3044
3300
  }
3045
3301
  verifyObj = verifyResult;
3046
3302
  }
@@ -3048,12 +3304,14 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log)
3048
3304
  const [fk, value] = Object.entries(condition)[0];
3049
3305
  if (!(fk in verifyObj)) {
3050
3306
  throw new PolicyError(
3051
- `prisma-guard: Cannot verify scope on "${fk}" \u2014 field not present in verification result. Ensure FK fields are selectable.`
3307
+ `prisma-guard: Cannot verify scope on model "${model}" \u2014 FK field "${fk}" not present in verification result. Ensure "${fk}" is selectable on model "${model}" (not excluded by select or field-level access).`
3052
3308
  );
3053
3309
  }
3054
3310
  if (!looseEqual(verifyObj[fk], value, log, fk)) {
3055
3311
  if (operation === "findUniqueOrThrow") {
3056
- throw new PolicyError("Record not accessible in current scope");
3312
+ throw new PolicyError(
3313
+ `Record on model "${model}" not accessible in current scope`
3314
+ );
3057
3315
  }
3058
3316
  return null;
3059
3317
  }
@@ -3758,11 +4016,22 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
3758
4016
  forced
3759
4017
  };
3760
4018
  }
3761
- function validateAndMergeData(bodyData, cached, method) {
4019
+ function validateAndMergeData(bodyData, cached, method, modelName) {
3762
4020
  if (bodyData === void 0 || bodyData === null) {
3763
4021
  throw new ShapeError(`${method} requires "data" in request body`);
3764
4022
  }
3765
- const validated = cached.schema.parse(bodyData);
4023
+ let validated;
4024
+ try {
4025
+ validated = cached.schema.parse(bodyData);
4026
+ } catch (err) {
4027
+ if (err instanceof ShapeError)
4028
+ throw err;
4029
+ if (err && typeof err === "object" && "issues" in err) {
4030
+ const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
4031
+ throw new ShapeError(`${context}: ${formatZodError(err)}`, { cause: err });
4032
+ }
4033
+ throw err;
4034
+ }
3766
4035
  return { ...validated, ...deepClone(cached.forced) };
3767
4036
  }
3768
4037
  function hasDataRefines(dataConfig) {
@@ -3832,14 +4101,26 @@ function resolveShape(input, body, contextFn, caller) {
3832
4101
  );
3833
4102
  }
3834
4103
  if (typeof caller !== "string") {
4104
+ if ("default" in namedMap) {
4105
+ const shapeOrFn2 = namedMap["default"];
4106
+ const wasDynamic2 = typeof shapeOrFn2 === "function";
4107
+ const shape2 = wasDynamic2 ? resolveDynamicShape(shapeOrFn2, contextFn) : shapeOrFn2;
4108
+ return { shape: shape2, body: parsed, matchedKey: "default", wasDynamic: wasDynamic2 };
4109
+ }
3835
4110
  const patterns2 = Object.keys(namedMap);
3836
4111
  throw new CallerError(
3837
- `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.`
4112
+ `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, or add a "default" variant.`
3838
4113
  );
3839
4114
  }
3840
4115
  const patterns = Object.keys(namedMap);
3841
4116
  const matched = matchCallerPattern(patterns, caller);
3842
4117
  if (!matched) {
4118
+ if ("default" in namedMap) {
4119
+ const shapeOrFn2 = namedMap["default"];
4120
+ const wasDynamic2 = typeof shapeOrFn2 === "function";
4121
+ const shape2 = wasDynamic2 ? resolveDynamicShape(shapeOrFn2, contextFn) : shapeOrFn2;
4122
+ return { shape: shape2, body: parsed, matchedKey: "default", wasDynamic: wasDynamic2 };
4123
+ }
3843
4124
  throw new CallerError(
3844
4125
  `Unknown caller: "${caller}". Allowed: ${patterns.map((k) => `"${k}"`).join(", ")}`
3845
4126
  );
@@ -4205,7 +4486,10 @@ function createModelGuardExtension(config) {
4205
4486
  const cached = uniqueWhereCache.get(cacheKey);
4206
4487
  if (cached)
4207
4488
  return cached;
4208
- const built = queryBuilder.buildUniqueWhereSchema(modelName, whereConfig);
4489
+ const built = queryBuilder.buildUniqueWhereSchema(
4490
+ modelName,
4491
+ whereConfig
4492
+ );
4209
4493
  uniqueWhereCache.set(cacheKey, built);
4210
4494
  return built;
4211
4495
  }
@@ -4290,7 +4574,15 @@ function createModelGuardExtension(config) {
4290
4574
  } else {
4291
4575
  projectionBody = buildDefaultProjectionBody(shape);
4292
4576
  }
4293
- const validated = projection.zodSchema.parse(projectionBody);
4577
+ let validated;
4578
+ try {
4579
+ validated = projection.zodSchema.parse(projectionBody);
4580
+ } catch (err) {
4581
+ wrapParseError(
4582
+ err,
4583
+ `Invalid select/include projection on model "${modelName}" for ${method}`
4584
+ );
4585
+ }
4294
4586
  if (Object.keys(projection.forcedIncludeTree).length > 0) {
4295
4587
  applyForcedTree(validated, "include", projection.forcedIncludeTree);
4296
4588
  }
@@ -4327,7 +4619,11 @@ function createModelGuardExtension(config) {
4327
4619
  }
4328
4620
  sanitizedWhere = w;
4329
4621
  }
4330
- validatedWhere = built.schema.parse(sanitizedWhere);
4622
+ try {
4623
+ validatedWhere = built.schema.parse(sanitizedWhere);
4624
+ } catch (err) {
4625
+ wrapParseError(err, `Invalid "where" clause on model "${modelName}"`);
4626
+ }
4331
4627
  } else if (bodyWhere !== void 0) {
4332
4628
  if (bodyWhere === null || !isPlainObject(bodyWhere) || Object.keys(bodyWhere).length > 0) {
4333
4629
  let hasOnlyForcedKeys = false;
@@ -4357,7 +4653,10 @@ function createModelGuardExtension(config) {
4357
4653
  wasDynamic
4358
4654
  );
4359
4655
  if (Object.keys(where).length === 0) {
4360
- throw new ShapeError(`${method} requires a where condition`);
4656
+ const expectedFields = shape.where ? Object.keys(shape.where).join(", ") : "none defined";
4657
+ throw new ShapeError(
4658
+ `${method} on model "${modelName}" requires a where condition. Expected fields: ${expectedFields}`
4659
+ );
4361
4660
  }
4362
4661
  return where;
4363
4662
  }
@@ -4369,20 +4668,30 @@ function createModelGuardExtension(config) {
4369
4668
  if (built.schema) {
4370
4669
  if (bodyWhere !== void 0 && bodyWhere !== null) {
4371
4670
  if (!isPlainObject(bodyWhere)) {
4372
- throw new ShapeError("Unique where must be an object");
4671
+ throw new ShapeError(
4672
+ `Invalid "where" on model "${modelName}": unique where must be a plain object`
4673
+ );
4373
4674
  }
4374
4675
  const sanitized = { ...bodyWhere };
4375
4676
  for (const key of built.forcedOnlyKeys) {
4376
4677
  delete sanitized[key];
4377
4678
  }
4378
- result = built.schema.parse(sanitized);
4679
+ try {
4680
+ result = built.schema.parse(sanitized);
4681
+ } catch (err) {
4682
+ const allowedFields = Object.keys(shape.where).join(", ");
4683
+ wrapParseError(
4684
+ err,
4685
+ `Invalid unique "where" on model "${modelName}". Allowed fields: ${allowedFields}`
4686
+ );
4687
+ }
4379
4688
  }
4380
4689
  } else if (bodyWhere !== void 0 && bodyWhere !== null) {
4381
4690
  if (isPlainObject(bodyWhere)) {
4382
4691
  const hasOnlyForcedKeys = built.forcedOnlyKeys.size > 0 && Object.keys(bodyWhere).every((k) => built.forcedOnlyKeys.has(k));
4383
4692
  if (!hasOnlyForcedKeys && Object.keys(bodyWhere).length > 0) {
4384
4693
  throw new ShapeError(
4385
- "Unique where shape contains only forced values. Client where input is not accepted."
4694
+ `Unique where on model "${modelName}" contains only forced values. Client where input is not accepted.`
4386
4695
  );
4387
4696
  }
4388
4697
  }
@@ -4400,7 +4709,12 @@ function createModelGuardExtension(config) {
4400
4709
  wasDynamic
4401
4710
  );
4402
4711
  if (Object.keys(where).length === 0) {
4403
- throw new ShapeError(`${method} requires a where condition`);
4712
+ const constraints = uniqueMap[modelName];
4713
+ const constraintDesc = constraints ? constraints.map((c) => `(${c.join(", ")})`).join(" | ") : "unknown";
4714
+ const expectedFields = shape.where ? Object.keys(shape.where).join(", ") : "none defined";
4715
+ throw new ShapeError(
4716
+ `${method} on model "${modelName}" requires a unique where condition. Unique constraints: ${constraintDesc}. Shape allows: ${expectedFields}`
4717
+ );
4404
4718
  }
4405
4719
  return where;
4406
4720
  }
@@ -4443,7 +4757,7 @@ function createModelGuardExtension(config) {
4443
4757
  );
4444
4758
  const isUnique = UNIQUE_READ_METHODS.has(method);
4445
4759
  const effectiveBody = buildEffectiveReadBody(resolved);
4446
- const args = applyBuiltShape(built, effectiveBody, isUnique);
4760
+ const args = applyBuiltShape(built, effectiveBody, isUnique, modelName);
4447
4761
  if (isUnique && args.where) {
4448
4762
  validateResolvedUniqueWhere(
4449
4763
  modelName,
@@ -4499,7 +4813,8 @@ function createModelGuardExtension(config) {
4499
4813
  const data = validateAndMergeData(
4500
4814
  resolved.body.data,
4501
4815
  dataSchema,
4502
- method
4816
+ method,
4817
+ modelName
4503
4818
  );
4504
4819
  args = { data };
4505
4820
  } else {
@@ -4508,7 +4823,7 @@ function createModelGuardExtension(config) {
4508
4823
  if (resolved.body.data.length === 0)
4509
4824
  throw new ShapeError(`${method} received empty data array`);
4510
4825
  const data = resolved.body.data.map(
4511
- (item) => validateAndMergeData(item, dataSchema, method)
4826
+ (item) => validateAndMergeData(item, dataSchema, method, modelName)
4512
4827
  );
4513
4828
  args = { data };
4514
4829
  }
@@ -4562,7 +4877,8 @@ function createModelGuardExtension(config) {
4562
4877
  const data = validateAndMergeData(
4563
4878
  resolved.body.data,
4564
4879
  dataSchema,
4565
- method
4880
+ method,
4881
+ modelName
4566
4882
  );
4567
4883
  let where;
4568
4884
  if (isUniqueWhere) {
@@ -4728,7 +5044,8 @@ function createModelGuardExtension(config) {
4728
5044
  const createData = validateAndMergeData(
4729
5045
  resolved.body.create,
4730
5046
  createDataSchema,
4731
- "upsert (create)"
5047
+ "upsert (create)",
5048
+ modelName
4732
5049
  );
4733
5050
  const updateDataSchema = getDataSchema(
4734
5051
  "update",
@@ -4739,7 +5056,8 @@ function createModelGuardExtension(config) {
4739
5056
  const updateData = validateAndMergeData(
4740
5057
  resolved.body.update,
4741
5058
  updateDataSchema,
4742
- "upsert (update)"
5059
+ "upsert (update)",
5060
+ modelName
4743
5061
  );
4744
5062
  const where = requireUniqueWhere(
4745
5063
  resolved.shape,