prisma-guard 1.28.1 → 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,7 +2974,12 @@ 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
@@ -2955,10 +2995,10 @@ var OPERATION_SHAPE_KEYS = {
2955
2995
  groupBy: ["where", "orderBy", "by", "having", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
2956
2996
  create: ["data", "include", "select"],
2957
2997
  createMany: ["data", "skipDuplicates"],
2958
- createManyAndReturn: ["data", "select", "skipDuplicates"],
2998
+ createManyAndReturn: ["data", "select", "include", "skipDuplicates"],
2959
2999
  update: ["where", "data", "include", "select"],
2960
3000
  updateMany: ["where", "data"],
2961
- updateManyAndReturn: ["where", "data", "select"],
3001
+ updateManyAndReturn: ["where", "data", "select", "include"],
2962
3002
  upsert: ["where", "create", "update", "include", "select"],
2963
3003
  delete: ["where", "include", "select"],
2964
3004
  deleteMany: ["where"]
@@ -3272,7 +3312,17 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
3272
3312
  let forcedIncludeCountWhere = {};
3273
3313
  let forcedSelectCountWhere = {};
3274
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
+ }
3275
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
+ }
3276
3326
  if (builtWhere.schema) {
3277
3327
  schemaFields.where = builtWhere.schema;
3278
3328
  }
