prisma-guard 1.15.0 → 1.17.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.
@@ -115,10 +115,7 @@ function isJsonSafe(value) {
115
115
  return true;
116
116
  }
117
117
  var DECIMAL_REGEX = /^-?(\d+\.?\d*|\.\d+)([eE]-?\d+)?$/;
118
- var decimalStringSchema = import_zod.z.string().refine(
119
- (s) => DECIMAL_REGEX.test(s),
120
- "Invalid decimal string"
121
- );
118
+ var decimalStringSchema = import_zod.z.string().refine((s) => DECIMAL_REGEX.test(s), "Invalid decimal string");
122
119
  var decimalObjectSchema = import_zod.z.custom(
123
120
  (v) => v !== null && typeof v === "object" && typeof v.toFixed === "function" && typeof v.toNumber === "function",
124
121
  "Expected Decimal-compatible object"
@@ -144,18 +141,39 @@ function createScalarBase(strictDecimal) {
144
141
  import_zod.z.string().regex(/^-?\d+$/).transform((v) => BigInt(v))
145
142
  ]),
146
143
  Boolean: () => import_zod.z.boolean(),
147
- DateTime: () => import_zod.z.union([
148
- import_zod.z.date(),
149
- import_zod.z.string().datetime({ offset: true })
150
- ]).pipe(import_zod.z.coerce.date()),
151
- Json: () => import_zod.z.unknown().refine(isJsonSafe, "Value must be JSON-serializable (no undefined, functions, symbols, class instances, NaN, Infinity, or circular references)"),
152
- Bytes: () => import_zod.z.union([
153
- import_zod.z.string(),
154
- import_zod.z.custom((v) => v instanceof Uint8Array)
155
- ])
144
+ DateTime: () => import_zod.z.union([import_zod.z.date(), import_zod.z.string().datetime({ offset: true })]).pipe(import_zod.z.coerce.date()),
145
+ Json: () => import_zod.z.unknown().refine(
146
+ isJsonSafe,
147
+ "Value must be JSON-serializable (no undefined, functions, symbols, class instances, NaN, Infinity, or circular references)"
148
+ ),
149
+ Bytes: () => import_zod.z.union([import_zod.z.string(), import_zod.z.custom((v) => v instanceof Uint8Array)])
156
150
  };
157
151
  }
158
152
  var SCALAR_BASE = createScalarBase(false);
153
+ function wrapWithInputCoercion(fieldType, isList, schema) {
154
+ let itemCoercion = null;
155
+ switch (fieldType) {
156
+ case "String":
157
+ itemCoercion = import_zod.z.union([import_zod.z.string(), import_zod.z.number().transform(String)]);
158
+ break;
159
+ case "Int":
160
+ itemCoercion = import_zod.z.union([
161
+ import_zod.z.number().int(),
162
+ import_zod.z.string().regex(/^-?\d+$/).transform(Number)
163
+ ]);
164
+ break;
165
+ case "Float":
166
+ itemCoercion = import_zod.z.union([
167
+ import_zod.z.number(),
168
+ import_zod.z.string().regex(/^-?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/).transform(Number)
169
+ ]);
170
+ break;
171
+ default:
172
+ return schema;
173
+ }
174
+ const coercion = isList ? import_zod.z.array(itemCoercion) : itemCoercion;
175
+ return coercion.pipe(schema);
176
+ }
159
177
 
160
178
  // src/runtime/schema-builder.ts
161
179
  var import_zod3 = require("zod");
