prisma-guard 1.14.1 → 1.16.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.
@@ -24,7 +24,8 @@ __export(runtime_exports, {
24
24
  PolicyError: () => PolicyError,
25
25
  ShapeError: () => ShapeError,
26
26
  createGuard: () => createGuard,
27
- force: () => force
27
+ force: () => force,
28
+ unsupported: () => unsupported
28
29
  });
29
30
  module.exports = __toCommonJS(runtime_exports);
30
31
 
@@ -114,10 +115,7 @@ function isJsonSafe(value) {
114
115
  return true;
115
116
  }
116
117
  var DECIMAL_REGEX = /^-?(\d+\.?\d*|\.\d+)([eE]-?\d+)?$/;
117
- var decimalStringSchema = import_zod.z.string().refine(
118
- (s) => DECIMAL_REGEX.test(s),
119
- "Invalid decimal string"
120
- );
118
+ var decimalStringSchema = import_zod.z.string().refine((s) => DECIMAL_REGEX.test(s), "Invalid decimal string");
121
119
  var decimalObjectSchema = import_zod.z.custom(
122
120
  (v) => v !== null && typeof v === "object" && typeof v.toFixed === "function" && typeof v.toNumber === "function",
123
121
  "Expected Decimal-compatible object"
@@ -143,18 +141,39 @@ function createScalarBase(strictDecimal) {
143
141
  import_zod.z.string().regex(/^-?\d+$/).transform((v) => BigInt(v))
144
142
  ]),
145
143
  Boolean: () => import_zod.z.boolean(),
146
- DateTime: () => import_zod.z.union([
147
- import_zod.z.date(),
148
- import_zod.z.string().datetime({ offset: true })
149
- ]).pipe(import_zod.z.coerce.date()),
150
- Json: () => import_zod.z.unknown().refine(isJsonSafe, "Value must be JSON-serializable (no undefined, functions, symbols, class instances, NaN, Infinity, or circular references)"),
151
- Bytes: () => import_zod.z.union([
152
- import_zod.z.string(),
153
- import_zod.z.custom((v) => v instanceof Uint8Array)
154
- ])
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)])
155
150
  };
156
151
  }
157
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
+ }
158
177
 
159
178
  // src/runtime/schema-builder.ts
160
179
  var import_zod3 = require("zod");
@@ -203,7 +222,19 @@ function coerceToArray(value) {
203
222
 
204
223
  // src/runtime/zod-type-map.ts
205
224
  var SCALAR_OPERATORS = {
206
- 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
+ ]),
207
238
  Int: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
208
239
  Float: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
209
240
  Decimal: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
@@ -212,10 +243,23 @@ var SCALAR_OPERATORS = {
212
243
  DateTime: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
213
244
  Bytes: /* @__PURE__ */ new Set([])
214
245
  };
215
- var SCALAR_LIST_OPERATORS = /* @__PURE__ */ new Set(["has", "hasEvery", "hasSome", "isEmpty", "equals"]);
246
+ var SCALAR_LIST_OPERATORS = /* @__PURE__ */ new Set([
247
+ "has",
248
+ "hasEvery",
249
+ "hasSome",
250
+ "isEmpty",
251
+ "equals"
252
+ ]);
216
253
  var ENUM_OPERATORS = /* @__PURE__ */ new Set(["equals", "not", "in", "notIn"]);
217
254
  var NUMERIC_TYPES = /* @__PURE__ */ new Set(["Int", "Float", "Decimal", "BigInt"]);