@@ -4074,27 +4124,19 @@ function validateRelationOpKeys(actual, opKey, model, field, opLabel) {
4074
4124
  const allowed = RELATION_OP_ALLOWED_KEYS[opKey];
4075
4125
  if (!allowed)
4076
4126
  return;
4077
- for (const key of Object.keys(actual)) {
4078
- if (!allowed.has(key)) {
4079
- throw new ShapeError(
4080
- `Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
4081
- );
4082
- }
4083
- }
4127
+ assertAllowedKeys(
4128
+ actual,
4129
+ allowed,
4130
+ (key) => `Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
4131
+ );
4084
4132
  }
4085
4133
  function validateAllowedKeys(value, allowed, method, kind) {
4086
- for (const key of Object.keys(value)) {
4087
- if (!allowed.has(key)) {
4088
- if (kind === "body") {
4089
- throw new ShapeError(
4090
- `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`
4091
- );
4092
- }
4093
- throw new ShapeError(
4094
- `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`
4095
- );
4134
+ assertAllowedKeys(value, allowed, (key) => {
4135
+ if (kind === "body") {
4136
+ return `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`;
4096
4137
  }
4097
- }
4138
+ return `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`;
4139
+ });
4098
4140
  }
4099
4141
  function validateCreateCompleteness(modelName, dataConfig, typeMap, scopeFks, zodDefaults) {
4100
4142
  const modelFields = typeMap[modelName];
@@ -4181,18 +4223,10 @@ function buildNestedDataSchema(model, config, mode, typeMap, schemaBuilder) {
4181
4223
  }
4182
4224
  return import_zod10.z.object(fieldSchemas).strict();
4183
4225
  }
4184
- function requirePlainObjectConfig(value, message) {
4185
- if (!isPlainObject(value))
4186
- throw new ShapeError(message);
4187
- return value;
4188
- }
4189
4226
  function requireNestedObject(cfg, key, message) {
4190
- const v = cfg[key];
4191
- if (!v || !isPlainObject(v))
4192
- throw new ShapeError(message);
4193
- return v;
4227
+ return requirePlainObjectConfig(cfg[key], message);
4194
4228
  }
4195
- function buildUniqueSelector(ctx, cfg, context) {
4229
+ function buildRelatedUniqueSelector(ctx, cfg, context) {
4196
4230
  return buildUniqueSelectorSchema(
4197
4231
  ctx.model,
4198
4232
  ctx.fieldName,
@@ -4205,7 +4239,7 @@ function buildUniqueSelector(ctx, cfg, context) {
4205
4239
  context
4206
4240
  );
4207
4241
  }
4208
- function buildNestedData(ctx, cfg, mode) {
4242
+ function buildRelatedNestedData(ctx, cfg, mode) {
4209
4243
  return buildNestedDataSchema(
4210
4244
  ctx.relatedModelName,
4211
4245
  cfg,
@@ -4219,7 +4253,7 @@ var handleConnect = (ctx) => {
4219
4253
  ctx.config,
4220
4254
  `connect config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
4221
4255
  );
4222
- const schema = buildUniqueSelector(ctx, cfg, "connect");
4256
+ const schema = buildRelatedUniqueSelector(ctx, cfg, "connect");
4223
4257
  return wrapRelationOp(ctx.isList, schema);
4224
4258
  };
4225
4259
  var handleConnectOrCreate = (ctx) => {
@@ -4238,8 +4272,8 @@ var handleConnectOrCreate = (ctx) => {
4238
4272
  "create",
4239
4273
  `connectOrCreate on "${ctx.model}.${ctx.fieldName}" requires "create" object`
4240
4274
  );
4241
- const whereSchema = buildUniqueSelector(ctx, where, "connectOrCreate.where");
4242
- const createSchema = buildNestedData(ctx, create, "create");
4275
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "connectOrCreate.where");
4276
+ const createSchema = buildRelatedNestedData(ctx, create, "create");
4243
4277
  const cocSchema = import_zod10.z.object({ where: whereSchema, create: createSchema }).strict();
4244
4278
  return wrapRelationOp(ctx.isList, cocSchema);
4245
4279
  };
@@ -4248,7 +4282,7 @@ var handleCreate = (ctx) => {
4248
4282
  ctx.config,
4249
4283
  `create config on "${ctx.model}.${ctx.fieldName}" must be an object of field names`
4250
4284
  );
4251
- const createSchema = buildNestedData(ctx, cfg, "create");
4285
+ const createSchema = buildRelatedNestedData(ctx, cfg, "create");
4252
4286
  return wrapRelationOp(ctx.isList, createSchema);
4253
4287
  };
4254
4288
  var handleCreateMany = (ctx) => {
@@ -4267,7 +4301,7 @@ var handleCreateMany = (ctx) => {
4267
4301
  "data",
4268
4302
  `createMany on "${ctx.model}.${ctx.fieldName}" requires "data" object`
4269
4303
  );
4270
- const dataSchema = buildNestedData(ctx, data, "create");
4304
+ const dataSchema = buildRelatedNestedData(ctx, data, "create");
4271
4305
  const cmSchemaFields = {
4272
4306
  data: import_zod10.z.preprocess(coerceToArray, import_zod10.z.array(dataSchema))
4273
4307
  };
@@ -4290,7 +4324,7 @@ var handleDisconnect = (ctx) => {
4290
4324
  `disconnect config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
4291
4325
  );
4292
4326
  }
4293
- const schema = buildUniqueSelector(ctx, ctx.config, "disconnect");
4327
+ const schema = buildRelatedUniqueSelector(ctx, ctx.config, "disconnect");
4294
4328
  if (ctx.isList)
4295
4329
  return wrapRelationOp(true, schema);
4296
4330
  return import_zod10.z.union([import_zod10.z.literal(true), schema]).optional();
@@ -4309,7 +4343,7 @@ var handleDelete = (ctx) => {
4309
4343
  `delete config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
4310
4344
  );
4311
4345
  }
4312
- const schema = buildUniqueSelector(ctx, ctx.config, "delete");
4346
+ const schema = buildRelatedUniqueSelector(ctx, ctx.config, "delete");
4313
4347
  if (ctx.isList)
4314
4348
  return wrapRelationOp(true, schema);
4315
4349
  return import_zod10.z.union([import_zod10.z.literal(true), schema]).optional();
@@ -4324,7 +4358,7 @@ var handleSet = (ctx) => {
4324
4358
  ctx.config,
4325
4359
  `set config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
4326
4360
  );
4327
- const schema = buildUniqueSelector(ctx, cfg, "set");
4361
+ const schema = buildRelatedUniqueSelector(ctx, cfg, "set");
4328
4362
  return wrapRelationOp(true, schema);
4329
4363
  };
4330
4364
  var handleUpdate = (ctx) => {
@@ -4344,12 +4378,12 @@ var handleUpdate = (ctx) => {
4344
4378
  "data",
4345
4379
  `update on to-many "${ctx.model}.${ctx.fieldName}" requires "data" object`
4346
4380
  );
4347
- const whereSchema = buildUniqueSelector(ctx, where, "update.where");
4348
- const dataSchema2 = buildNestedData(ctx, data, "update");
4381
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "update.where");
4382
+ const dataSchema2 = buildRelatedNestedData(ctx, data, "update");
4349
4383
  const updateSchema = import_zod10.z.object({ where: whereSchema, data: dataSchema2 }).strict();
4350
4384
  return wrapRelationOp(true, updateSchema);
4351
4385
  }
4352
- const dataSchema = buildNestedData(ctx, cfg, "update");
4386
+ const dataSchema = buildRelatedNestedData(ctx, cfg, "update");
4353
4387
  return dataSchema.optional();
4354
4388
  };
4355
4389
  var handleUpsert = (ctx) => {
@@ -4374,15 +4408,15 @@ var handleUpsert = (ctx) => {
4374
4408
  "update",
4375
4409
  `upsert on "${ctx.model}.${ctx.fieldName}" requires "update" object`
4376
4410
  );
4377
- const createSchema = buildNestedData(ctx, create, "create");
4378
- const updateSchema = buildNestedData(ctx, update, "update");
4411
+ const createSchema = buildRelatedNestedData(ctx, create, "create");
4412
+ const updateSchema = buildRelatedNestedData(ctx, update, "update");
4379
4413
  if (ctx.isList) {
4380
4414
  const where = requireNestedObject(
4381
4415
  cfg,
4382
4416
  "where",
4383
4417
  `upsert on to-many "${ctx.model}.${ctx.fieldName}" requires "where" object`
4384
4418
  );
4385
- const whereSchema = buildUniqueSelector(ctx, where, "upsert.where");
4419
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "upsert.where");
4386
4420
  const upsertSchema2 = import_zod10.z.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
4387
4421
  return wrapRelationOp(true, upsertSchema2);
4388
4422
  }
@@ -4393,7 +4427,7 @@ var handleUpsert = (ctx) => {
4393
4427
  `upsert on to-one "${ctx.model}.${ctx.fieldName}" has invalid "where": must be a plain object of unique selectors`
4394
4428
  );
4395
4429
  }
4396
- const whereSchema = buildUniqueSelector(ctx, cfg.where, "upsert.where");
4430
+ const whereSchema = buildRelatedUniqueSelector(ctx, cfg.where, "upsert.where");
4397
4431
  const upsertSchema2 = import_zod10.z.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
4398
4432
  return upsertSchema2.optional();
4399
4433
  }
@@ -4437,7 +4471,7 @@ var handleUpdateMany = (ctx) => {
4437
4471
  ctx.typeMap,
4438
4472
  ctx.schemaBuilder
4439
4473
  );
4440
- const dataSchema = buildNestedData(ctx, data, "update");
4474
+ const dataSchema = buildRelatedNestedData(ctx, data, "update");
4441
4475
  const umSchema = import_zod10.z.object({ where: whereSchema, data: dataSchema }).strict();
4442
4476
  return wrapRelationOp(true, umSchema);
4443
4477
  };
@@ -4484,17 +4518,21 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
4484
4518
  throw new ShapeError(
4485
4519
  `Unknown related model "${relatedModelName}" for field "${model}.${fieldName}"`
4486
4520
  );
4487
- for (const key of Object.keys(config)) {
4488
- if (!KNOWN_RELATION_WRITE_OPS.has(key)) {
4489
- throw new ShapeError(
4490
- `Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
4491
- );
4492
- }
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
+ );
4493
4533
  }
4494
4534
  const opSchemas = {};
4495
- for (const [op, opConfig] of Object.entries(config)) {
4496
- if (opConfig === void 0)
4497
- continue;
4535
+ for (const [op, opConfig] of definedEntries) {
4498
4536
  const handler = RELATION_OP_HANDLERS[op];
4499
4537
  opSchemas[op] = handler({
4500
4538
  model,
@@ -4511,7 +4549,7 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
4511
4549
  }
4512
4550
  return import_zod10.z.object(opSchemas).strict();
4513
4551
  }
4514
- function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults) {
4552
+ function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults, allowRelationWrites) {
4515
4553
  const modelFields = typeMap[model];
4516
4554
  if (!modelFields)
4517
4555
  throw new ShapeError(`Unknown model: ${model}`);
@@ -4541,6 +4579,11 @@ function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, s
4541
4579
  continue;
4542
4580
  }
4543
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
+ }
4544
4587
  if (!isPlainObject(value)) {
4545
4588
  throw new ShapeError(
4546
4589
  `Relation field "${fieldName}" on model "${model}" requires a relation write config object`
@@ -4654,13 +4697,8 @@ function validateAndMergeData(bodyData, cached, method, modelName) {
4654
4697
  try {
4655
4698
  validated = cached.schema.parse(bodyData);
4656
4699
  } catch (err) {
4657
- if (err instanceof ShapeError)
4658
- throw err;
4659
- if (err && typeof err === "object" && "issues" in err) {
4660
- const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
4661
- throw new ShapeError(`${context}: ${formatZodError(err)}`, { cause: err });
4662
- }
4663
- throw err;
4700
+ const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
4701
+ wrapParseError(err, context);
4664
4702
  }
4665
4703
  return { ...validated, ...deepClone(cached.forced) };
4666
4704
  }
@@ -4815,6 +4853,8 @@ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
4815
4853
  "updateManyAndReturn"
4816
4854
  ]);
4817
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"]);
4818
4858
  var MAX_PROJECTION_WALK_DEPTH = 10;
4819
4859
  function walkForClientContent(obj, predicate, depth) {
4820
4860
  if (depth > MAX_PROJECTION_WALK_DEPTH)
@@ -4965,11 +5005,11 @@ function createModelGuardExtension(config) {
4965
5005
  )
4966
5006
  );
4967
5007
  }
4968
- function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
5008
+ function getDataSchema(mode, dataConfig, matchedKey, wasDynamic, allowRelationWrites) {
4969
5009
  const skipCache = wasDynamic || hasDataRefines(dataConfig);
4970
5010
  return memoize(
4971
5011
  dataSchemaCache,
4972
- `${mode}\0${matchedKey}`,
5012
+ `${mode}\0${matchedKey}\0${allowRelationWrites ? "r" : "n"}`,
4973
5013
  skipCache,
4974
5014
  () => buildDataSchema(
4975
5015
  modelName,
@@ -4980,7 +5020,8 @@ function createModelGuardExtension(config) {
4980
5020
  enumMap,
4981
5021
  scalarBase,
4982
5022
  schemaBuilder,
4983
- zodDefaults
5023
+ zodDefaults,
5024
+ allowRelationWrites
4984
5025
  )
4985
5026
  );
4986
5027
  }
@@ -5238,6 +5279,39 @@ function createModelGuardExtension(config) {
5238
5279
  const defaultProjection = buildDefaultProjectionBody(resolved.shape);
5239
5280
  return { ...resolved.body, ...defaultProjection };
5240
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
+ }
5241
5315
  function makeReadMethod(method) {
5242
5316
  return (body) => {
5243
5317
  const caller = resolveCaller();
@@ -5271,6 +5345,7 @@ function createModelGuardExtension(config) {
5271
5345
  const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
5272
5346
  const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
5273
5347
  const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
5348
+ const allowRelationWrites = RELATION_WRITE_CREATE_METHODS.has(method);
5274
5349
  return (body) => {
5275
5350
  const caller = resolveCaller();
5276
5351
  const resolved = resolveShape(input, body, contextFn, caller);
@@ -5296,7 +5371,8 @@ function createModelGuardExtension(config) {
5296
5371
  "create",
5297
5372
  resolved.shape.data,
5298
5373
  resolved.matchedKey,
5299
- resolved.wasDynamic
5374
+ resolved.wasDynamic,
5375
+ allowRelationWrites
5300
5376
  );
5301
5377
  let args;
5302
5378
  if (method === "create") {
@@ -5344,6 +5420,7 @@ function createModelGuardExtension(config) {
5344
5420
  const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
5345
5421
  const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
5346
5422
  const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
5423
+ const allowRelationWrites = RELATION_WRITE_UPDATE_METHODS.has(method);
5347
5424
  return (body) => {
5348
5425
  const caller = resolveCaller();
5349
5426
  const resolved = resolveShape(input, body, contextFn, caller);
@@ -5366,7 +5443,8 @@ function createModelGuardExtension(config) {
5366
5443
  "update",
5367
5444
  resolved.shape.data,
5368
5445
  resolved.matchedKey,
5369
- resolved.wasDynamic
5446
+ resolved.wasDynamic,
5447
+ allowRelationWrites
5370
5448
  );
5371
5449
  const data = validateAndMergeData(
5372
5450
  resolved.body.data,
@@ -5539,7 +5617,8 @@ function createModelGuardExtension(config) {
5539
5617
  "create",
5540
5618
  resolved.shape.create,
5541
5619
  `upsert:create\0${resolved.matchedKey}`,
5542
- resolved.wasDynamic
5620
+ resolved.wasDynamic,
5621
+ true
5543
5622
  );
5544
5623
  const createData = validateAndMergeData(
5545
5624
  resolved.body.create,
@@ -5551,7 +5630,8 @@ function createModelGuardExtension(config) {
5551
5630
  "update",
5552
5631
  resolved.shape.update,
5553
5632
  `upsert:update\0${resolved.matchedKey}`,
5554
- resolved.wasDynamic
5633
+ resolved.wasDynamic,
5634
+ true
5555
5635
  );
5556
5636
  const updateData = validateAndMergeData(
5557
5637
  resolved.body.update,
@@ -5584,6 +5664,7 @@ function createModelGuardExtension(config) {
5584
5664
  };
5585
5665
  }
5586
5666
  return {
5667
+ resolve: makeResolveMethod(),
5587
5668
  findMany: makeReadMethod("findMany"),
5588
5669
  findFirst: makeReadMethod("findFirst"),
5589
5670
  findFirstOrThrow: makeReadMethod("findFirstOrThrow"),