@@ -204,19 +222,65 @@ function coerceToArray(value) {
204
222
 
205
223
  // src/runtime/zod-type-map.ts
206
224
  var SCALAR_OPERATORS = {
207
- String: /* @__PURE__ */ new Set(["equals", "not", "contains", "startsWith", "endsWith", "in", "notIn", "gt", "gte", "lt", "lte"]),
225
+ String: /* @__PURE__ */ new Set([
226
+ "equals",
227
+ "not",
228
+ "contains",
229
+ "startsWith",
230
+ "endsWith",
231
+ "in",
232
+ "notIn",
233
+ "gt",
234
+ "gte",
235
+ "lt",
236
+ "lte"
237
+ ]),
208
238
  Int: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
209
239
  Float: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
210
240
  Decimal: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
211
241
  BigInt: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
212
242
  Boolean: /* @__PURE__ */ new Set(["equals", "not"]),
213
243
  DateTime: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
214
- Bytes: /* @__PURE__ */ new Set([])
244
+ Bytes: /* @__PURE__ */ new Set([]),
245
+ Json: /* @__PURE__ */ new Set([
246
+ "equals",
247
+ "not",
248
+ "path",
249
+ "string_contains",
250
+ "string_starts_with",
251
+ "string_ends_with",
252
+ "array_contains",
253
+ "array_starts_with",
254
+ "array_ends_with"
255
+ ])
215
256
  };
216
- var SCALAR_LIST_OPERATORS = /* @__PURE__ */ new Set(["has", "hasEvery", "hasSome", "isEmpty", "equals"]);
257
+ var SCALAR_LIST_OPERATORS = /* @__PURE__ */ new Set([
258
+ "has",
259
+ "hasEvery",
260
+ "hasSome",
261
+ "isEmpty",
262
+ "equals"
263
+ ]);
217
264
  var ENUM_OPERATORS = /* @__PURE__ */ new Set(["equals", "not", "in", "notIn"]);
218
265
  var NUMERIC_TYPES = /* @__PURE__ */ new Set(["Int", "Float", "Decimal", "BigInt"]);
219
- var COMPARABLE_TYPES = /* @__PURE__ */ new Set(["Int", "Float", "Decimal", "BigInt", "String", "DateTime"]);
266
+ var COMPARABLE_TYPES = /* @__PURE__ */ new Set([
267
+ "Int",
268
+ "Float",
269
+ "Decimal",
270
+ "BigInt",
271
+ "String",
272
+ "DateTime"
273
+ ]);
274
+ var JSON_STRING_OPERATORS = /* @__PURE__ */ new Set([
275
+ "string_contains",
276
+ "string_starts_with",
277
+ "string_ends_with"
278
+ ]);
279
+ var JSON_ARRAY_OPERATORS = /* @__PURE__ */ new Set([
280
+ "array_contains",
281
+ "array_starts_with",
282
+ "array_ends_with"
283
+ ]);
220
284
  function getSupportedOperators(fieldMeta) {
221
285
  if (fieldMeta.isList)
222
286
  return [...SCALAR_LIST_OPERATORS];
@@ -251,7 +315,9 @@ function createBaseType(fieldMeta, enumMap, scalarBase) {
251
315
  }
252
316
  function createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
253
317
  if (!SCALAR_LIST_OPERATORS.has(operator)) {
254
- throw new ShapeError(`Operator "${operator}" not supported for scalar list fields`);
318
+ throw new ShapeError(
319
+ `Operator "${operator}" not supported for scalar list fields`
320
+ );
255
321
  }
256
322
  if (operator === "isEmpty") {
257
323
  return import_zod2.z.boolean();
@@ -267,9 +333,32 @@ function createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase
267
333
  }
268
334
  return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(itemBase));
269
335
  }
336
+ function createJsonOperatorSchema(fieldMeta, operator) {
337
+ const jsonValue = import_zod2.z.unknown();
338
+ if (operator === "equals" || operator === "not") {
339
+ return !fieldMeta.isRequired ? import_zod2.z.union([jsonValue, import_zod2.z.null()]) : jsonValue;
340
+ }
341
+ if (operator === "path") {
342
+ return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(import_zod2.z.string()).min(1));
343
+ }
344
+ if (JSON_STRING_OPERATORS.has(operator)) {
345
+ return import_zod2.z.string();
346
+ }
347
+ if (JSON_ARRAY_OPERATORS.has(operator)) {
348
+ return jsonValue;
349
+ }
350
+ throw new ShapeError(
351
+ `Operator "${operator}" not supported for Json fields`
352
+ );
353
+ }
270
354
  function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
271
355
  if (fieldMeta.isList) {
272
- return createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase);
356
+ return createScalarListOperatorSchema(
357
+ fieldMeta,
358
+ operator,
359
+ enumMap,
360
+ scalarBase
361
+ );
273
362
  }
274
363
  if (fieldMeta.isEnum) {
275
364
  const values = enumMap[fieldMeta.type];
@@ -277,7 +366,9 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
277
366
  throw new ShapeError(`Unknown enum: ${fieldMeta.type}`);
278
367
  }