218
- var COMPARABLE_TYPES = /* @__PURE__ */ new Set(["Int", "Float", "Decimal", "BigInt", "String", "DateTime"]);
255
+ var COMPARABLE_TYPES = /* @__PURE__ */ new Set([
256
+ "Int",
257
+ "Float",
258
+ "Decimal",
259
+ "BigInt",
260
+ "String",
261
+ "DateTime"
262
+ ]);
219
263
  function getSupportedOperators(fieldMeta) {
220
264
  if (fieldMeta.isList)
221
265
  return [...SCALAR_LIST_OPERATORS];
@@ -250,7 +294,9 @@ function createBaseType(fieldMeta, enumMap, scalarBase) {
250
294
  }
251
295
  function createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
252
296
  if (!SCALAR_LIST_OPERATORS.has(operator)) {
253
- throw new ShapeError(`Operator "${operator}" not supported for scalar list fields`);
297
+ throw new ShapeError(
298
+ `Operator "${operator}" not supported for scalar list fields`
299
+ );
254
300
  }
255
301
  if (operator === "isEmpty") {
256
302
  return import_zod2.z.boolean();
@@ -268,7 +314,12 @@ function createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase
268
314
  }
269
315
  function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
270
316
  if (fieldMeta.isList) {
271
- return createScalarListOperatorSchema(fieldMeta, operator, enumMap, scalarBase);
317
+ return createScalarListOperatorSchema(
318
+ fieldMeta,
319
+ operator,
320
+ enumMap,
321
+ scalarBase
322
+ );
272
323
  }
273
324
  if (fieldMeta.isEnum) {
274
325
  const values = enumMap[fieldMeta.type];
@@ -276,7 +327,9 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
276
327
  throw new ShapeError(`Unknown enum: ${fieldMeta.type}`);
277
328
  }
278
329
  if (!ENUM_OPERATORS.has(operator)) {
279
- throw new ShapeError(`Operator "${operator}" not supported for enum fields`);
330
+ throw new ShapeError(
331
+ `Operator "${operator}" not supported for enum fields`
332
+ );
280
333
  }
281
334
  const enumSchema = import_zod2.z.enum(values);
282
335
  if (operator === "equals" || operator === "not") {
@@ -290,24 +343,29 @@ function createOperatorSchema(fieldMeta, operator, enumMap, scalarBase) {
290
343
  throw new ShapeError(`Unknown scalar type for operator: ${fieldMeta.type}`);
291
344
  }
292
345
  if (supportedOps.size === 0) {
293
- throw new ShapeError(`Type "${fieldMeta.type}" does not support filter operators`);
346
+ throw new ShapeError(
347
+ `Type "${fieldMeta.type}" does not support filter operators`
348
+ );
294
349
  }
295
350
  if (!supportedOps.has(operator)) {
296
- throw new ShapeError(`Operator "${operator}" not supported for type "${fieldMeta.type}"`);
351
+ throw new ShapeError(
352
+ `Operator "${operator}" not supported for type "${fieldMeta.type}"`
353
+ );
297
354
  }
298
355
  const factory = scalarBase[fieldMeta.type];
299
356
  if (!factory) {
300
357
  throw new ShapeError(`Unknown scalar type: ${fieldMeta.type}`);
301
358
  }
302
359
  const scalar = factory();
360
+ const coerced = wrapWithInputCoercion(fieldMeta.type, false, scalar);
303
361
  if (operator === "equals" || operator === "not") {
304
- return !fieldMeta.isRequired ? import_zod2.z.union([scalar, import_zod2.z.null()]) : scalar;
362
+ return !fieldMeta.isRequired ? import_zod2.z.union([coerced, import_zod2.z.null()]) : coerced;
305
363
  }
306
364
  if (operator === "in" || operator === "notIn") {
307
- const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([scalar, import_zod2.z.null()]) : scalar;
365
+ const itemSchema = !fieldMeta.isRequired ? import_zod2.z.union([coerced, import_zod2.z.null()]) : coerced;
308
366
  return import_zod2.z.preprocess(coerceToArray, import_zod2.z.array(itemSchema));
309
367
  }
310
- return scalar;
368
+ return coerced;
311
369
  }
312
370
 
313
371
  // src/runtime/schema-builder.ts
@@ -357,6 +415,9 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
357
415
  );
358
416
  }
359
417
  }
