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.
@@ -212,7 +212,7 @@ function createScalarBase(strictDecimal) {
212
212
  return {
213
213
  String: () => z.string(),
214
214
  Int: () => z.number().int(),
215
- Float: () => z.number(),
215
+ Float: () => z.number().finite(),
216
216
  Decimal: createDecimalFactory(strictDecimal),
217
217
  BigInt: () => z.union([
218
218
  z.bigint(),
@@ -353,6 +353,19 @@ function requireConfigTrue(config, context) {
353
353
  }
354
354
  }
355
355
  }
356
+ function requirePlainObjectConfig(value, message) {
357
+ if (!isPlainObject(value)) {
358
+ throw new ShapeError(message);
359
+ }
360
+ return value;
361
+ }
362
+ function assertAllowedKeys(value, allowed, makeError) {
363
+ for (const key of Object.keys(value)) {
364
+ if (!allowed.has(key)) {
365
+ throw new ShapeError(makeError(key));
366
+ }
367
+ }
368
+ }
356
369
 
357
370
  // src/runtime/zod-type-map.ts
358
371
  var SCALAR_OPERATORS = {
@@ -416,24 +429,12 @@ var JSON_ARRAY_OPERATORS = /* @__PURE__ */ new Set([
416
429
  "array_starts_with",
417
430
  "array_ends_with"
418
431
  ]);
419
- function getSupportedOperators(input, isList = false, isEnum = false) {
420
- let fieldType;
421
- let list;
422
- let enumField;
423
- if (typeof input === "string") {
424
- fieldType = input;
425
- list = isList;
426
- enumField = isEnum;
427
- } else {
428
- fieldType = input.type;
429
- list = input.isList;
430
- enumField = input.isEnum === true;
431
- }
432
- if (list)
432
+ function getSupportedOperators(fieldMeta) {
433
+ if (fieldMeta.isList)
433
434
  return [...SCALAR_LIST_OPERATORS];
434
- if (enumField)
435
+ if (fieldMeta.isEnum === true)
435
436
  return [...ENUM_OPERATORS];
436
- const ops = SCALAR_OPERATORS[fieldType];
437
+ const ops = SCALAR_OPERATORS[fieldMeta.type];
437
438
  if (!ops)
438
439
  return [];
439
440
  return [...ops];
@@ -998,6 +999,7 @@ function validateContext(ctx) {
998
999
 
999
1000
  // src/runtime/query-builder-where.ts
1000
1001
  import { z as z5 } from "zod";
1002
+ import { inspect } from "util";
1001
1003
 
1002
1004
  // src/shared/deep-clone.ts
1003
1005
  function deepClone(value) {
@@ -1278,15 +1280,10 @@ function applyBuiltShape(built, body, isUniqueMethod, modelName) {
1278
1280
  try {
1279
1281
  validated = built.zodSchema.parse(parseable);
1280
1282
  } catch (err) {
1281
- if (err instanceof ShapeError)
1282
- throw err;
1283
- if (err && typeof err === "object" && "issues" in err) {
1284
- const context = modelName ? `Invalid query on model "${modelName}"` : "Invalid query";
1285
- throw new ShapeError(`${context}: ${formatZodError(err)}`, {
1286
- cause: err
1287
- });
1288
- }
1289
- throw err;
1283
+ wrapParseError(
1284
+ err,
1285
+ modelName ? `Invalid query on model "${modelName}"` : "Invalid query"
1286
+ );
1290
1287
  }
1291
1288
  if (hasWhereForced(built.forcedWhere)) {
1292
1289
  validated.where = isUniqueMethod ? mergeUniqueWhereForced(
@@ -1603,37 +1600,8 @@ var JSON_STRING_MODE_OPS = /* @__PURE__ */ new Set([
1603
1600
  ]);
1604
1601
  var NEGATIVE_RELATION_OPS = /* @__PURE__ */ new Set(["none", "isNot"]);
1605
1602
  var MAX_WHERE_DEPTH = 10;
1606
- function safeStringify(value) {
1607
- if (typeof value === "bigint")
1608
- return `${value}n`;
1609
- if (typeof value === "undefined")
1610
- return "undefined";
1611
- if (typeof value === "function")
1612
- return "[function]";
1613
- if (typeof value === "symbol")
1614
- return value.toString();
1615
- const seen = /* @__PURE__ */ new WeakSet();
1616
- try {
1617
- const json = JSON.stringify(value, (_key, current) => {
1618
- if (typeof current === "bigint")
1619
- return `${current}n`;
1620
- if (typeof current === "undefined")
1621
- return "[undefined]";
1622
- if (typeof current === "function")
1623
- return "[function]";
1624
- if (typeof current === "symbol")
1625
- return current.toString();
1626
- if (current && typeof current === "object") {
1627
- if (seen.has(current))
1628
- return "[Circular]";
1629
- seen.add(current);
1630
- }
1631
- return current;
1632
- });
1633
- return json === void 0 ? String(value) : json;
1634
- } catch {
1635
- return String(value);
1636
- }
1603
+ function formatValue(value) {
1604
+ return inspect(value, { depth: 3, breakLength: Infinity });
1637
1605
  }
1638
1606
  function mergeScalarConditions(target, source) {
1639
1607
  for (const [field, ops] of Object.entries(source)) {
@@ -1654,7 +1622,7 @@ function mergeScalarConditions(target, source) {
1654
1622
  const existingVal = existing[op];
1655
1623
  if (!deepEqual(existingVal, val)) {
1656
1624
  throw new ShapeError(
1657
- `Conflicting forced where values for "${field}.${op}": shape defines both ${safeStringify(existingVal)} and ${safeStringify(val)}`
1625
+ `Conflicting forced where values for "${field}.${op}": shape defines both ${formatValue(existingVal)} and ${formatValue(val)}`
1658
1626
  );
1659
1627
  }
1660
1628
  }
@@ -2492,10 +2460,7 @@ function createArgsBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
2492
2460
  `${fieldMeta.type} field "${fieldName}" cannot be used in having`
2493
2461
  );
2494
2462
  }
2495
- const allowedOps = getSupportedOperators(
2496
- fieldMeta.type,
2497
- fieldMeta.isList
2498
- );
2463
+ const allowedOps = getSupportedOperators(fieldMeta);
2499
2464
  const opSchemas = {};
2500
2465
  for (const op of allowedOps) {
2501
2466
  opSchemas[op] = createOperatorSchema(
@@ -2672,20 +2637,27 @@ function buildDefaultProjectionBody(shape) {
2672
2637
 
2673
2638
  // src/runtime/query-builder-projection.ts
2674
2639
  var KNOWN_NESTED_KEYS = {
2675
- include: /* @__PURE__ */ new Set(["where", "include", "select", "orderBy", "cursor", "take", "skip"]),
2676
- select: /* @__PURE__ */ new Set(["select", "include", "where", "orderBy", "cursor", "take", "skip"])
2640
+ include: /* @__PURE__ */ new Set([
2641
+ "where",
2642
+ "include",
2643
+ "select",
2644
+ "orderBy",
2645
+ "cursor",
2646
+ "take",
2647
+ "skip"
2648
+ ]),
2649
+ select: /* @__PURE__ */ new Set([
2650
+ "select",
2651
+ "include",
2652
+ "where",
2653
+ "orderBy",
2654
+ "cursor",
2655
+ "take",
2656
+ "skip"
2657
+ ])
2677
2658
  };
2678
2659
  var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
2679
2660
  var MAX_PROJECTION_DEPTH = 10;
2680
- function validateNestedKeys(keys, allowed, context) {
2681
- for (const key of keys) {
2682
- if (!allowed.has(key)) {
2683
- throw new ShapeError(
2684
- `Unknown key "${key}" in ${context}. Allowed: ${[...allowed].join(", ")}`
2685
- );
2686
- }
2687
- }
2688
- }
2689
2661
  function hasDefinedKeys(v) {
2690
2662
  return Object.values(v).some((value) => value !== void 0);
2691
2663
  }
@@ -2698,6 +2670,20 @@ function wrapRelationSchema(nestedObj, skeleton) {
2698
2670
  collapsed
2699
2671
  );
2700
2672
  }
2673
+ function buildRelationWhere(relatedType, whereConfig, context, buildWhereSchema) {
2674
+ if (Object.keys(whereConfig).length === 0) {
2675
+ throw new ShapeError(
2676
+ `Empty "where" in ${context}. Define at least one field.`
2677
+ );
2678
+ }
2679
+ const { schema, forced } = buildWhereSchema(relatedType, whereConfig);
2680
+ if (!schema && !hasWhereForced(forced)) {
2681
+ throw new ShapeError(
2682
+ `"where" in ${context} produced no schema and no forced conditions. Define at least one field.`
2683
+ );
2684
+ }
2685
+ return { schema, forced };
2686
+ }
2701
2687
  function createProjectionBuilder(typeMap, _enumMap, deps) {
2702
2688
  function buildIncludeCountSchema(model, config) {
2703
2689
  const modelFields = typeMap[model];
@@ -2711,13 +2697,11 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2711
2697
  `Invalid _count config on model "${model}". Expected true or { select: { ... } }`
2712
2698
  );
2713
2699
  }
2714
- for (const key of Object.keys(config)) {
2715
- if (key !== "select") {
2716
- throw new ShapeError(
2717
- `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
2718
- );
2719
- }
2720
- }
2700
+ assertAllowedKeys(
2701
+ config,
2702
+ /* @__PURE__ */ new Set(["select"]),
2703
+ (key) => `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
2704
+ );
2721
2705
  if (!isPlainObject(config.select)) {
2722
2706
  throw new ShapeError(
2723
2707
  `Invalid _count.select on model "${model}". Expected a plain object with relation field keys.`
@@ -2734,11 +2718,17 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2734
2718
  for (const [fieldName, fieldConfig] of Object.entries(selectObj)) {
2735
2719
  const fieldMeta = modelFields[fieldName];
2736
2720
  if (!fieldMeta)
2737
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}" in _count.select`);
2721
+ throw new ShapeError(
2722
+ `Unknown field "${fieldName}" on model "${model}" in _count.select`
2723
+ );
2738
2724
  if (!fieldMeta.isRelation)
2739
- throw new ShapeError(`Field "${fieldName}" is not a relation on model "${model}" in _count.select`);
2725
+ throw new ShapeError(
2726
+ `Field "${fieldName}" is not a relation on model "${model}" in _count.select`
2727
+ );
2740
2728
  if (!fieldMeta.isList)
2741
- throw new ShapeError(`Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`);
2729
+ throw new ShapeError(
2730
+ `Field "${fieldName}" is a to-one relation on model "${model}" in _count.select. Only to-many relations support _count.`
2731
+ );
2742
2732
  if (fieldConfig === true) {
2743
2733
  countSelectFields[fieldName] = z7.literal(true).optional();
2744
2734
  continue;
@@ -2753,16 +2743,18 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2753
2743
  `Empty config for _count.select.${fieldName} on model "${model}". Use true or { where: { ... } }.`
2754
2744
  );
2755
2745
  }
2756
- validateNestedKeys(
2757
- Object.keys(fieldConfig),
2746
+ assertAllowedKeys(
2747
+ fieldConfig,
2758
2748
  KNOWN_COUNT_SELECT_ENTRY_KEYS,
2759
- `_count.select.${fieldName} on model "${model}"`
2749
+ (key) => `Unknown key "${key}" in _count.select.${fieldName} on model "${model}". Allowed: ${[...KNOWN_COUNT_SELECT_ENTRY_KEYS].join(", ")}`
2760
2750
  );
2761
2751
  if (fieldConfig.where) {
2762
2752
  const relatedType = fieldMeta.type;
2763
- const { schema: whereSchema, forced } = deps.buildWhereSchema(
2753
+ const { schema: whereSchema, forced } = buildRelationWhere(
2764
2754
  relatedType,
2765
- fieldConfig.where
2755
+ fieldConfig.where,
2756
+ `_count.select.${fieldName} on model "${model}"`,
2757
+ deps.buildWhereSchema
2766
2758
  );
2767
2759
  const nestedSchemas = {};
2768
2760
  if (whereSchema)
@@ -2785,13 +2777,15 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2785
2777
  forcedCountWhere
2786
2778
  };
2787
2779
  }
2788
- function buildNestedRelSchemas(relatedType, config, depth) {
2780
+ function buildNestedRelSchemas(relatedType, config, depth, context) {
2789
2781
  const nestedSchemas = {};
2790
2782
  const relForced = {};
2791
2783
  if (config.where) {
2792
- const { schema: whereSchema, forced } = deps.buildWhereSchema(
2784
+ const { schema: whereSchema, forced } = buildRelationWhere(
2793
2785
  relatedType,
2794
- config.where
2786
+ config.where,
2787
+ context,
2788
+ deps.buildWhereSchema
2795
2789
  );
2796
2790
  if (whereSchema)
2797
2791
  nestedSchemas["where"] = whereSchema;
@@ -2799,7 +2793,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2799
2793
  relForced.where = forced;
2800
2794
  }
2801
2795
  if (config.include) {
2802
- const nested = buildProjectionSchema("include", relatedType, config.include, depth + 1);
2796
+ const nested = buildProjectionSchema(
2797
+ "include",
2798
+ relatedType,
2799
+ config.include,
2800
+ depth + 1
2801
+ );
2803
2802
  nestedSchemas["include"] = nested.schema;
2804
2803
  if (Object.keys(nested.forcedTree).length > 0)
2805
2804
  relForced.include = nested.forcedTree;
@@ -2809,7 +2808,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2809
2808
  }
2810
2809
  }
2811
2810
  if (config.select) {
2812
- const nested = buildProjectionSchema("select", relatedType, config.select, depth + 1);
2811
+ const nested = buildProjectionSchema(
2812
+ "select",
2813
+ relatedType,
2814
+ config.select,
2815
+ depth + 1
2816
+ );
2813
2817
  nestedSchemas["select"] = nested.schema;
2814
2818
  if (Object.keys(nested.forcedTree).length > 0)
2815
2819
  relForced.select = nested.forcedTree;
@@ -2819,15 +2823,26 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2819
2823
  }
2820
2824
  }
2821
2825
  if (config.orderBy) {
2822
- nestedSchemas["orderBy"] = deps.buildOrderBySchema(relatedType, config.orderBy);
2826
+ nestedSchemas["orderBy"] = deps.buildOrderBySchema(
2827
+ relatedType,
2828
+ config.orderBy
2829
+ );
2823
2830
  }
2824
2831
  if (config.cursor) {
2825
- nestedSchemas["cursor"] = deps.buildCursorSchema(relatedType, config.cursor);
2832
+ nestedSchemas["cursor"] = deps.buildCursorSchema(
2833
+ relatedType,
2834
+ config.cursor
2835
+ );
2826
2836
  }
2827
- if (config.take) {
2837
+ if ("take" in config && config.take !== void 0) {
2828
2838
  nestedSchemas["take"] = deps.buildTakeSchema(config.take);
2829
2839
  }
2830
- if (config.skip) {
2840
+ if ("skip" in config && config.skip !== void 0) {
2841
+ if (config.skip !== true) {
2842
+ throw new ShapeError(
2843
+ `Nested "skip" in ${context} must be true`
2844
+ );
2845
+ }
2831
2846
  nestedSchemas["skip"] = z7.number().int().min(0).optional();
2832
2847
  }
2833
2848
  return { nestedSchemas, relForced };
@@ -2853,28 +2868,43 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2853
2868
  let topLevelForcedCountWhere = {};
2854
2869
  for (const [fieldName, config] of Object.entries(projectionConfig)) {
2855
2870
  if (fieldName === "_count") {
2856
- const countResult = buildIncludeCountSchema(model, config);
2871
+ const countResult = buildIncludeCountSchema(
2872
+ model,
2873
+ config
2874
+ );
2857
2875
  fieldSchemas["_count"] = countResult.schema;
2858
2876
  topLevelForcedCountWhere = countResult.forcedCountWhere;
2859
2877
  continue;
2860
2878
  }
2861
2879
  const fieldMeta = modelFields[fieldName];
2862
2880
  if (!fieldMeta)
2863
- throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
2881
+ throw new ShapeError(
2882
+ `Unknown field "${fieldName}" on model "${model}"`
2883
+ );
2864
2884
  if (mode === "include" && !fieldMeta.isRelation) {
2865
- throw new ShapeError(`Field "${fieldName}" is not a relation on model "${model}"`);
2885
+ throw new ShapeError(
2886
+ `Field "${fieldName}" is not a relation on model "${model}"`
2887
+ );
2866
2888
  }
2867
2889
  if (config === true) {
2868
2890
  fieldSchemas[fieldName] = z7.literal(true).optional();
2869
2891
  continue;
2870
2892
  }
2871
2893
  if (mode === "select" && !fieldMeta.isRelation) {
2872
- throw new ShapeError(`Nested select args only valid for relations, not scalar "${fieldName}" on model "${model}"`);
2894
+ throw new ShapeError(
2895
+ `Nested select args only valid for relations, not scalar "${fieldName}" on model "${model}"`
2896
+ );
2873
2897
  }
2874
2898
  const contextLabel = `nested ${mode} for "${fieldName}" on model "${model}"`;
2875
- validateNestedKeys(Object.keys(config), allowedNestedKeys, contextLabel);
2899
+ assertAllowedKeys(
2900
+ config,
2901
+ allowedNestedKeys,
2902
+ (key) => `Unknown key "${key}" in ${contextLabel}. Allowed: ${[...allowedNestedKeys].join(", ")}`
2903
+ );
2876
2904
  if (config.select && config.include) {
2877
- throw new ShapeError(`Nested ${mode} for "${fieldName}" cannot define both "select" and "include".`);
2905
+ throw new ShapeError(
2906
+ `Nested ${mode} for "${fieldName}" cannot define both "select" and "include".`
2907
+ );
2878
2908
  }
2879
2909
  if (!fieldMeta.isList) {
2880
2910
  if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
@@ -2883,7 +2913,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2883
2913
  );
2884
2914
  }
2885
2915
  }
2886
- const { nestedSchemas, relForced } = buildNestedRelSchemas(fieldMeta.type, config, currentDepth);
2916
+ const { nestedSchemas, relForced } = buildNestedRelSchemas(
2917
+ fieldMeta.type,
2918
+ config,
2919
+ currentDepth,
2920
+ contextLabel
2921
+ );
2887
2922
  const nestedObj = z7.object(nestedSchemas).strict();
2888
2923
  fieldSchemas[fieldName] = wrapRelationSchema(
2889
2924
  nestedObj,
@@ -2908,7 +2943,12 @@ function createProjectionBuilder(typeMap, _enumMap, deps) {
2908
2943
  function buildSelectSchema(model, selectConfig, depth) {
2909
2944
  return buildProjectionSchema("select", model, selectConfig, depth);
2910
2945
  }
2911
- return { buildIncludeSchema, buildSelectSchema, buildIncludeCountSchema, buildProjectionSchema };
2946
+ return {
2947
+ buildIncludeSchema,
2948
+ buildSelectSchema,
2949
+ buildIncludeCountSchema,
2950
+ buildProjectionSchema
2951
+ };
2912
2952
  }
2913
2953
 
2914
2954
  // src/shared/operation-shape-keys.ts
@@ -2924,10 +2964,10 @@ var OPERATION_SHAPE_KEYS = {
2924
2964
  groupBy: ["where", "orderBy", "by", "having", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
2925
2965
  create: ["data", "include", "select"],
2926
2966
  createMany: ["data", "skipDuplicates"],
2927
- createManyAndReturn: ["data", "select", "skipDuplicates"],
2967
+ createManyAndReturn: ["data", "select", "include", "skipDuplicates"],
2928
2968
  update: ["where", "data", "include", "select"],
2929
2969
  updateMany: ["where", "data"],
2930
- updateManyAndReturn: ["where", "data", "select"],
2970
+ updateManyAndReturn: ["where", "data", "select", "include"],
2931
2971
  upsert: ["where", "create", "update", "include", "select"],
2932
2972
  delete: ["where", "include", "select"],
2933
2973
  deleteMany: ["where"]
@@ -3241,7 +3281,17 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
3241
3281
  let forcedIncludeCountWhere = {};
3242
3282
  let forcedSelectCountWhere = {};
3243
3283
  if (shape.where) {
3284
+ if (Object.keys(shape.where).length === 0) {
3285
+ throw new ShapeError(
3286
+ `Empty "where" in shape for model "${model}" method "${method}". Define at least one field.`
3287
+ );
3288
+ }
3244
3289
  const builtWhere = UNIQUE_WHERE_METHODS.has(method) ? whereBuilder.buildUniqueWhereSchema(model, shape.where) : whereBuilder.buildWhereSchema(model, shape.where);
3290
+ if (!builtWhere.schema && !hasWhereForced(builtWhere.forced)) {
3291
+ throw new ShapeError(
3292
+ `"where" in shape for model "${model}" method "${method}" produced no schema and no forced conditions.`
3293
+ );
3294
+ }
3245
3295
  if (builtWhere.schema) {
3246
3296
  schemaFields.where = builtWhere.schema;
3247
3297
  }
@@ -4043,27 +4093,19 @@ function validateRelationOpKeys(actual, opKey, model, field, opLabel) {
4043
4093
  const allowed = RELATION_OP_ALLOWED_KEYS[opKey];
4044
4094
  if (!allowed)
4045
4095
  return;
4046
- for (const key of Object.keys(actual)) {
4047
- if (!allowed.has(key)) {
4048
- throw new ShapeError(
4049
- `Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
4050
- );
4051
- }
4052
- }
4096
+ assertAllowedKeys(
4097
+ actual,
4098
+ allowed,
4099
+ (key) => `Unknown key "${key}" in ${opLabel} config on "${model}.${field}". Allowed: ${[...allowed].join(", ")}`
4100
+ );
4053
4101
  }
4054
4102
  function validateAllowedKeys(value, allowed, method, kind) {
4055
- for (const key of Object.keys(value)) {
4056
- if (!allowed.has(key)) {
4057
- if (kind === "body") {
4058
- throw new ShapeError(
4059
- `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`
4060
- );
4061
- }
4062
- throw new ShapeError(
4063
- `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`
4064
- );
4103
+ assertAllowedKeys(value, allowed, (key) => {
4104
+ if (kind === "body") {
4105
+ return `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`;
4065
4106
  }
4066
- }
4107
+ return `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`;
4108
+ });
4067
4109
  }
4068
4110
  function validateCreateCompleteness(modelName, dataConfig, typeMap, scopeFks, zodDefaults) {
4069
4111
  const modelFields = typeMap[modelName];
@@ -4150,18 +4192,10 @@ function buildNestedDataSchema(model, config, mode, typeMap, schemaBuilder) {
4150
4192
  }
4151
4193
  return z10.object(fieldSchemas).strict();
4152
4194
  }
4153
- function requirePlainObjectConfig(value, message) {
4154
- if (!isPlainObject(value))
4155
- throw new ShapeError(message);
4156
- return value;
4157
- }
4158
4195
  function requireNestedObject(cfg, key, message) {
4159
- const v = cfg[key];
4160
- if (!v || !isPlainObject(v))
4161
- throw new ShapeError(message);
4162
- return v;
4196
+ return requirePlainObjectConfig(cfg[key], message);
4163
4197
  }
4164
- function buildUniqueSelector(ctx, cfg, context) {
4198
+ function buildRelatedUniqueSelector(ctx, cfg, context) {
4165
4199
  return buildUniqueSelectorSchema(
4166
4200
  ctx.model,
4167
4201
  ctx.fieldName,
@@ -4174,7 +4208,7 @@ function buildUniqueSelector(ctx, cfg, context) {
4174
4208
  context
4175
4209
  );
4176
4210
  }
4177
- function buildNestedData(ctx, cfg, mode) {
4211
+ function buildRelatedNestedData(ctx, cfg, mode) {
4178
4212
  return buildNestedDataSchema(
4179
4213
  ctx.relatedModelName,
4180
4214
  cfg,
@@ -4188,7 +4222,7 @@ var handleConnect = (ctx) => {
4188
4222
  ctx.config,
4189
4223
  `connect config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
4190
4224
  );
4191
- const schema = buildUniqueSelector(ctx, cfg, "connect");
4225
+ const schema = buildRelatedUniqueSelector(ctx, cfg, "connect");
4192
4226
  return wrapRelationOp(ctx.isList, schema);
4193
4227
  };
4194
4228
  var handleConnectOrCreate = (ctx) => {
@@ -4207,8 +4241,8 @@ var handleConnectOrCreate = (ctx) => {
4207
4241
  "create",
4208
4242
  `connectOrCreate on "${ctx.model}.${ctx.fieldName}" requires "create" object`
4209
4243
  );
4210
- const whereSchema = buildUniqueSelector(ctx, where, "connectOrCreate.where");
4211
- const createSchema = buildNestedData(ctx, create, "create");
4244
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "connectOrCreate.where");
4245
+ const createSchema = buildRelatedNestedData(ctx, create, "create");
4212
4246
  const cocSchema = z10.object({ where: whereSchema, create: createSchema }).strict();
4213
4247
  return wrapRelationOp(ctx.isList, cocSchema);
4214
4248
  };
@@ -4217,7 +4251,7 @@ var handleCreate = (ctx) => {
4217
4251
  ctx.config,
4218
4252
  `create config on "${ctx.model}.${ctx.fieldName}" must be an object of field names`
4219
4253
  );
4220
- const createSchema = buildNestedData(ctx, cfg, "create");
4254
+ const createSchema = buildRelatedNestedData(ctx, cfg, "create");
4221
4255
  return wrapRelationOp(ctx.isList, createSchema);
4222
4256
  };
4223
4257
  var handleCreateMany = (ctx) => {
@@ -4236,7 +4270,7 @@ var handleCreateMany = (ctx) => {
4236
4270
  "data",
4237
4271
  `createMany on "${ctx.model}.${ctx.fieldName}" requires "data" object`
4238
4272
  );
4239
- const dataSchema = buildNestedData(ctx, data, "create");
4273
+ const dataSchema = buildRelatedNestedData(ctx, data, "create");
4240
4274
  const cmSchemaFields = {
4241
4275
  data: z10.preprocess(coerceToArray, z10.array(dataSchema))
4242
4276
  };
@@ -4259,7 +4293,7 @@ var handleDisconnect = (ctx) => {
4259
4293
  `disconnect config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
4260
4294
  );
4261
4295
  }
4262
- const schema = buildUniqueSelector(ctx, ctx.config, "disconnect");
4296
+ const schema = buildRelatedUniqueSelector(ctx, ctx.config, "disconnect");
4263
4297
  if (ctx.isList)
4264
4298
  return wrapRelationOp(true, schema);
4265
4299
  return z10.union([z10.literal(true), schema]).optional();
@@ -4278,7 +4312,7 @@ var handleDelete = (ctx) => {
4278
4312
  `delete config on "${ctx.model}.${ctx.fieldName}" must be true (to-one) or an object of unique selectors`
4279
4313
  );
4280
4314
  }
4281
- const schema = buildUniqueSelector(ctx, ctx.config, "delete");
4315
+ const schema = buildRelatedUniqueSelector(ctx, ctx.config, "delete");
4282
4316
  if (ctx.isList)
4283
4317
  return wrapRelationOp(true, schema);
4284
4318
  return z10.union([z10.literal(true), schema]).optional();
@@ -4293,7 +4327,7 @@ var handleSet = (ctx) => {
4293
4327
  ctx.config,
4294
4328
  `set config on "${ctx.model}.${ctx.fieldName}" must be an object of unique selectors`
4295
4329
  );
4296
- const schema = buildUniqueSelector(ctx, cfg, "set");
4330
+ const schema = buildRelatedUniqueSelector(ctx, cfg, "set");
4297
4331
  return wrapRelationOp(true, schema);
4298
4332
  };
4299
4333
  var handleUpdate = (ctx) => {
@@ -4313,12 +4347,12 @@ var handleUpdate = (ctx) => {
4313
4347
  "data",
4314
4348
  `update on to-many "${ctx.model}.${ctx.fieldName}" requires "data" object`
4315
4349
  );
4316
- const whereSchema = buildUniqueSelector(ctx, where, "update.where");
4317
- const dataSchema2 = buildNestedData(ctx, data, "update");
4350
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "update.where");
4351
+ const dataSchema2 = buildRelatedNestedData(ctx, data, "update");
4318
4352
  const updateSchema = z10.object({ where: whereSchema, data: dataSchema2 }).strict();
4319
4353
  return wrapRelationOp(true, updateSchema);
4320
4354
  }
4321
- const dataSchema = buildNestedData(ctx, cfg, "update");
4355
+ const dataSchema = buildRelatedNestedData(ctx, cfg, "update");
4322
4356
  return dataSchema.optional();
4323
4357
  };
4324
4358
  var handleUpsert = (ctx) => {
@@ -4343,15 +4377,15 @@ var handleUpsert = (ctx) => {
4343
4377
  "update",
4344
4378
  `upsert on "${ctx.model}.${ctx.fieldName}" requires "update" object`
4345
4379
  );
4346
- const createSchema = buildNestedData(ctx, create, "create");
4347
- const updateSchema = buildNestedData(ctx, update, "update");
4380
+ const createSchema = buildRelatedNestedData(ctx, create, "create");
4381
+ const updateSchema = buildRelatedNestedData(ctx, update, "update");
4348
4382
  if (ctx.isList) {
4349
4383
  const where = requireNestedObject(
4350
4384
  cfg,
4351
4385
  "where",
4352
4386
  `upsert on to-many "${ctx.model}.${ctx.fieldName}" requires "where" object`
4353
4387
  );
4354
- const whereSchema = buildUniqueSelector(ctx, where, "upsert.where");
4388
+ const whereSchema = buildRelatedUniqueSelector(ctx, where, "upsert.where");
4355
4389
  const upsertSchema2 = z10.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
4356
4390
  return wrapRelationOp(true, upsertSchema2);
4357
4391
  }
@@ -4362,7 +4396,7 @@ var handleUpsert = (ctx) => {
4362
4396
  `upsert on to-one "${ctx.model}.${ctx.fieldName}" has invalid "where": must be a plain object of unique selectors`
4363
4397
  );
4364
4398
  }
4365
- const whereSchema = buildUniqueSelector(ctx, cfg.where, "upsert.where");
4399
+ const whereSchema = buildRelatedUniqueSelector(ctx, cfg.where, "upsert.where");
4366
4400
  const upsertSchema2 = z10.object({ where: whereSchema, create: createSchema, update: updateSchema }).strict();
4367
4401
  return upsertSchema2.optional();
4368
4402
  }
@@ -4406,7 +4440,7 @@ var handleUpdateMany = (ctx) => {
4406
4440
  ctx.typeMap,
4407
4441
  ctx.schemaBuilder
4408
4442
  );
4409
- const dataSchema = buildNestedData(ctx, data, "update");
4443
+ const dataSchema = buildRelatedNestedData(ctx, data, "update");
4410
4444
  const umSchema = z10.object({ where: whereSchema, data: dataSchema }).strict();
4411
4445
  return wrapRelationOp(true, umSchema);
4412
4446
  };
@@ -4453,17 +4487,21 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
4453
4487
  throw new ShapeError(
4454
4488
  `Unknown related model "${relatedModelName}" for field "${model}.${fieldName}"`
4455
4489
  );
4456
- for (const key of Object.keys(config)) {
4457
- if (!KNOWN_RELATION_WRITE_OPS.has(key)) {
4458
- throw new ShapeError(
4459
- `Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
4460
- );
4461
- }
4490
+ assertAllowedKeys(
4491
+ config,
4492
+ KNOWN_RELATION_WRITE_OPS,
4493
+ (key) => `Unknown relation write operation "${key}" on "${model}.${fieldName}". Allowed: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
4494
+ );
4495
+ const definedEntries = Object.entries(config).filter(
4496
+ ([, opConfig]) => opConfig !== void 0
4497
+ );
4498
+ if (definedEntries.length === 0) {
4499
+ throw new ShapeError(
4500
+ `Empty relation write config on "${model}.${fieldName}". Define at least one operation: ${[...KNOWN_RELATION_WRITE_OPS].join(", ")}`
4501
+ );
4462
4502
  }
4463
4503
  const opSchemas = {};
4464
- for (const [op, opConfig] of Object.entries(config)) {
4465
- if (opConfig === void 0)
4466
- continue;
4504
+ for (const [op, opConfig] of definedEntries) {
4467
4505
  const handler = RELATION_OP_HANDLERS[op];
4468
4506
  opSchemas[op] = handler({
4469
4507
  model,
@@ -4480,7 +4518,7 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
4480
4518
  }
4481
4519
  return z10.object(opSchemas).strict();
4482
4520
  }
4483
- function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults) {
4521
+ function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, scalarBase, schemaBuilder, zodDefaults, allowRelationWrites) {
4484
4522
  const modelFields = typeMap[model];
4485
4523
  if (!modelFields)
4486
4524
  throw new ShapeError(`Unknown model: ${model}`);
@@ -4510,6 +4548,11 @@ function buildDataSchema(model, dataConfig, mode, typeMap, uniqueMap, enumMap, s
4510
4548
  continue;
4511
4549
  }
4512
4550
  if (fieldMeta.isRelation) {
4551
+ if (!allowRelationWrites) {
4552
+ throw new ShapeError(
4553
+ `Field "${fieldName}" on model "${model}" is a relation. Relation writes are not supported for this method.`
4554
+ );
4555
+ }
4513
4556
  if (!isPlainObject(value)) {
4514
4557
  throw new ShapeError(
4515
4558
  `Relation field "${fieldName}" on model "${model}" requires a relation write config object`
@@ -4623,13 +4666,8 @@ function validateAndMergeData(bodyData, cached, method, modelName) {
4623
4666
  try {
4624
4667
  validated = cached.schema.parse(bodyData);
4625
4668
  } catch (err) {
4626
- if (err instanceof ShapeError)
4627
- throw err;
4628
- if (err && typeof err === "object" && "issues" in err) {
4629
- const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
4630
- throw new ShapeError(`${context}: ${formatZodError(err)}`, { cause: err });
4631
- }
4632
- throw err;
4669
+ const context = modelName ? `Invalid data for ${method} on model "${modelName}"` : `Invalid data for ${method}`;
4670
+ wrapParseError(err, context);
4633
4671
  }
4634
4672
  return { ...validated, ...deepClone(cached.forced) };
4635
4673
  }
@@ -4784,6 +4822,8 @@ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
4784
4822
  "updateManyAndReturn"
4785
4823
  ]);
4786
4824
  var BATCH_CREATE_METHODS = /* @__PURE__ */ new Set(["createMany", "createManyAndReturn"]);
4825
+ var RELATION_WRITE_CREATE_METHODS = /* @__PURE__ */ new Set(["create"]);
4826
+ var RELATION_WRITE_UPDATE_METHODS = /* @__PURE__ */ new Set(["update"]);
4787
4827
  var MAX_PROJECTION_WALK_DEPTH = 10;
4788
4828
  function walkForClientContent(obj, predicate, depth) {
4789
4829
  if (depth > MAX_PROJECTION_WALK_DEPTH)
@@ -4934,11 +4974,11 @@ function createModelGuardExtension(config) {
4934
4974
  )
4935
4975
  );
4936
4976
  }
4937
- function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
4977
+ function getDataSchema(mode, dataConfig, matchedKey, wasDynamic, allowRelationWrites) {
4938
4978
  const skipCache = wasDynamic || hasDataRefines(dataConfig);
4939
4979
  return memoize(
4940
4980
  dataSchemaCache,
4941
- `${mode}\0${matchedKey}`,
4981
+ `${mode}\0${matchedKey}\0${allowRelationWrites ? "r" : "n"}`,
4942
4982
  skipCache,
4943
4983
  () => buildDataSchema(
4944
4984
  modelName,
@@ -4949,7 +4989,8 @@ function createModelGuardExtension(config) {
4949
4989
  enumMap,
4950
4990
  scalarBase,
4951
4991
  schemaBuilder,
4952
- zodDefaults
4992
+ zodDefaults,
4993
+ allowRelationWrites
4953
4994
  )
4954
4995
  );
4955
4996
  }
@@ -5207,6 +5248,39 @@ function createModelGuardExtension(config) {
5207
5248
  const defaultProjection = buildDefaultProjectionBody(resolved.shape);
5208
5249
  return { ...resolved.body, ...defaultProjection };
5209
5250
  }
5251
+ function makeResolveMethod() {
5252
+ const WRITE_KEYS = ["data", "create", "update"];
5253
+ const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
5254
+ return (body) => {
5255
+ const caller = resolveCaller();
5256
+ const resolved = resolveShape(input, body, contextFn, caller);
5257
+ for (const key of WRITE_KEYS) {
5258
+ if (hasOwn(resolved.shape, key)) {
5259
+ throw new ShapeError(
5260
+ `.resolve() is a read-only planning helper. Guard shape contains write key "${key}". Use the corresponding write method instead.`
5261
+ );
5262
+ }
5263
+ }
5264
+ for (const key of WRITE_KEYS) {
5265
+ if (hasOwn(resolved.body, key)) {
5266
+ throw new ShapeError(
5267
+ `.resolve() is a read-only planning helper. Request body contains write key "${key}".`
5268
+ );
5269
+ }
5270
+ }
5271
+ const effectiveReadBody = buildEffectiveReadBody({
5272
+ shape: resolved.shape,
5273
+ body: resolved.body
5274
+ });
5275
+ return {
5276
+ shape: resolved.shape,
5277
+ body: resolved.body,
5278
+ effectiveReadBody,
5279
+ matchedKey: resolved.matchedKey,
5280
+ wasDynamic: resolved.wasDynamic
5281
+ };
5282
+ };
5283
+ }
5210
5284
  function makeReadMethod(method) {
5211
5285
  return (body) => {
5212
5286
  const caller = resolveCaller();
@@ -5240,6 +5314,7 @@ function createModelGuardExtension(config) {
5240
5314
  const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
5241
5315
  const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
5242
5316
  const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
5317
+ const allowRelationWrites = RELATION_WRITE_CREATE_METHODS.has(method);
5243
5318
  return (body) => {
5244
5319
  const caller = resolveCaller();
5245
5320
  const resolved = resolveShape(input, body, contextFn, caller);
@@ -5265,7 +5340,8 @@ function createModelGuardExtension(config) {
5265
5340
  "create",
5266
5341
  resolved.shape.data,
5267
5342
  resolved.matchedKey,
5268
- resolved.wasDynamic
5343
+ resolved.wasDynamic,
5344
+ allowRelationWrites
5269
5345
  );
5270
5346
  let args;
5271
5347
  if (method === "create") {
@@ -5313,6 +5389,7 @@ function createModelGuardExtension(config) {
5313
5389
  const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
5314
5390
  const allowedBodyKeys = getAllowedBodyKeys(method, supportsProjection);
5315
5391
  const allowedShapeKeys = getAllowedShapeKeys(method, supportsProjection);
5392
+ const allowRelationWrites = RELATION_WRITE_UPDATE_METHODS.has(method);
5316
5393
  return (body) => {
5317
5394
  const caller = resolveCaller();
5318
5395
  const resolved = resolveShape(input, body, contextFn, caller);
@@ -5335,7 +5412,8 @@ function createModelGuardExtension(config) {
5335
5412
  "update",
5336
5413
  resolved.shape.data,
5337
5414
  resolved.matchedKey,
5338
- resolved.wasDynamic
5415
+ resolved.wasDynamic,
5416
+ allowRelationWrites
5339
5417
  );
5340
5418
  const data = validateAndMergeData(
5341
5419
  resolved.body.data,
@@ -5508,7 +5586,8 @@ function createModelGuardExtension(config) {
5508
5586
  "create",
5509
5587
  resolved.shape.create,
5510
5588
  `upsert:create\0${resolved.matchedKey}`,
5511
- resolved.wasDynamic
5589
+ resolved.wasDynamic,
5590
+ true
5512
5591
  );
5513
5592
  const createData = validateAndMergeData(
5514
5593
  resolved.body.create,
@@ -5520,7 +5599,8 @@ function createModelGuardExtension(config) {
5520
5599
  "update",
5521
5600
  resolved.shape.update,
5522
5601
  `upsert:update\0${resolved.matchedKey}`,
5523
- resolved.wasDynamic
5602
+ resolved.wasDynamic,
5603
+ true
5524
5604
  );
5525
5605
  const updateData = validateAndMergeData(
5526
5606
  resolved.body.update,
@@ -5553,6 +5633,7 @@ function createModelGuardExtension(config) {
5553
5633
  };
5554
5634
  }
5555
5635
  return {
5636
+ resolve: makeResolveMethod(),
5556
5637
  findMany: makeReadMethod("findMany"),
5557
5638
  findFirst: makeReadMethod("findFirst"),
5558
5639
  findFirstOrThrow: makeReadMethod("findFirstOrThrow"),