279
368
  if (!ENUM_OPERATORS.has(operator)) {
280
- throw new ShapeError(`Operator "${operator}" not supported for enum fields`);
369
+ throw new ShapeError(
370
+ `Operator "${operator}" not supported for enum fields`
371
+ );
281
372
  }
282
373
  const enumSchema = import_zod2.z.enum(values);
283
374
  if (operator === "equals" || operator === "not") {
@@ -286,29 +377,43 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
286
377
  const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([enumSchema, import_zod2.z.null()]) : enumSchema;
287
378
  return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(itemSchema));
288
379
  }
380
+ if (fieldMeta.type === "Json") {
381
+ const supportedOps2 = SCALAR_OPERATORS["Json"];
382
+ if (!supportedOps2 || !supportedOps2.has(operator)) {
383
+ throw new ShapeError(
384
+ `Operator "${operator}" not supported for type "Json"`
385
+ );
386
+ }
387
+ return createJsonOperatorSchema(fieldMeta, operator);
388
+ }
289
389
  const supportedOps = SCALAR_OPERATORS[fieldMeta.type];
290
390
  if (!supportedOps) {
291
391
  throw new ShapeError(`Unknown scalar type for operator: ${fieldMeta.type}`);
292
392
  }
293
393
  if (supportedOps.size === 0) {
294
- throw new ShapeError(`Type "${fieldMeta.type}" does not support filter operators`);
394
+ throw new ShapeError(
395
+ `Type "${fieldMeta.type}" does not support filter operators`
396
+ );
295
397
  }
296
398
  if (!supportedOps.has(operator)) {
297
- throw new ShapeError(`Operator "${operator}" not supported for type "${fieldMeta.type}"`);
399
+ throw new ShapeError(
400
+ `Operator "${operator}" not supported for type "${fieldMeta.type}"`
401
+ );
298
402
  }
299
403
  const factory = scalarBase[fieldMeta.type];
300
404
  if (!factory) {
301
405
  throw new ShapeError(`Unknown scalar type: ${fieldMeta.type}`);
302
406
  }
303
407
  const scalar = factory();
408
+ const coerced = wrapWithInputCoercion(fieldMeta.type, false, scalar);
304
409
  if (operator === "equals" || operator === "not") {
305
- return !fieldMeta.isRequired ? import_zod2.z.union([scalar, import_zod2.z.null()]) : scalar;
410
+ return !fieldMeta.isRequired ? import_zod2.z.union([coerced, import_zod2.z.null()]) : coerced;
306
411
  }
307
412
  if (operator === "in" || operator === "notIn") {
308
- const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([scalar, import_zod2.z.null()]) : scalar;
413
+ const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([coerced, import_zod2.z.null()]) : coerced;
309
414
  return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(itemSchema));
310
415
  }
311
- return scalar;
416
+ return coerced;
312
417
  }
313
418
 
314
419
  // src/runtime/schema-builder.ts
@@ -358,6 +463,9 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
358
463
  );
359
464
  }
360
465
  }
466
+ if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
467
+ result = wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, result);
468
+ }
361
469
  lruSet(chainCache, cacheKey, result, DEFAULT_MAX_CACHE);
362
470
  return result;
363
471
  }
@@ -390,9 +498,13 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
390
498
  if (!modelFields[name])
391
499
  throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
392
500
  if (modelFields[name].isRelation)
393
- throw new ShapeError(`Field "${name}" cannot be used in input schema (relation field)`);
501
+ throw new ShapeError(
502
+ `Field "${name}" cannot be used in input schema (relation field)`
503
+ );
394
504
  if (modelFields[name].isUpdatedAt)
395
- throw new ShapeError(`Field "${name}" cannot be used in input schema (updatedAt field)`);
505
+ throw new ShapeError(
506
+ `Field "${name}" cannot be used in input schema (updatedAt field)`
507
+ );
396
508
  }
397
509
  fieldNames = fieldNames.filter((n) => opts.pick.includes(n));
398
510
  } else if (opts.omit) {
@@ -466,7 +578,9 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
466
578
  }
467
579
  const effectiveMaxDepth = maxDepth ?? opts.maxDepth ?? DEFAULT_MAX_DEPTH;