418
+ if (!fieldMeta.isEnum && !fieldMeta.isRelation && !fieldMeta.isUnsupported) {
419
+ result = wrapWithInputCoercion(fieldMeta.type, fieldMeta.isList, result);
420
+ }
360
421
  lruSet(chainCache, cacheKey, result, DEFAULT_MAX_CACHE);
361
422
  return result;
362
423
  }
@@ -389,9 +450,13 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
389
450
  if (!modelFields[name])
390
451
  throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
391
452
  if (modelFields[name].isRelation)
392
- throw new ShapeError(`Field "${name}" cannot be used in input schema (relation field)`);
453
+ throw new ShapeError(
454
+ `Field "${name}" cannot be used in input schema (relation field)`
455
+ );
393
456
  if (modelFields[name].isUpdatedAt)
394
- throw new ShapeError(`Field "${name}" cannot be used in input schema (updatedAt field)`);
457
+ throw new ShapeError(
458
+ `Field "${name}" cannot be used in input schema (updatedAt field)`
459
+ );
395
460
  }
396
461
  fieldNames = fieldNames.filter((n) => opts.pick.includes(n));
397
462
  } else if (opts.omit) {
@@ -465,7 +530,9 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
465
530
  }
466
531
  const effectiveMaxDepth = maxDepth ?? opts.maxDepth ?? DEFAULT_MAX_DEPTH;
467
532
  if (depth > effectiveMaxDepth) {
468
- throw new ShapeError(`Maximum include depth (${effectiveMaxDepth}) exceeded`);
533
+ throw new ShapeError(
534
+ `Maximum include depth (${effectiveMaxDepth}) exceeded`
535
+ );
469
536
  }
470
537
  const modelFields = typeMap[model];
471
538
  if (!modelFields)
@@ -476,7 +543,9 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
476
543
  if (!modelFields[name])
477
544
  throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
478
545
  if (modelFields[name].isRelation && !includeKeys.has(name)) {
479
- throw new ShapeError(`Field "${name}" is a relation on model "${model}". Use include: { ${name}: ... } instead of pick.`);
546
+ throw new ShapeError(
547
+ `Field "${name}" is a relation on model "${model}". Use include: { ${name}: ... } instead of pick.`
548
+ );
480
549
  }
481
550
  }
482
551
  }
@@ -509,10 +578,14 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
509
578
  if (!fieldMeta)
510
579
  throw new ShapeError(`Unknown field "${relName}" on model "${model}"`);
511
580
  if (!fieldMeta.isRelation)
512
- throw new ShapeError(`Field "${relName}" is not a relation on model "${model}"`);
581
+ throw new ShapeError(
582
+ `Field "${relName}" is not a relation on model "${model}"`
583
+ );
513
584
  const relatedModel = fieldMeta.type;
514
585
  if (!typeMap[relatedModel]) {
515
- throw new ShapeError(`Related model "${relatedModel}" not found in type map`);
586
+ throw new ShapeError(
587
+ `Related model "${relatedModel}" not found in type map`
588
+ );
516
589
  }
517
590
  let relSchema = buildModelSchema(
518
591
  relatedModel,
@@ -541,11 +614,17 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
541
614
  const countFields = {};
542
615
  for (const relName of Object.keys(opts._count)) {
543
616
  if (!modelFields[relName])
544
- throw new ShapeError(`Unknown field "${relName}" on model "${model}" in _count`);
617
+ throw new ShapeError(
618
+ `Unknown field "${relName}" on model "${model}" in _count`
619
+ );
545
620
  if (!modelFields[relName].isRelation)
546
- throw new ShapeError(`Field "${relName}" is not a relation on model "${model}" in _count`);
621
+ throw new ShapeError(
622
+ `Field "${relName}" is not a relation on model "${model}" in _count`
623
+ );
547
624
  if (!modelFields[relName].isList)
548
- throw new ShapeError(`Field "${relName}" is a to-one relation on model "${model}" in _count. Only to-many relations support _count.`);
625
+ throw new ShapeError(
626
+ `Field "${relName}" is a to-one relation on model "${model}" in _count. Only to-many relations support _count.`
627
+ );
549
628
  countFields[relName] = import_zod3.z.number().int().min(0);
550
629
  }
551
630
  schemaMap["_count"] = import_zod3.z.object(countFields);
@@ -557,7 +636,12 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
557
636
  }
