prisma-guard 1.28.0 → 1.29.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.
@@ -243,7 +243,7 @@ function createScalarBase(strictDecimal) {
243
243
  return {
244
244
  String: () => import_zod.z.string(),
245
245
  Int: () => import_zod.z.number().int(),
246
- Float: () => import_zod.z.number(),
246
+ Float: () => import_zod.z.number().finite(),
247
247
  Decimal: createDecimalFactory(strictDecimal),
248
248
  BigInt: () => import_zod.z.union([
249
249
  import_zod.z.bigint(),
@@ -384,6 +384,19 @@ function requireConfigTrue(config, context) {
384
384
  }
385
385
  }
386
386
  }
387
+ function requirePlainObjectConfig(value, message) {
388
+ if (!isPlainObject(value)) {
389
+ throw new ShapeError(message);
390
+ }
391
+ return value;
392
+ }
393
+ function assertAllowedKeys(value, allowed, makeError) {
394
+ for (const key of Object.keys(value)) {
395
+ if (!allowed.has(key)) {
396
+ throw new ShapeError(makeError(key));
397
+ }
398
+ }
399
+ }
387
400
 
388
401
  // src/runtime/zod-type-map.ts
389
402
  var SCALAR_OPERATORS = {
@@ -447,24 +460,12 @@ var JSON_ARRAY_OPERATORS = /* @__PURE__ */ new Set([
447
460
  "array_starts_with",
448
461
  "array_ends_with"
449
462
  ]);
450
- function getSupportedOperators(input, isList = false, isEnum = false) {
451
- let fieldType;
452
- let list;
453
- let enumField;
454
- if (typeof input === "string") {
455
- fieldType = input;
456
- list = isList;
457
- enumField = isEnum;
458
- } else {
459
- fieldType = input.type;
460
- list = input.isList;
461
- enumField = input.isEnum === true;
462
- }
463
- if (list)
463
+ function getSupportedOperators(fieldMeta) {
464
+ if (fieldMeta.isList)
464
465
  return [...SCALAR_LIST_OPERATORS];
465
- if (enumField)
466
+ if (fieldMeta.isEnum === true)
466
467
  return [...ENUM_OPERATORS];
467
- const ops = SCALAR_OPERATORS[fieldType];
468
+ const ops = SCALAR_OPERATORS[fieldMeta.type];
468
469
  if (!ops)
469
470
  return [];
470
471
  return [...ops];
@@ -1029,6 +1030,7 @@ function validateContext(ctx) {
1029
1030
 
1030
1031
  // src/runtime/query-builder-where.ts
1031
1032
  var import_zod5 = require("zod");
1033
+ var import_node_util = require("util");
1032
1034
 
1033
1035
  // src/shared/deep-clone.ts
1034
1036
  function deepClone(value) {
@@ -1309,15 +1311,10 @@ function applyBuiltShape(built, body, isUniqueMethod, modelName) {
1309
1311
  try {
1310
1312
  validated = built.zodSchema.parse(parseable);
1311
1313
  } catch (err) {
1312
- if (err instanceof ShapeError)
1313
- throw err;
1314
- if (err && typeof err === "object" && "issues" in err) {
1315
- const context = modelName ? `Invalid query on model "${modelName}"` : "Invalid query";
1316
- throw new ShapeError(`${context}: ${formatZodError(err)}`, {
1317
- cause: err
1318
- });
1319
- }
1320
- throw err;
1314
+ wrapParseError(
1315
+ err,
1316
+ modelName ? `Invalid query on model "${modelName}"` : "Invalid query"
1317
+ );
1321
1318
  }
1322
1319
  if (hasWhereForced(built.forcedWhere)) {
1323
1320
  validated.where = isUniqueMethod ? mergeUniqueWhereForced(
@@ -1634,37 +1631,8 @@ var JSON_STRING_MODE_OPS = /* @__PURE__ */ new Set([
1634
1631
  ]);
1635
1632
  var NEGATIVE_RELATION_OPS = /* @__PURE__ */ new Set(["none", "isNot"]);
1636
1633
  var MAX_WHERE_DEPTH = 10;
1637
- function safeStringify(value) {
1638
- if (typeof value === "bigint")
1639
- return `${value}n`;
1640
- if (typeof value === "undefined")
1641
- return "undefined";
1642
- if (typeof value === "function")
1643
- return "[function]";
1644
- if (typeof value === "symbol")
1645
- return value.toString();
1646
- const seen = /* @__PURE__ */ new WeakSet();
1647
- try {
1648
- const json = JSON.stringify(value, (_key, current) => {
1649
- if (typeof current === "bigint")
1650
- return `${current}n`;
1651
- if (typeof current === "undefined")
1652
- return "[undefined]";
1653
- if (typeof current === "function")
1654
- return "[function]";
1655
- if (typeof current === "symbol")
1656
- return current.toString();
1657
- if (current && typeof current === "object") {
1658
- if (seen.has(current))
1659
- return "[Circular]";
1660
- seen.add(current);
1661
- }
1662
- return current;
1663
- });
1664
- return json === void 0 ? String(value) : json;
1665
- } catch {
1666
- return String(value);
1667
- }
1634
+ function formatValue(value) {
1635
+ return (0, import_node_util.inspect)(value, { depth: 3, breakLength: Infinity });
1668
1636
  }
1669
1637
  function mergeScalarConditions(target, source) {
1670
1638
  for (const [field, ops] of Object.entries(source)) {
@@ -1685,7 +1653,7 @@ function mergeScalarConditions(target, source) {
1685
1653
  const existingVal = existing[op];
1686
1654
  if (!deepEqual(existingVal, val)) {
1687
1655
  throw new ShapeError(
1688
- `Conflicting forced where values for "${field}.${op}": shape defines both ${safeStringify(existingVal)} and ${safeStringify(val)}`
1656
+ `Conflicting forced where values for "${field}.${op}": shape defines both ${formatValue(existingVal)} and ${formatValue(val)}`
1689
1657
  );
1690
1658
  }
1691
1659
  }
@@ -2523,10 +2491,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2523
2491
  `${fieldMeta.type} field "${fieldName}" cannot be used in having`
2524
2492
  );
2525
2493
  }
2526
- const allowedOps = getSupportedOperators(
2527
- fieldMeta.type,
2528
- fieldMeta.isList
2529
- );
2494
+ const allowedOps = getSupportedOperators(fieldMeta);
2530
2495
  const opSchemas = {};
2531
2496
  for (const op of allowedOps) {
2532
2497
  opSchemas[op] = createOperatorSchema(
@@ -2703,20 +2668,27 @@ function buildDefaultProjectionBody(shape) {
2703
2668
 
2704
2669
  // src/runtime/query-builder-projection.ts
2705
2670
  var KNOWN_NESTED_KEYS = {
2706
- include: /* @__PURE__ */ new Set(["where", "include", "select", "orderBy", "cursor", "take", "skip"]),
2707
- select: /* @__PURE__ */ new Set(["select", "include", "where", "orderBy", "cursor", "take", "skip"])
2671
+ include: /* @__PURE__ */ new Set([
2672
+ "where",
2673
+ "include",
2674
+ "select",
2675
+ "orderBy",
2676
+ "cursor",
2677
+ "take",
2678
+ "skip"
2679
+ ]),
2680
+ select: /* @__PURE__ */ new Set([
2681
+ "select",
2682
+ "include",
2683
+ "where",
2684
+ "orderBy",
2685
+ "cursor",
2686
+ "take",
2687
+ "skip"
2688
+ ])
2708
2689
  };
2709
2690
  var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
2710
2691
  var MAX_PROJECTION_DEPTH = 10;
2711
- function validateNestedKeys(keys, allowed, context) {
2712
- for (const key of keys) {
2713
- if (!allowed.has(key)) {
2714
- throw new ShapeError(
2715
- `Unknown key "${key}" in ${context}. Allowed: ${[...allowed].join(", ")}`
2716
- );
2717
- }
2718
- }
2719
- }
2720
2692
  function hasDefinedKeys(v) {
2721
2693
  return Object.values(v).some((value) => value !== void 0);
2722
2694
  }
@@ -2729,6 +2701,20 @@ function wrapRelationSchema(nestedObj, skeleton) {
2729
2701
  collapsed
2730
2702
  );
2731
2703
  }
2704
+ function buildRelationWhere(relatedType, whereConfig, context, buildWhereSchema) {
2705
+ if (Object.keys(whereConfig).length === 0) {
2706
+ throw new ShapeError(
2707
+ `Empty "where" in ${context}. Define at least one field.`
2708
+ );
2709
+ }
2710
+ const { schema, forced } = buildWhereSchema(relatedType, whereConfig);
2711
+ if (!schema && !hasWhereForced(forced)) {
2712
+ throw new ShapeError(
2713
+ `"where" in ${context} produced no schema and no forced conditions. Define at least one field.`
2714
+ );
2715
+ }
2716
+ return { schema, forced };
2717
+ }
2732
2718
  function createProjectionBuilder(typeMap, _enumMap, deps) {
2733
2719
  function buildIncludeCountSchema(model, config) {
2734
2720
  const modelFields = typeMap[model];
@@ -2742,13 +2728,11 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2742
2728
  `Invalid _count config on model "${model}". Expected true or { select: { ... } }`
2743
2729
  );
2744
2730
  }
2745
- for (const key of Object.keys(config)) {
2746
- if (key !== "select") {
2747
- throw new ShapeError(
2748
- `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
2749
- );
2750
- }
2751
- }
2731
+ assertAllowedKeys(
2732
+ config,
2733
+ /* @__PURE__ */ new Set(["select"]),
2734
+ (key) => `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
2735
+ );
2752
2736
  if (!isPlainObject(config.select)) {
2753
2737
  throw new ShapeError(
2754
2738
  `Invalid _count.select on model "${model}". Expected a plain object with relation field keys.`
@@ -2765,11 +2749,17 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2765
2749
  for (const [fieldName, fieldConfig] of Object.entries(selectObj)) {
2766
2750
  const fieldMeta = modelFields[fieldName];
2767
2751
  if (!fieldMeta)
2768
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in _count.select`);
2752
+ throw new ShapeError(
2753
+ `Unknown field "${fieldName}" on model "${model}" in _count.select`
2754
+ );
2769
2755
  if (!fieldMeta.isRelation)
2770
- throw new ShapeError(`Field "${fieldName}" is not a relation on model "${model}" in _count.select`);
2756
+ throw new ShapeError(
2757
+ `Field "${fieldName}" is not a relation on model "${model}" in _count.select`
2758
+ );
2771
2759
  if (!fieldMeta.isList)
2772
- throw new ShapeError(`Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`);
2760
+ throw new ShapeError(
2761
+ `Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`
2762
+ );
2773
2763
  if (fieldConfig === true) {
2774
2764
  countSelectFields[fieldName] = import_zod7.z.literal(true).optional();
2775
2765
  continue;
@@ -2784,16 +2774,18 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2784
2774
  `Empty config for _count.select.${fieldName} on model "${model}". Use true or { where: { ... } }.`
2785
2775
  );
2786
2776
  }
2787
- validateNestedKeys(
2788
- Object.keys(fieldConfig),
2777
+ assertAllowedKeys(
2778
+ fieldConfig,
2789
2779
  KNOWN_COUNT_SELECT_ENTRY_KEYS,
2790
- `_count.select.${fieldName} on model "${model}"`
2780
+ (key) => `Unknown key "${key}" in _count.select.${fieldName} on model "${model}". Allowed: ${[...KNOWN_COUNT_SELECT_ENTRY_KEYS].join(", ")}`
2791
2781
  );
2792
2782
  if (fieldConfig.where) {
2793
2783
  const relatedType = fieldMeta.type;
2794
- const { schema: whereSchema, forced } = deps.buildWhereSchema(
2784
+ const { schema: whereSchema, forced } = buildRelationWhere(
2795
2785
  relatedType,
2796
- fieldConfig.where
2786
+ fieldConfig.where,
2787
+ `_count.select.${fieldName} on model "${model}"`,
2788
+ deps.buildWhereSchema
2797
2789
  );
2798
2790
  const nestedSchemas = {};
2799
2791
  if (whereSchema)
@@ -2816,13 +2808,15 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2816
2808
  forcedCountWhere
2817
2809
  };
2818
2810
  }
2819
- function buildNestedRelSchemas(relatedType, config, depth) {
2811
+ function buildNestedRelSchemas(relatedType, config, depth, context) {
2820
2812
  const nestedSchemas = {};
2821
2813
  const relForced = {};
2822
2814
  if (config.where) {
2823
- const { schema: whereSchema, forced } = deps.buildWhereSchema(
2815
+ const { schema: whereSchema, forced } = buildRelationWhere(
2824
2816
  relatedType,
2825
- config.where
2817
+ config.where,
2818
+ context,
2819
+ deps.buildWhereSchema
2826
2820
  );
2827
2821
  if (whereSchema)
2828
2822
  nestedSchemas["where"] = whereSchema;
@@ -2830,7 +2824,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2830
2824
  relForced.where = forced;
2831
2825
  }
2832
2826
  if (config.include) {
2833
- const nested = buildProjectionSchema("include", relatedType, config.include, depth + 1);
2827
+ const nested = buildProjectionSchema(
2828
+ "include",
2829
+ relatedType,
2830
+ config.include,
2831
+ depth + 1
2832
+ );
2834
2833
  nestedSchemas["include"] = nested.schema;
2835
2834
  if (Object.keys(nested.forcedTree).length > 0)
2836
2835
  relForced.include = nested.forcedTree;
@@ -2840,7 +2839,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2840
2839
  }
2841
2840
  }
2842
2841
  if (config.select) {
2843
- const nested = buildProjectionSchema("select", relatedType, config.select, depth + 1);
2842
+ const nested = buildProjectionSchema(
2843
+ "select",
2844
+ relatedType,
2845
+ config.select,
2846
+ depth + 1
2847
+ );
2844
2848
  nestedSchemas["select"] = nested.schema;
2845
2849
  if (Object.keys(nested.forcedTree).length > 0)
2846
2850
  relForced.select = nested.forcedTree;
@@ -2850,15 +2854,26 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2850
2854
  }
2851
2855
  }
2852
2856
  if (config.orderBy) {
2853
- nestedSchemas["orderBy"] = deps.buildOrderBySchema(relatedType, config.orderBy);
2857
+ nestedSchemas["orderBy"] = deps.buildOrderBySchema(
2858
+ relatedType,
2859
+ config.orderBy
2860
+ );
2854
2861
  }
2855
2862
  if (config.cursor) {
2856
- nestedSchemas["cursor"] = deps.buildCursorSchema(relatedType, config.cursor);
2863
+ nestedSchemas["cursor"] = deps.buildCursorSchema(
2864
+ relatedType,
2865
+ config.cursor
2866
+ );
2857
2867
  }
2858
- if (config.take) {
2868
+ if ("take" in config && config.take !== void 0) {
2859
2869
  nestedSchemas["take"] = deps.buildTakeSchema(config.take);
2860
2870
  }
2861
- if (config.skip) {
2871
+ if ("skip" in config && config.skip !== void 0) {
2872
+ if (config.skip !== true) {
2873
+ throw new ShapeError(
2874
+ `Nested "skip" in ${context} must be true`
2875
+ );
2876
+ }
2862
2877
  nestedSchemas["skip"] = import_zod7.z.number().int().min(0).optional();
2863
2878
  }
2864
2879
  return { nestedSchemas, relForced };
@@ -2884,28 +2899,43 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2884
2899
  let topLevelForcedCountWhere = {};
2885
2900
  for (const [fieldName, config] of Object.entries(projectionConfig)) {
2886
2901
  if (fieldName === "_count") {
2887
- const countResult = buildIncludeCountSchema(model, config);
2902
+ const countResult = buildIncludeCountSchema(
2903
+ model,
2904
+ config
2905
+ );
2888
2906
  fieldSchemas["_count"] = countResult.schema;
2889
2907
  topLevelForcedCountWhere = countResult.forcedCountWhere;
2890
2908
  continue;
2891
2909
  }
2892
2910
  const fieldMeta = modelFields[fieldName];
2893
2911
  if (!fieldMeta)
2894
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
2912
+ throw new ShapeError(
2913
+ `Unknown field "${fieldName}" on model "${model}"`
2914
+ );
2895
2915
  if (mode === "include" && !fieldMeta.isRelation) {
2896
- throw new ShapeError(`Field "${fieldName}" is not a relation on model "${model}"`);
2916
+ throw new ShapeError(
2917
+ `Field "${fieldName}" is not a relation on model "${model}"`
2918
+ );
2897
2919
  }
2898
2920
  if (config === true) {
2899
2921
  fieldSchemas[fieldName] = import_zod7.z.literal(true).optional();
2900
2922
  continue;
2901
2923
  }
2902
2924
  if (mode === "select" && !fieldMeta.isRelation) {
2903
- throw new ShapeError(`Nested select args only valid for relations, not scalar "${fieldName}" on model "${model}"`);
2925
+ throw new ShapeError(
2926
+ `Nested select args only valid for relations, not scalar "${fieldName}" on model "${model}"`
2927
+ );
2904
2928
  }
2905
2929
  const contextLabel = `nested ${mode} for "${fieldName}" on model "${model}"`;
2906
- validateNestedKeys(Object.keys(config), allowedNestedKeys, contextLabel);
2930
+ assertAllowedKeys(
2931
+ config,
2932
+ allowedNestedKeys,
2933
+ (key) => `Unknown key "${key}" in ${contextLabel}. Allowed: ${[...allowedNestedKeys].join(", ")}`
2934
+ );
2907
2935
  if (config.select && config.include) {
2908
- throw new ShapeError(`Nested ${mode} for "${fieldName}" cannot define both "select" and "include".`);
2936
+ throw new ShapeError(
2937
+ `Nested ${mode} for "${fieldName}" cannot define both "select" and "include".`
2938
+ );
2909
2939
  }
2910
2940
  if (!fieldMeta.isList) {
2911
2941
  if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
@@ -2914,7 +2944,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2914
2944
  );
2915
2945
  }
2916
2946
  }
2917
- const { nestedSchemas, relForced } = buildNestedRelSchemas(fieldMeta.type, config, currentDepth);
2947
+ const { nestedSchemas, relForced } = buildNestedRelSchemas(
2948
+ fieldMeta.type,
2949
+ config,
2950
+ currentDepth,
2951
+ contextLabel
2952
+ );
2918
2953
  const nestedObj = import_zod7.z.object(nestedSchemas).strict();
2919
2954
  fieldSchemas[fieldName] = wrapRelationSchema(
2920
2955
  nestedObj,
@@ -2939,27 +2974,33 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2939
2974
  function buildSelectSchema(model, selectConfig, depth) {
2940
2975
  return buildProjectionSchema("select", model, selectConfig, depth);
2941
2976
  }
2942
- return { buildIncludeSchema, buildSelectSchema, buildIncludeCountSchema, buildProjectionSchema };
2977
+ return {
2978
+ buildIncludeSchema,
2979
+ buildSelectSchema,
2980
+ buildIncludeCountSchema,
2981
+ buildProjectionSchema
2982
+ };
2943
2983
  }
2944
2984
 
2945
2985
  // src/shared/operation-shape-keys.ts
2946
2986
  var OPERATION_SHAPE_KEYS = {
2947
2987
  findMany: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
2988
+ findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
2948
2989
  findFirst: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
2949
2990
  findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
2950
2991
  findUnique: ["where", "include", "select"],
2951
2992
  findUniqueOrThrow: ["where", "include", "select"],
2952
2993
  count: ["where", "select", "cursor", "orderBy", "skip", "take"],
2953
2994
  aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
2954
- groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
2955
- create: ["data", "select", "include"],
2956
- createMany: ["data"],
2957
- createManyAndReturn: ["data", "select", "include"],
2958
- update: ["data", "where", "select", "include"],
2959
- updateMany: ["data", "where"],
2960
- updateManyAndReturn: ["data", "where", "select", "include"],
2961
- upsert: ["where", "create", "update", "select", "include"],
2962
- delete: ["where", "select", "include"],
2995
+ groupBy: ["where", "orderBy", "by", "having", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
2996
+ create: ["data", "include", "select"],
2997
+ createMany: ["data", "skipDuplicates"],
2998
+ createManyAndReturn: ["data", "select", "include", "skipDuplicates"],
2999
+ update: ["where", "data", "include", "select"],
3000
+ updateMany: ["where", "data"],
3001
+ updateManyAndReturn: ["where", "data", "select", "include"],
3002
+ upsert: ["where", "create", "update", "include", "select"],
3003
+ delete: ["where", "include", "select"],
2963
3004
  deleteMany: ["where"]
2964
3005
  };
2965
3006
  var READ_METHOD_ALLOWED_ARGS = {
@@ -3271,7 +3312,17 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
3271
3312
  let forcedIncludeCountWhere = {};
3272
3313
  let forcedSelectCountWhere = {};
3273
3314
  if (shape.where) {
3315
+ if (Object.keys(shape.where).length === 0) {
3316
+ throw new ShapeError(
3317
+ `Empty "where" in shape for model "${model}" method "${method}". Define at least one field.`
3318
+ );
3319
+ }
3274
3320
  const builtWhere = UNIQUE_WHERE_METHODS.has(method) ? whereBuilder.buildUniqueWhereSchema(model, shape.where) : whereBuilder.buildWhereSchema(model, shape.where);
3321
+ if (!builtWhere.schema && !hasWhereForced(builtWhere.forced)) {
3322
+ throw new ShapeError(
3323
+ `"where" in shape for model "${model}" method "${method}" produced no schema and no forced conditions.`
3324
+ );
3325
+ }
3275
3326
  if (builtWhere.schema) {
3276
3327
  schemaFields.where = builtWhere.schema;
3277
3328
  }
@@ -4073,27 +4124,19 @@ function validateRelationOpKeys(actual, opKey, model, field, opLabel) {
4073
4124
  const allowed = RELATION_OP_ALLOWED_KEYS[opKey];
4074
4125
  if (!allowed)
4075
4126
  return;
4076
- for (const key of Object.keys(actual)) {
4077
- if (!allowed.has(key)) {
4078
- throw new ShapeError(
4079
- `Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
4080
- );
4081
- }
4082
- }
4127
+ assertAllowedKeys(
4128
+ actual,
4129
+ allowed,
4130
+ (key) => `Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
4131
+ );
4083
4132
  }
4084
4133
  function validateAllowedKeys(value, allowed, method, kind) {
4085
- for (const key of Object.keys(value)) {
4086
- if (!allowed.has(key)) {
4087
- if (kind === "body") {
4088
- throw new ShapeError(
4089
- `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`
4090
- );
4091
- }
4092
- throw new ShapeError(
4093
- `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`
4094
- );
4134
+ assertAllowedKeys(value, allowed, (key) => {
4135
+ if (kind === "body") {
4136
+ return `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`;
4095
4137
  }
4096
- }
4138
+ return `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`;
4139
+ });
4097
4140
  }
4098
4141
  function validateCreateCompleteness(modelName, dataConfig, typeMap, scopeFks, zodDefaults) {
4099
4142
  const modelFields = typeMap[modelName];
@@ -4180,18 +4223,10 @@ function buildNestedDataSchema(model, config, mode, typeMap, schemaBuilder) {
4180
4223
  }
4181
4224
  return import_zod10.z.object(fieldSchemas).strict();
4182
4225
  }
4183
- function requirePlainObjectConfig(value, message) {
4184
- if (!isPlainObject(value))
4185
- throw new ShapeError(message);
4186
- return value;
4187
- }
4188
4226
  function requireNestedObject(cfg, key, message) {
4189
- const v = cfg[key];
4190
- if (!v || !isPlainObject(v))
4191
- throw new ShapeError(message);
4192
- return v;
4227
+ return requirePlainObjectConfig(cfg[key], message);
4193
4228
  }
4194
- function buildUniqueSelector(ctx, cfg, context) {
4229
+ function buildRelatedUniqueSelector(ctx, cfg, context) {
4195
4230
  return buildUniqueSelectorSchema(
4196
4231
  ctx.model,
4197
4232
  ctx.fieldName,
@@ -4204,7 +4239,7 @@ function buildUniqueSelector(ctx, cfg, context) {
4204
4239
  context
4205
4240
  );
4206
4241
  }
4207
- function buildNestedData(ctx, cfg, mode) {
4242
+ function buildRelatedNestedData(ctx, cfg, mode) {
4208
4243
  return buildNestedDataSchema(
4209
4244
  ctx.relatedModelName,
4210
4245
  cfg,
@@ -4218,7 +4253,7 @@ var handleConnect = (ctx) => {
4218
4253
  ctx.config,
4219
4254
  `connect config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
4220
4255
  );
4221
- const schema = buildUniqueSelector(ctx, cfg, "connect");
4256
+ const schema = buildRelatedUniqueSelector(ctx, cfg, "connect");
4222
4257
  return wrapRelationOp(ctx.isList, schema);
4223
4258
  };
4224
4259
  var handleConnectOrCreate = (ctx) => {
@@ -4237,8 +4272,8 @@ var handleConnectOrCreate = (ctx) => {
4237
4272
  "create",
4238
4273
  `connectOrCreate on "${ctx.model}.${ctx.fieldName}" requires "create" object`
4239
4274
  );
4240
- const whereSchema = buildUniqueSelector(ctx, where, "connectOrCreate.where");
4241
- const createSchema = buildNestedData(ctx, create, "create");
4275
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "connectOrCreate.where");
4276
+ const createSchema = buildRelatedNestedData(ctx, create, "create");
4242
4277
  const cocSchema = import_zod10.z.object({ where: whereSchema, create: createSchema }).strict();
4243
4278
  return wrapRelationOp(ctx.isList, cocSchema);
4244
4279
  };
@@ -4247,7 +4282,7 @@ var handleCreate = (ctx) => {
4247
4282
  ctx.config,
4248
4283
  `create config on "${ctx.model}.${ctx.fieldName}" must be an object of field names`
4249
4284
  );
4250
- const createSchema = buildNestedData(ctx, cfg, "create");
4285
+ const createSchema = buildRelatedNestedData(ctx, cfg, "create");
4251
4286
  return wrapRelationOp(ctx.isList, createSchema);
4252
4287
  };
4253
4288
  var handleCreateMany = (ctx) => {
@@ -4266,7 +4301,7 @@ var handleCreateMany = (ctx) => {
4266
4301
  "data",
4267
4302
  `createMany on "${ctx.model}.${ctx.fieldName}" requires "data" object`
4268
4303
  );
4269
- const dataSchema = buildNestedData(ctx, data, "create");
4304
+ const dataSchema = buildRelatedNestedData(ctx, data, "create");
4270
4305
  const cmSchemaFields = {
4271
4306
  data: import_zod10.z.preprocess(coerceToArray, import_zod10.z.array(dataSchema))
4272
4307
  };
@@ -4289,7 +4324,7 @@ var handleDisconnect = (ctx) => {
4289
4324
  `disconnect config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
4290
4325
  );
4291
4326
  }
4292
- const schema = buildUniqueSelector(ctx, ctx.config, "disconnect");
4327
+ const schema = buildRelatedUniqueSelector(ctx, ctx.config, "disconnect");
4293
4328
  if (ctx.isList)
4294
4329
  return wrapRelationOp(true, schema);
4295
4330
  return import_zod10.z.union([import_zod10.z.literal(true), schema]).optional();
@@ -4308,7 +4343,7 @@ var handleDelete = (ctx) => {
4308
4343
  `delete config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
4309
4344
  );
4310
4345
  }
4311
- const schema = buildUniqueSelector(ctx, ctx.config, "delete");
4346
+ const schema = buildRelatedUniqueSelector(ctx, ctx.config, "delete");
4312
4347
  if (ctx.isList)
4313
4348
  return wrapRelationOp(true, schema);
4314
4349
  return import_zod10.z.union([import_zod10.z.literal(true), schema]).optional();
@@ -4323,7 +4358,7 @@ var handleSet = (ctx) => {
4323
4358
  ctx.config,
4324
4359
  `set config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
4325
4360
  );
4326
- const schema = buildUniqueSelector(ctx, cfg, "set");
4361
+ const schema = buildRelatedUniqueSelector(ctx, cfg, "set");
4327
4362
  return wrapRelationOp(true, schema);
4328
4363
  };
4329
4364
  var handleUpdate = (ctx) => {
@@ -4343,12 +4378,12 @@ var handleUpdate = (ctx) => {
4343
4378
  "data",
4344
4379
  `update on to-many "${ctx.model}.${ctx.fieldName}" requires "data" object`
4345
4380
  );
4346
- const whereSchema = buildUniqueSelector(ctx, where, "update.where");
4347
- const dataSchema2 = buildNestedData(ctx, data, "update");
4381
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "update.where");
4382
+ const dataSchema2 = buildRelatedNestedData(ctx, data, "update");
4348
4383
  const updateSchema = import_zod10.z.object({ where: whereSchema, data: dataSchema2 }).strict();
4349
4384
  return wrapRelationOp(true, updateSchema);
4350
4385
  }
4351
- const dataSchema = buildNestedData(ctx, cfg, "update");
4386
+ const dataSchema = buildRelatedNestedData(ctx, cfg, "update");
4352
4387
  return dataSchema.optional();
4353
4388
  };
4354
4389
  var handleUpsert = (ctx) => {
@@ -4373,15 +4408,15 @@ var handleUpsert = (ctx) => {
4373
4408
  "update",
4374
4409
  `upsert on "${ctx.model}.${ctx.fieldName}" requires "update" object`
4375
4410
  );
4376
- const createSchema = buildNestedData(ctx, create, "create");
4377
- const updateSchema = buildNestedData(ctx, update, "update");
4411
+ const createSchema = buildRelatedNestedData(ctx, create, "create");
4412
+ const updateSchema = buildRelatedNestedData(ctx, update, "update");
4378
4413
  if (ctx.isList) {
4379
4414
  const where = requireNestedObject(
4380
4415
  cfg,
4381
4416
  "where",
4382
4417
  `upsert on to-many "${ctx.model}.${ctx.fieldName}" requires "where" object`
4383
4418
  );
4384
- const whereSchema = buildUniqueSelector(ctx, where, "upsert.where");
4419
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "upsert.where");
4385
4420
  const upsertSchema2 = import_zod10.z.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
4386
4421
  return wrapRelationOp(true, upsertSchema2);
4387
4422
  }
@@ -4392,7 +4427,7 @@ var handleUpsert = (ctx) => {
4392
4427
  `upsert on to-one "${ctx.model}.${ctx.fieldName}" has invalid "where": must be a plain object of unique selectors`
4393
4428
  );
4394
4429
  }
4395
- const whereSchema = buildUniqueSelector(ctx, cfg.where, "upsert.where");
4430
+ const whereSchema = buildRelatedUniqueSelector(ctx, cfg.where, "upsert.where");
4396
4431
  const upsertSchema2 = import_zod10.z.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
4397
4432
  return upsertSchema2.optional();
4398
4433
  }
@@ -4436,7 +4471,7 @@ var handleUpdateMany = (ctx) => {
4436
4471
  ctx.typeMap,
4437
4472
  ctx.schemaBuilder
4438
4473
  );
4439
- const dataSchema = buildNestedData(ctx, data, "update");
4474
+ const dataSchema = buildRelatedNestedData(ctx, data, "update");
4440
4475
  const umSchema = import_zod10.z.object({ where: whereSchema, data: dataSchema }).strict();
4441
4476
  return wrapRelationOp(true, umSchema);
4442
4477
  };
@@ -4483,17 +4518,21 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
4483
4518
  throw new ShapeError(
4484
4519
  `Unknown related model "${relatedModelName}" for field "${model}.${fieldName}"`
4485
4520
  );
4486
- for (const key of Object.keys(config)) {
4487
- if (!KNOWN_RELATION_WRITE_OPS.has(key)) {
4488
- throw new ShapeError(
4489
- `Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
4490
- );
4491
- }
4521
+ assertAllowedKeys(
4522
+ config,
4523
+ KNOWN_RELATION_WRITE_OPS,
4524
+ (key) => `Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
4525
+ );
4526
+ const definedEntries = Object.entries(config).filter(
4527
+ ([, opConfig]) => opConfig !== void 0
4528
+ );
4529
+ if (definedEntries.length === 0) {
4530
+ throw new ShapeError(
4531
+ `Empty relation write config on "${model}.${fieldName}". Define at least one operation: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
4532
+ );
4492
4533
  }
4493
4534
  const opSchemas = {};
4494
- for (const [op, opConfig] of Object.entries(config)) {
4495
- if (opConfig === void 0)
4496
- continue;
4535
+ for (const [op, opConfig] of definedEntries) {
4497
4536
  const handler = RELATION_OP_HANDLERS[op];
4498
4537
  opSchemas[op] = handler({
4499
4538
  model,
@@ -4510,7 +4549,7 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
4510
4549
  }
4511
4550
  return import_zod10.z.object(opSchemas).strict();
4512
4551
  }
4513
- function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults) {
4552
+ function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults, allowRelationWrites) {
4514
4553
  const modelFields = typeMap[model];
4515
4554
  if (!modelFields)
4516
4555
  throw new ShapeError(`Unknown model: ${model}`);
@@ -4540,6 +4579,11 @@ function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, s
4540
4579
  continue;
4541
4580
  }
4542
4581
  if (fieldMeta.isRelation) {
4582
+ if (!allowRelationWrites) {
4583
+ throw new ShapeError(
4584
+ `Field "${fieldName}" on model "${model}" is a relation. Relation writes are not supported for this method.`
4585
+ );
4586
+ }
4543
4587
  if (!isPlainObject(value)) {
4544
4588
  throw new ShapeError(
4545
4589
  `Relation field "${fieldName}" on model "${model}" requires a relation write config object`
@@ -4653,13 +4697,8 @@ function validateAndMergeData(bodyData, cached, method, modelName) {
4653
4697
  try {
4654
4698
  validated = cached.schema.parse(bodyData);
4655
4699
  } catch (err) {
4656
- if (err instanceof ShapeError)
4657
- throw err;
4658
- if (err && typeof err === "object" && "issues" in err) {
4659
- const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
4660
- throw new ShapeError(`${context}: ${formatZodError(err)}`, { cause: err });
4661
- }
4662
- throw err;
4700
+ const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
4701
+ wrapParseError(err, context);
4663
4702
  }
4664
4703
  return { ...validated, ...deepClone(cached.forced) };
4665
4704
  }
@@ -4814,6 +4853,8 @@ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
4814
4853
  "updateManyAndReturn"
4815
4854
  ]);
4816
4855
  var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set(["createMany", "createManyAndReturn"]);
4856
+ var RELATION_WRITE_CREATE_METHODS = /* @__PURE__ */ new Set(["create"]);
4857
+ var RELATION_WRITE_UPDATE_METHODS = /* @__PURE__ */ new Set(["update"]);
4817
4858
  var MAX_PROJECTION_WALK_DEPTH = 10;
4818
4859
  function walkForClientContent(obj, predicate, depth) {
4819
4860
  if (depth > MAX_PROJECTION_WALK_DEPTH)
@@ -4964,11 +5005,11 @@ function createModelGuardExtension(config) {
4964
5005
  )
4965
5006
  );
4966
5007
  }
4967
- function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
5008
+ function getDataSchema(mode, dataConfig, matchedKey, wasDynamic, allowRelationWrites) {
4968
5009
  const skipCache = wasDynamic || hasDataRefines(dataConfig);
4969
5010
  return memoize(
4970
5011
  dataSchemaCache,
4971
- `${mode}\0${matchedKey}`,
5012
+ `${mode}\0${matchedKey}\0${allowRelationWrites ? "r" : "n"}`,
4972
5013
  skipCache,
4973
5014
  () => buildDataSchema(
4974
5015
  modelName,
@@ -4979,7 +5020,8 @@ function createModelGuardExtension(config) {
4979
5020
  enumMap,
4980
5021
  scalarBase,
4981
5022
  schemaBuilder,
4982
- zodDefaults
5023
+ zodDefaults,
5024
+ allowRelationWrites
4983
5025
  )
4984
5026
  );
4985
5027
  }
@@ -5237,6 +5279,39 @@ function createModelGuardExtension(config) {
5237
5279
  const defaultProjection = buildDefaultProjectionBody(resolved.shape);
5238
5280
  return { ...resolved.body, ...defaultProjection };
5239
5281
  }
5282
+ function makeResolveMethod() {
5283
+ const WRITE_KEYS = ["data", "create", "update"];
5284
+ const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
5285
+ return (body) => {
5286
+ const caller = resolveCaller();
5287
+ const resolved = resolveShape(input, body, contextFn, caller);
5288
+ for (const key of WRITE_KEYS) {
5289
+ if (hasOwn(resolved.shape, key)) {
5290
+ throw new ShapeError(
5291
+ `.resolve() is a read-only planning helper. Guard shape contains write key "${key}". Use the corresponding write method instead.`
5292
+ );
5293
+ }
5294
+ }
5295
+ for (const key of WRITE_KEYS) {
5296
+ if (hasOwn(resolved.body, key)) {
5297
+ throw new ShapeError(
5298
+ `.resolve() is a read-only planning helper. Request body contains write key "${key}".`
5299
+ );
5300
+ }
5301
+ }
5302
+ const effectiveReadBody = buildEffectiveReadBody({
5303
+ shape: resolved.shape,
5304
+ body: resolved.body
5305
+ });
5306
+ return {
5307
+ shape: resolved.shape,
5308
+ body: resolved.body,
5309
+ effectiveReadBody,
5310
+ matchedKey: resolved.matchedKey,
5311
+ wasDynamic: resolved.wasDynamic
5312
+ };
5313
+ };
5314
+ }
5240
5315
  function makeReadMethod(method) {
5241
5316
  return (body) => {
5242
5317
  const caller = resolveCaller();
@@ -5270,6 +5345,7 @@ function createModelGuardExtension(config) {
5270
5345
  const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
5271
5346
  const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
5272
5347
  const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
5348
+ const allowRelationWrites = RELATION_WRITE_CREATE_METHODS.has(method);
5273
5349
  return (body) => {
5274
5350
  const caller = resolveCaller();
5275
5351
  const resolved = resolveShape(input, body, contextFn, caller);
@@ -5295,7 +5371,8 @@ function createModelGuardExtension(config) {
5295
5371
  "create",
5296
5372
  resolved.shape.data,
5297
5373
  resolved.matchedKey,
5298
- resolved.wasDynamic
5374
+ resolved.wasDynamic,
5375
+ allowRelationWrites
5299
5376
  );
5300
5377
  let args;
5301
5378
  if (method === "create") {
@@ -5343,6 +5420,7 @@ function createModelGuardExtension(config) {
5343
5420
  const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
5344
5421
  const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
5345
5422
  const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
5423
+ const allowRelationWrites = RELATION_WRITE_UPDATE_METHODS.has(method);
5346
5424
  return (body) => {
5347
5425
  const caller = resolveCaller();
5348
5426
  const resolved = resolveShape(input, body, contextFn, caller);
@@ -5365,7 +5443,8 @@ function createModelGuardExtension(config) {
5365
5443
  "update",
5366
5444
  resolved.shape.data,
5367
5445
  resolved.matchedKey,
5368
- resolved.wasDynamic
5446
+ resolved.wasDynamic,
5447
+ allowRelationWrites
5369
5448
  );
5370
5449
  const data = validateAndMergeData(
5371
5450
  resolved.body.data,
@@ -5538,7 +5617,8 @@ function createModelGuardExtension(config) {
5538
5617
  "create",
5539
5618
  resolved.shape.create,
5540
5619
  `upsert:create\0${resolved.matchedKey}`,
5541
- resolved.wasDynamic
5620
+ resolved.wasDynamic,
5621
+ true
5542
5622
  );
5543
5623
  const createData = validateAndMergeData(
5544
5624
  resolved.body.create,
@@ -5550,7 +5630,8 @@ function createModelGuardExtension(config) {
5550
5630
  "update",
5551
5631
  resolved.shape.update,
5552
5632
  `upsert:update\0${resolved.matchedKey}`,
5553
- resolved.wasDynamic
5633
+ resolved.wasDynamic,
5634
+ true
5554
5635
  );
5555
5636
  const updateData = validateAndMergeData(
5556
5637
  resolved.body.update,
@@ -5583,6 +5664,7 @@ function createModelGuardExtension(config) {
5583
5664
  };
5584
5665
  }
5585
5666
  return {
5667
+ resolve: makeResolveMethod(),
5586
5668
  findMany: makeReadMethod("findMany"),
5587
5669
  findFirst: makeReadMethod("findFirst"),
5588
5670
  findFirstOrThrow: makeReadMethod("findFirstOrThrow"),