468
580
  if (depth > effectiveMaxDepth) {
469
- throw new ShapeError(`Maximum include depth (${effectiveMaxDepth}) exceeded`);
581
+ throw new ShapeError(
582
+ `Maximum include depth (${effectiveMaxDepth}) exceeded`
583
+ );
470
584
  }
471
585
  const modelFields = typeMap[model];
472
586
  if (!modelFields)
@@ -477,7 +591,9 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
477
591
  if (!modelFields[name])
478
592
  throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
479
593
  if (modelFields[name].isRelation && !includeKeys.has(name)) {
480
- throw new ShapeError(`Field "${name}" is a relation on model "${model}". Use include: { ${name}: ... } instead of pick.`);
594
+ throw new ShapeError(
595
+ `Field "${name}" is a relation on model "${model}". Use include: { ${name}: ... } instead of pick.`
596
+ );
481
597
  }
482
598
  }
483
599
  }
@@ -510,10 +626,14 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
510
626
  if (!fieldMeta)
511
627
  throw new ShapeError(`Unknown field "${relName}" on model "${model}"`);
512
628
  if (!fieldMeta.isRelation)
513
- throw new ShapeError(`Field "${relName}" is not a relation on model "${model}"`);
629
+ throw new ShapeError(
630
+ `Field "${relName}" is not a relation on model "${model}"`
631
+ );
514
632
  const relatedModel = fieldMeta.type;
515
633
  if (!typeMap[relatedModel]) {
516
- throw new ShapeError(`Related model "${relatedModel}" not found in type map`);
634
+ throw new ShapeError(
635
+ `Related model "${relatedModel}" not found in type map`
636
+ );
517
637
  }
518
638
  let relSchema = buildModelSchema(
519
639
  relatedModel,
@@ -542,11 +662,17 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
542
662
  const countFields = {};
543
663
  for (const relName of Object.keys(opts._count)) {
544
664
  if (!modelFields[relName])
545
- throw new ShapeError(`Unknown field "${relName}" on model "${model}" in _count`);
665
+ throw new ShapeError(
666
+ `Unknown field "${relName}" on model "${model}" in _count`
667
+ );
546
668
  if (!modelFields[relName].isRelation)
547
- throw new ShapeError(`Field "${relName}" is not a relation on model "${model}" in _count`);
669
+ throw new ShapeError(
670
+ `Field "${relName}" is not a relation on model "${model}" in _count`
671
+ );
548
672
  if (!modelFields[relName].isList)
549
- throw new ShapeError(`Field "${relName}" is a to-one relation on model "${model}" in _count. Only to-many relations support _count.`);
673
+ throw new ShapeError(
674
+ `Field "${relName}" is a to-one relation on model "${model}" in _count. Only to-many relations support _count.`
675
+ );
550
676
  countFields[relName] = import_zod3.z.number().int().min(0);
551
677
  }
552
678
  schemaMap["_count"] = import_zod3.z.object(countFields);
@@ -558,7 +684,12 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
558
684
  }
559
685
  return schema;
560
686
  }
561
- return { buildFieldSchema, buildBaseFieldSchema, buildInputSchema, buildModelSchema };
687
+ return {
688
+ buildFieldSchema,
689
+ buildBaseFieldSchema,
690
+ buildInputSchema,
691
+ buildModelSchema
692
+ };
562
693
  }
563
694
 
564
695
  // src/runtime/query-builder.ts
@@ -1012,13 +1143,18 @@ function validateUniqueEquality(model, where, method, uniqueMap, typeMap) {
1012
1143
  }
1013
1144
 
1014
1145
  // src/runtime/query-builder-where.ts
1015
- var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
1146
+ var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Bytes"]);
1016
1147
  var STRING_MODE_OPS = /* @__PURE__ */ new Set([
1017
1148
  "contains",
1018
1149
  "startsWith",
1019
1150
  "endsWith",
1020
1151
  "equals"
1021
1152
  ]);
1153
+ var JSON_STRING_MODE_OPS = /* @__PURE__ */ new Set([
1154
+ "string_contains",
1155
+ "string_starts_with",
1156
+ "string_ends_with"
1157
+ ]);
1022
1158
  var MAX_WHERE_DEPTH = 10;
1023
1159
  function safeStringify(v) {
1024
1160
  if (typeof v === "bigint")
@@ -1114,6 +1250,13 @@ function mergeRelationForcedMaps(target, source) {
1114
1250
  }
1115
1251
  }