558
637
  return schema;
559
638
  }
560
- return { buildFieldSchema, buildBaseFieldSchema, buildInputSchema, buildModelSchema };
639
+ return {
640
+ buildFieldSchema,
641
+ buildBaseFieldSchema,
642
+ buildInputSchema,
643
+ buildModelSchema
644
+ };
561
645
  }
562
646
 
563
647
  // src/runtime/query-builder.ts
@@ -603,6 +687,15 @@ function force(value) {
603
687
  wrapper[FORCED_MARKER] = true;
604
688
  return wrapper;
605
689
  }
690
+ var UNSUPPORTED_MARKER = Symbol.for("prisma-guard.unsupported");
691
+ function isUnsupportedMarker(v) {
692
+ return v !== null && typeof v === "object" && v[UNSUPPORTED_MARKER] === true;
693
+ }
694
+ function unsupported() {
695
+ const marker = {};
696
+ marker[UNSUPPORTED_MARKER] = true;
697
+ return marker;
698
+ }
606
699
 
607
700
  // src/shared/match-caller.ts
608
701
  function matchCallerPattern(patterns, caller) {
@@ -3189,31 +3282,6 @@ function buildRelationWriteSchema(model, fieldName, relatedModelName, isList, co
3189
3282
  );
3190
3283
  }
3191
3284
  }
3192
- if (config.delete !== void 0) {
3193
- if (config.delete === true) {
3194
- if (isList) {
3195
- throw new ShapeError(
3196
- `delete on to-many relation "${model}.${fieldName}" requires field config, not true`
3197
- );
3198
- }
3199
- opSchemas["delete"] = import_zod8.z.literal(true).optional();
3200
- } else if (isPlainObject(config.delete)) {
3201
- const deleteSchema = buildWhereFieldsSchema(
3202
- relatedModelName,
3203
- config.delete,
3204
- typeMap,
3205
- schemaBuilder
3206
- );
3207
- opSchemas["delete"] = isList ? import_zod8.z.union([
3208
- deleteSchema,
3209
- import_zod8.z.preprocess(coerceToArray, import_zod8.z.array(deleteSchema))
3210
- ]).optional() : deleteSchema.optional();
3211
- } else {
3212
- throw new ShapeError(
3213
- `delete config on "${model}.${fieldName}" must be true (to-one) or an object of field names`
3214
- );
3215
- }
3216
- }
3217
3285
  if (config.set !== void 0) {
3218
3286
  if (!isList) {
3219
3287
  throw new ShapeError(
@@ -3420,8 +3488,13 @@ function buildDataSchema(model, dataConfig, mode, typeMap, schemaBuilder, zodDef
3420
3488
  const forced = {};
3421
3489
  for (const [fieldName, value] of Object.entries(dataConfig)) {
3422
3490
  const fieldMeta = modelFields[fieldName];
3423
- if (!fieldMeta)
3491
+ if (!fieldMeta) {
3492
+ if (isUnsupportedMarker(value)) {
3493
+ schemaMap[fieldName] = import_zod8.z.unknown().optional();
3494
+ continue;
3495
+ }
3424
3496
  throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
3497
+ }
3425
3498
  if (fieldMeta.isRelation) {
3426
3499
  if (!isPlainObject(value)) {
3427
3500
  throw new ShapeError(
@@ -4630,6 +4703,7 @@ function createGuard(config) {
4630
4703
  PolicyError,
4631
4704
  ShapeError,
4632
4705
  createGuard,
4633
- force
4706
+ force,
4707
+ unsupported
4634
4708
  });
4635
4709
  //# sourceMappingURL=index.cjs.map