1116
1252
  }
1253
+ function isModeCompatibleOp(fieldType, op) {
1254
+ if (fieldType === "String")
1255
+ return STRING_MODE_OPS.has(op);
1256
+ if (fieldType === "Json")
1257
+ return JSON_STRING_MODE_OPS.has(op);
1258
+ return false;
1259
+ }
1117
1260
  function createWhereBuilder(typeMap, enumMap, scalarBase) {
1118
1261
  function buildWhereSchema(model, whereConfig, depth) {
1119
1262
  const currentDepth = depth ?? 0;
@@ -1316,7 +1459,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1316
1459
  const opSchemas = {};
1317
1460
  const fieldForced = {};
1318
1461
  let hasClientOps = false;
1319
- let hasStringModeOp = false;
1462
+ let hasModeCompatibleOp = false;
1320
1463
  const clientOpKeys = [];
1321
1464
  let modeConfigValue = void 0;
1322
1465
  let hasModeConfig = false;
@@ -1335,8 +1478,8 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1335
1478
  ).optional();
1336
1479
  hasClientOps = true;
1337
1480
  clientOpKeys.push(op);
1338
- if (fieldMeta.type === "String" && !fieldMeta.isList && STRING_MODE_OPS.has(op)) {
1339
- hasStringModeOp = true;
1481
+ if (!fieldMeta.isList && isModeCompatibleOp(fieldMeta.type, op)) {
1482
+ hasModeCompatibleOp = true;
1340
1483
  }
1341
1484
  } else {
1342
1485
  const actualOpValue = isForcedValue(opValue) ? opValue.value : opValue;
@@ -1355,15 +1498,15 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1355
1498
  );
1356
1499
  }
1357
1500
  fieldForced[op] = parsed;
1358
- if (fieldMeta.type === "String" && !fieldMeta.isList && STRING_MODE_OPS.has(op)) {
1359
- hasStringModeOp = true;
1501
+ if (!fieldMeta.isList && isModeCompatibleOp(fieldMeta.type, op)) {
1502
+ hasModeCompatibleOp = true;
1360
1503
  }
1361
1504
  }
1362
1505
  }
1363
1506
  if (!hasClientOps && Object.keys(fieldForced).length === 0) {
1364
1507
  if (hasModeConfig) {
1365
1508
  throw new ShapeError(
1366
- `Where field "${fieldName}" on model "${model}" has "mode" but no operators. Add at least one operator (contains, startsWith, endsWith, equals).`
1509
+ `Where field "${fieldName}" on model "${model}" has "mode" but no operators. Add at least one compatible operator.`
1367
1510
  );
1368
1511
  }
1369
1512
  throw new ShapeError(
@@ -1371,9 +1514,9 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1371
1514
  );
1372
1515
  }
1373
1516
  if (hasModeConfig) {
1374
- if (!hasStringModeOp) {
1517
+ if (!hasModeCompatibleOp) {
1375
1518
  throw new ShapeError(
1376
- `"mode" on where field "${fieldName}" on model "${model}" requires a compatible String operator (contains, startsWith, endsWith, equals)`
1519
+ `"mode" on where field "${fieldName}" on model "${model}" requires a compatible operator (String: contains, startsWith, endsWith, equals; Json: string_contains, string_starts_with, string_ends_with)`
1377
1520
  );
1378
1521
  }
1379
1522
  if (modeConfigValue === true) {
@@ -1391,7 +1534,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1391
1534
  }
1392
1535
  fieldForced["mode"] = parsed;
1393
1536
  }
1394
- } else if (hasStringModeOp) {
1537
+ } else if (hasModeCompatibleOp) {
1395
1538
  opSchemas["mode"] = import_zod4.z.enum(["default", "insensitive"]).optional();
1396
1539
  }
1397
1540
  if (hasClientOps) {
@@ -1404,7 +1547,7 @@ function createWhereBuilder(typeMap, enumMap, scalarBase) {
1404
1547
  message: `At least one operator required for where field "${fieldName}"`
1405
1548
  }
1406
1549
  );
1407
- if ("equals" in opSchemas) {
1550
+ if ("equals" in opSchemas && fieldMeta.type !== "Json") {
1408
1551
  const equalsBase = createOperatorSchema(
1409
1552
  fieldMeta,
1410
1553
  "equals",