prisma-guard 1.1.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.
@@ -0,0 +1,2677 @@
1
+ // src/runtime/guard.ts
2
+ import { ZodError } from "zod";
3
+
4
+ // src/shared/errors.ts
5
+ var PolicyError = class extends Error {
6
+ status = 403;
7
+ code = "POLICY_DENIED";
8
+ constructor(message = "Access denied", options) {
9
+ super(message, options);
10
+ this.name = "PolicyError";
11
+ }
12
+ };
13
+ var ShapeError = class extends Error {
14
+ status = 400;
15
+ code = "SHAPE_INVALID";
16
+ constructor(message, options) {
17
+ super(message, options);
18
+ this.name = "ShapeError";
19
+ }
20
+ };
21
+ var CallerError = class extends Error {
22
+ status = 400;
23
+ code = "CALLER_UNKNOWN";
24
+ constructor(message, options) {
25
+ super(message, options);
26
+ this.name = "CallerError";
27
+ }
28
+ };
29
+
30
+ // src/runtime/schema-builder.ts
31
+ import { z as z3 } from "zod";
32
+
33
+ // src/runtime/zod-type-map.ts
34
+ import { z as z2 } from "zod";
35
+
36
+ // src/shared/scalar-base.ts
37
+ import { z } from "zod";
38
+ function isJsonSafe(value) {
39
+ const stack = [value];
40
+ while (stack.length > 0) {
41
+ const current = stack.pop();
42
+ if (current === void 0)
43
+ return false;
44
+ if (current === null)
45
+ continue;
46
+ switch (typeof current) {
47
+ case "string":
48
+ case "boolean":
49
+ continue;
50
+ case "number":
51
+ if (!Number.isFinite(current))
52
+ return false;
53
+ continue;
54
+ case "object": {
55
+ if (Array.isArray(current)) {
56
+ for (let i = 0; i < current.length; i++) {
57
+ stack.push(current[i]);
58
+ }
59
+ continue;
60
+ }
61
+ const proto = Object.getPrototypeOf(current);
62
+ if (proto !== Object.prototype && proto !== null)
63
+ return false;
64
+ const values = Object.values(current);
65
+ for (let i = 0; i < values.length; i++) {
66
+ stack.push(values[i]);
67
+ }
68
+ continue;
69
+ }
70
+ default:
71
+ return false;
72
+ }
73
+ }
74
+ return true;
75
+ }
76
+ var SCALAR_BASE = {
77
+ String: () => z.string(),
78
+ Int: () => z.number().int(),
79
+ Float: () => z.number(),
80
+ Decimal: () => z.union([
81
+ z.number(),
82
+ z.string().refine(
83
+ (s) => /^-?(\d+\.?\d*|\.\d+)([eE]-?\d+)?$/.test(s),
84
+ "Invalid decimal string"
85
+ )
86
+ ]),
87
+ BigInt: () => z.union([
88
+ z.bigint(),
89
+ z.number().int().refine(
90
+ (v) => v >= Number.MIN_SAFE_INTEGER && v <= Number.MAX_SAFE_INTEGER,
91
+ "Number exceeds safe integer range for BigInt conversion"
92
+ ).transform((v) => BigInt(v)),
93
+ z.string().regex(/^-?\d+$/).transform((v) => BigInt(v))
94
+ ]),
95
+ Boolean: () => z.boolean(),
96
+ DateTime: () => z.union([
97
+ z.date(),
98
+ z.string().datetime({ offset: true }),
99
+ z.string().datetime()
100
+ ]).pipe(z.coerce.date()),
101
+ Json: () => z.unknown().refine(isJsonSafe, "Value must be JSON-serializable (no undefined, functions, symbols, class instances, NaN, or Infinity)"),
102
+ Bytes: () => z.union([
103
+ z.string(),
104
+ z.custom((v) => v instanceof Uint8Array)
105
+ ])
106
+ };
107
+
108
+ // src/runtime/zod-type-map.ts
109
+ var SCALAR_OPERATORS = {
110
+ String: /* @__PURE__ */ new Set(["equals", "not", "contains", "startsWith", "endsWith", "in", "notIn"]),
111
+ Int: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
112
+ Float: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
113
+ Decimal: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
114
+ BigInt: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
115
+ Boolean: /* @__PURE__ */ new Set(["equals", "not"]),
116
+ DateTime: /* @__PURE__ */ new Set(["equals", "not", "gt", "gte", "lt", "lte", "in", "notIn"]),
117
+ Bytes: /* @__PURE__ */ new Set([])
118
+ };
119
+ var SCALAR_LIST_OPERATORS = /* @__PURE__ */ new Set(["has", "hasEvery", "hasSome", "isEmpty", "equals"]);
120
+ var ENUM_OPERATORS = /* @__PURE__ */ new Set(["equals", "not", "in", "notIn"]);
121
+ var NUMERIC_TYPES = /* @__PURE__ */ new Set(["Int", "Float", "Decimal", "BigInt"]);
122
+ var COMPARABLE_TYPES = /* @__PURE__ */ new Set(["Int", "Float", "Decimal", "BigInt", "String", "DateTime"]);
123
+ function getSupportedOperators(fieldMeta) {
124
+ if (fieldMeta.isList)
125
+ return [...SCALAR_LIST_OPERATORS];
126
+ if (fieldMeta.isEnum)
127
+ return [...ENUM_OPERATORS];
128
+ const ops = SCALAR_OPERATORS[fieldMeta.type];
129
+ if (!ops)
130
+ return [];
131
+ return [...ops];
132
+ }
133
+ function createBaseType(fieldMeta, enumMap) {
134
+ let base;
135
+ if (fieldMeta.isEnum) {
136
+ const values = enumMap[fieldMeta.type];
137
+ if (!values || values.length === 0) {
138
+ throw new ShapeError(`Unknown enum: ${fieldMeta.type}`);
139
+ }
140
+ base = z2.enum(values);
141
+ } else {
142
+ const factory = SCALAR_BASE[fieldMeta.type];
143
+ if (!factory) {
144
+ throw new ShapeError(`Unknown scalar type: ${fieldMeta.type}`);
145
+ }
146
+ base = factory();
147
+ }
148
+ if (fieldMeta.isList) {
149
+ base = z2.array(base);
150
+ }
151
+ return base;
152
+ }
153
+ function createScalarListOperatorSchema(fieldMeta, operator, enumMap) {
154
+ if (!SCALAR_LIST_OPERATORS.has(operator)) {
155
+ throw new ShapeError(`Operator "${operator}" not supported for scalar list fields`);
156
+ }
157
+ if (operator === "isEmpty") {
158
+ return z2.boolean();
159
+ }
160
+ if (operator === "equals") {
161
+ const itemMeta2 = { ...fieldMeta, isList: false };
162
+ const itemBase2 = createBaseType(itemMeta2, enumMap);
163
+ return fieldMeta.isRequired ? z2.array(itemBase2) : z2.union([z2.array(itemBase2), z2.null()]);
164
+ }
165
+ const itemMeta = { ...fieldMeta, isList: false };
166
+ const itemBase = createBaseType(itemMeta, enumMap);
167
+ if (operator === "has") {
168
+ return !fieldMeta.isRequired ? z2.union([itemBase, z2.null()]) : itemBase;
169
+ }
170
+ return z2.array(itemBase);
171
+ }
172
+ function createOperatorSchema(fieldMeta, operator, enumMap) {
173
+ if (fieldMeta.isList) {
174
+ return createScalarListOperatorSchema(fieldMeta, operator, enumMap);
175
+ }
176
+ if (fieldMeta.isEnum) {
177
+ const values = enumMap[fieldMeta.type];
178
+ if (!values || values.length === 0) {
179
+ throw new ShapeError(`Unknown enum: ${fieldMeta.type}`);
180
+ }
181
+ if (!ENUM_OPERATORS.has(operator)) {
182
+ throw new ShapeError(`Operator "${operator}" not supported for enum fields`);
183
+ }
184
+ const enumSchema = z2.enum(values);
185
+ if (operator === "equals" || operator === "not") {
186
+ return !fieldMeta.isRequired ? z2.union([enumSchema, z2.null()]) : enumSchema;
187
+ }
188
+ if (!fieldMeta.isRequired) {
189
+ return z2.array(z2.union([enumSchema, z2.null()]));
190
+ }
191
+ return z2.array(enumSchema);
192
+ }
193
+ const supportedOps = SCALAR_OPERATORS[fieldMeta.type];
194
+ if (!supportedOps) {
195
+ throw new ShapeError(`Unknown scalar type for operator: ${fieldMeta.type}`);
196
+ }
197
+ if (supportedOps.size === 0) {
198
+ throw new ShapeError(`Type "${fieldMeta.type}" does not support filter operators`);
199
+ }
200
+ if (!supportedOps.has(operator)) {
201
+ throw new ShapeError(`Operator "${operator}" not supported for type "${fieldMeta.type}"`);
202
+ }
203
+ const factory = SCALAR_BASE[fieldMeta.type];
204
+ if (!factory) {
205
+ throw new ShapeError(`Unknown scalar type: ${fieldMeta.type}`);
206
+ }
207
+ const scalar = factory();
208
+ if (operator === "equals" || operator === "not") {
209
+ return !fieldMeta.isRequired ? z2.union([scalar, z2.null()]) : scalar;
210
+ }
211
+ if (operator === "in" || operator === "notIn") {
212
+ if (!fieldMeta.isRequired) {
213
+ return z2.array(z2.union([scalar, z2.null()]));
214
+ }
215
+ return z2.array(scalar);
216
+ }
217
+ return scalar;
218
+ }
219
+
220
+ // src/runtime/schema-builder.ts
221
+ var DEFAULT_MAX_CACHE = 500;
222
+ var DEFAULT_MAX_DEPTH = 5;
223
+ function lruGet(cache, key) {
224
+ const value = cache.get(key);
225
+ if (value !== void 0) {
226
+ cache.delete(key);
227
+ cache.set(key, value);
228
+ }
229
+ return value;
230
+ }
231
+ function lruSet(cache, key, value, maxSize) {
232
+ if (cache.has(key))
233
+ cache.delete(key);
234
+ cache.set(key, value);
235
+ if (cache.size > maxSize) {
236
+ const oldest = cache.keys().next().value;
237
+ if (oldest !== void 0)
238
+ cache.delete(oldest);
239
+ }
240
+ }
241
+ function createSchemaBuilder(typeMap, zodChains, enumMap) {
242
+ const chainCache = /* @__PURE__ */ new Map();
243
+ function buildFieldSchema(model, field) {
244
+ const cacheKey = `${model}.${field}`;
245
+ const cached = lruGet(chainCache, cacheKey);
246
+ if (cached)
247
+ return cached;
248
+ const modelFields = typeMap[model];
249
+ if (!modelFields)
250
+ throw new ShapeError(`Unknown model: ${model}`);
251
+ const fieldMeta = modelFields[field];
252
+ if (!fieldMeta)
253
+ throw new ShapeError(`Unknown field "${field}" on model "${model}"`);
254
+ const base = createBaseType(fieldMeta, enumMap);
255
+ let result = base;
256
+ const chainFn = zodChains[model]?.[field];
257
+ if (chainFn) {
258
+ try {
259
+ result = chainFn(base);
260
+ } catch (err) {
261
+ throw new ShapeError(
262
+ `Invalid @zod directive on ${model}.${field} (${fieldMeta.type}): ${err.message}`,
263
+ { cause: err }
264
+ );
265
+ }
266
+ }
267
+ lruSet(chainCache, cacheKey, result, DEFAULT_MAX_CACHE);
268
+ return result;
269
+ }
270
+ function buildBaseFieldSchema(model, field) {
271
+ const modelFields = typeMap[model];
272
+ if (!modelFields)
273
+ throw new ShapeError(`Unknown model: ${model}`);
274
+ const fieldMeta = modelFields[field];
275
+ if (!fieldMeta)
276
+ throw new ShapeError(`Unknown field "${field}" on model "${model}"`);
277
+ return createBaseType(fieldMeta, enumMap);
278
+ }
279
+ function buildInputSchema(model, opts) {
280
+ if (opts.pick && opts.omit) {
281
+ throw new ShapeError('InputOpts cannot define both "pick" and "omit"');
282
+ }
283
+ const mode = opts.mode ?? "create";
284
+ const allowNull = opts.allowNull ?? false;
285
+ const modelFields = typeMap[model];
286
+ if (!modelFields)
287
+ throw new ShapeError(`Unknown model: ${model}`);
288
+ let fieldNames = Object.keys(modelFields).filter((name) => {
289
+ const meta = modelFields[name];
290
+ return !meta.isRelation && !meta.isUpdatedAt;
291
+ });
292
+ if (opts.pick) {
293
+ for (const name of opts.pick) {
294
+ if (!modelFields[name])
295
+ throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
296
+ if (modelFields[name].isRelation)
297
+ throw new ShapeError(`Field "${name}" cannot be used in input schema (relation field)`);
298
+ if (modelFields[name].isUpdatedAt)
299
+ throw new ShapeError(`Field "${name}" cannot be used in input schema (updatedAt field)`);
300
+ }
301
+ fieldNames = fieldNames.filter((n) => opts.pick.includes(n));
302
+ } else if (opts.omit) {
303
+ for (const name of opts.omit) {
304
+ if (!modelFields[name])
305
+ throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
306
+ }
307
+ fieldNames = fieldNames.filter((n) => !opts.omit.includes(n));
308
+ }
309
+ const schemaMap = {};
310
+ for (const name of fieldNames) {
311
+ const fieldMeta = modelFields[name];
312
+ let fieldSchema;
313
+ if (opts.refine?.[name]) {
314
+ fieldSchema = opts.refine[name](buildBaseFieldSchema(model, name));
315
+ } else {
316
+ fieldSchema = buildFieldSchema(model, name);
317
+ }
318
+ if (mode === "create") {
319
+ if (!fieldMeta.isRequired) {
320
+ fieldSchema = allowNull ? fieldSchema.nullable().optional() : fieldSchema.optional();
321
+ } else if (fieldMeta.hasDefault) {
322
+ fieldSchema = fieldSchema.optional();
323
+ }
324
+ } else {
325
+ if (!fieldMeta.isRequired && allowNull) {
326
+ fieldSchema = fieldSchema.nullable().optional();
327
+ } else {
328
+ fieldSchema = fieldSchema.optional();
329
+ }
330
+ }
331
+ schemaMap[name] = fieldSchema;
332
+ }
333
+ let schema = z3.object(schemaMap).strict();
334
+ if (opts.partial) {
335
+ schema = schema.partial();
336
+ }
337
+ return {
338
+ schema,
339
+ parse(data) {
340
+ return schema.parse(data);
341
+ }
342
+ };
343
+ }
344
+ function buildModelSchema(model, opts, depth = 0, maxDepth) {
345
+ if (opts.pick && opts.omit) {
346
+ throw new ShapeError('ModelOpts cannot define both "pick" and "omit"');
347
+ }
348
+ const effectiveMaxDepth = maxDepth ?? opts.maxDepth ?? DEFAULT_MAX_DEPTH;
349
+ if (depth > effectiveMaxDepth) {
350
+ throw new ShapeError(`Maximum include depth (${effectiveMaxDepth}) exceeded`);
351
+ }
352
+ const modelFields = typeMap[model];
353
+ if (!modelFields)
354
+ throw new ShapeError(`Unknown model: ${model}`);
355
+ const includeKeys = new Set(Object.keys(opts.include ?? {}));
356
+ if (opts.pick) {
357
+ for (const name of opts.pick) {
358
+ if (!modelFields[name])
359
+ throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
360
+ if (modelFields[name].isRelation && !includeKeys.has(name)) {
361
+ throw new ShapeError(`Field "${name}" is a relation on model "${model}". Use include: { ${name}: ... } instead of pick.`);
362
+ }
363
+ }
364
+ }
365
+ if (opts.omit) {
366
+ for (const name of opts.omit) {
367
+ if (!modelFields[name])
368
+ throw new ShapeError(`Unknown field "${name}" on model "${model}"`);
369
+ }
370
+ }
371
+ let scalarNames = Object.keys(modelFields).filter((name) => {
372
+ const meta = modelFields[name];
373
+ return !meta.isRelation;
374
+ });
375
+ if (opts.pick) {
376
+ scalarNames = scalarNames.filter((n) => opts.pick.includes(n));
377
+ } else if (opts.omit) {
378
+ scalarNames = scalarNames.filter((n) => !opts.omit.includes(n));
379
+ }
380
+ const schemaMap = {};
381
+ for (const name of scalarNames) {
382
+ const fieldMeta = modelFields[name];
383
+ let fieldSchema = createBaseType(fieldMeta, enumMap);
384
+ if (!fieldMeta.isRequired) {
385
+ fieldSchema = fieldSchema.nullable();
386
+ }
387
+ schemaMap[name] = fieldSchema;
388
+ }
389
+ for (const [relName, relOpts] of Object.entries(opts.include ?? {})) {
390
+ const fieldMeta = modelFields[relName];
391
+ if (!fieldMeta)
392
+ throw new ShapeError(`Unknown field "${relName}" on model "${model}"`);
393
+ if (!fieldMeta.isRelation)
394
+ throw new ShapeError(`Field "${relName}" is not a relation on model "${model}"`);
395
+ const relatedModel = fieldMeta.type;
396
+ if (!typeMap[relatedModel]) {
397
+ throw new ShapeError(`Related model "${relatedModel}" not found in type map`);
398
+ }
399
+ let relSchema = buildModelSchema(
400
+ relatedModel,
401
+ relOpts,
402
+ depth + 1,
403
+ effectiveMaxDepth
404
+ );
405
+ if (fieldMeta.isList) {
406
+ relSchema = z3.array(relSchema);
407
+ } else if (!fieldMeta.isRequired) {
408
+ relSchema = relSchema.nullable();
409
+ }
410
+ schemaMap[relName] = relSchema;
411
+ }
412
+ if (opts._count) {
413
+ const relationNames = Object.keys(modelFields).filter((n) => modelFields[n].isRelation);
414
+ if (opts._count === true) {
415
+ const countFields = {};
416
+ for (const relName of relationNames) {
417
+ countFields[relName] = z3.number().int().min(0);
418
+ }
419
+ schemaMap["_count"] = z3.object(countFields);
420
+ } else {
421
+ const countFields = {};
422
+ for (const relName of Object.keys(opts._count)) {
423
+ if (!modelFields[relName])
424
+ throw new ShapeError(`Unknown field "${relName}" on model "${model}" in _count`);
425
+ if (!modelFields[relName].isRelation)
426
+ throw new ShapeError(`Field "${relName}" is not a relation on model "${model}" in _count`);
427
+ countFields[relName] = z3.number().int().min(0);
428
+ }
429
+ schemaMap["_count"] = z3.object(countFields);
430
+ }
431
+ }
432
+ let schema = z3.object(schemaMap);
433
+ if (opts.strict) {
434
+ schema = schema.strict();
435
+ }
436
+ return schema;
437
+ }
438
+ return { buildFieldSchema, buildBaseFieldSchema, buildInputSchema, buildModelSchema };
439
+ }
440
+
441
+ // src/runtime/query-builder.ts
442
+ import { z as z4 } from "zod";
443
+
444
+ // src/shared/constants.ts
445
+ var SHAPE_CONFIG_KEYS = /* @__PURE__ */ new Set([
446
+ "where",
447
+ "include",
448
+ "select",
449
+ "orderBy",
450
+ "cursor",
451
+ "take",
452
+ "skip",
453
+ "distinct",
454
+ "having",
455
+ "_count",
456
+ "_avg",
457
+ "_sum",
458
+ "_min",
459
+ "_max",
460
+ "by"
461
+ ]);
462
+ var GUARD_SHAPE_KEYS = /* @__PURE__ */ new Set([
463
+ "data",
464
+ ...SHAPE_CONFIG_KEYS
465
+ ]);
466
+
467
+ // src/shared/match-caller.ts
468
+ function matchCallerPattern(patterns, caller) {
469
+ if (patterns.includes(caller))
470
+ return caller;
471
+ const matches = [];
472
+ for (const pattern of patterns) {
473
+ if (!pattern.includes(":"))
474
+ continue;
475
+ const patternParts = pattern.split("/");
476
+ const callerParts = caller.split("/");
477
+ if (patternParts.length !== callerParts.length)
478
+ continue;
479
+ let ok = true;
480
+ for (let i = 0; i < patternParts.length; i++) {
481
+ if (patternParts[i].startsWith(":"))
482
+ continue;
483
+ if (patternParts[i] !== callerParts[i]) {
484
+ ok = false;
485
+ break;
486
+ }
487
+ }
488
+ if (ok)
489
+ matches.push(pattern);
490
+ }
491
+ if (matches.length === 0)
492
+ return null;
493
+ if (matches.length > 1) {
494
+ throw new CallerError(
495
+ `Ambiguous caller "${caller}" matches multiple patterns: ${matches.map((p) => `"${p}"`).join(", ")}`
496
+ );
497
+ }
498
+ return matches[0];
499
+ }
500
+
501
+ // src/runtime/policy.ts
502
+ function requireContext(ctx, label) {
503
+ if (ctx === void 0 || ctx === null) {
504
+ throw new PolicyError(`Context required for ${label}`);
505
+ }
506
+ }
507
+
508
+ // src/runtime/query-builder.ts
509
+ var METHOD_ALLOWED_ARGS = {
510
+ findMany: /* @__PURE__ */ new Set([
511
+ "where",
512
+ "include",
513
+ "select",
514
+ "orderBy",
515
+ "cursor",
516
+ "take",
517
+ "skip",
518
+ "distinct"
519
+ ]),
520
+ findFirst: /* @__PURE__ */ new Set([
521
+ "where",
522
+ "include",
523
+ "select",
524
+ "orderBy",
525
+ "cursor",
526
+ "take",
527
+ "skip",
528
+ "distinct"
529
+ ]),
530
+ findFirstOrThrow: /* @__PURE__ */ new Set([
531
+ "where",
532
+ "include",
533
+ "select",
534
+ "orderBy",
535
+ "cursor",
536
+ "take",
537
+ "skip",
538
+ "distinct"
539
+ ]),
540
+ findUnique: /* @__PURE__ */ new Set(["where", "include", "select"]),
541
+ findUniqueOrThrow: /* @__PURE__ */ new Set(["where", "include", "select"]),
542
+ count: /* @__PURE__ */ new Set(["where", "select", "cursor", "orderBy", "skip", "take"]),
543
+ aggregate: /* @__PURE__ */ new Set([
544
+ "where",
545
+ "orderBy",
546
+ "cursor",
547
+ "take",
548
+ "skip",
549
+ "_count",
550
+ "_avg",
551
+ "_sum",
552
+ "_min",
553
+ "_max"
554
+ ]),
555
+ groupBy: /* @__PURE__ */ new Set([
556
+ "where",
557
+ "by",
558
+ "having",
559
+ "_count",
560
+ "_avg",
561
+ "_sum",
562
+ "_min",
563
+ "_max",
564
+ "orderBy",
565
+ "take",
566
+ "skip"
567
+ ])
568
+ };
569
+ var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
570
+ "findUnique",
571
+ "findUniqueOrThrow"
572
+ ]);
573
+ var STRING_MODE_OPS = /* @__PURE__ */ new Set([
574
+ "contains",
575
+ "startsWith",
576
+ "endsWith",
577
+ "equals"
578
+ ]);
579
+ var UNSUPPORTED_WHERE_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
580
+ var UNSUPPORTED_BY_TYPES = /* @__PURE__ */ new Set(["Json", "Bytes"]);
581
+ var KNOWN_NESTED_INCLUDE_KEYS = /* @__PURE__ */ new Set([
582
+ "where",
583
+ "include",
584
+ "select",
585
+ "orderBy",
586
+ "cursor",
587
+ "take",
588
+ "skip"
589
+ ]);
590
+ var KNOWN_NESTED_SELECT_KEYS = /* @__PURE__ */ new Set([
591
+ "select",
592
+ "where",
593
+ "orderBy",
594
+ "cursor",
595
+ "take",
596
+ "skip"
597
+ ]);
598
+ var KNOWN_COUNT_SELECT_ENTRY_KEYS = /* @__PURE__ */ new Set(["where"]);
599
+ function isPlainObject(v) {
600
+ if (typeof v !== "object" || v === null || Array.isArray(v))
601
+ return false;
602
+ const proto = Object.getPrototypeOf(v);
603
+ return proto === Object.prototype || proto === null;
604
+ }
605
+ function mergeForced(where, forced) {
606
+ if (!where)
607
+ return forced;
608
+ return { AND: [where, forced] };
609
+ }
610
+ function mergeUniqueForced(where, forced) {
611
+ if (!where)
612
+ return { ...forced };
613
+ return { ...where, AND: [forced] };
614
+ }
615
+ function applyBuiltShape(built, body, isUniqueMethod) {
616
+ const validated = built.zodSchema.parse(body);
617
+ if (Object.keys(built.forcedWhere).length > 0) {
618
+ const cloned = structuredClone(built.forcedWhere);
619
+ validated.where = isUniqueMethod ? mergeUniqueForced(
620
+ validated.where,
621
+ cloned
622
+ ) : mergeForced(
623
+ validated.where,
624
+ cloned
625
+ );
626
+ }
627
+ if (Object.keys(built.forcedIncludeTree).length > 0) {
628
+ applyForcedTree(validated, "include", built.forcedIncludeTree);
629
+ }
630
+ if (Object.keys(built.forcedSelectTree).length > 0) {
631
+ applyForcedTree(validated, "select", built.forcedSelectTree);
632
+ }
633
+ if (Object.keys(built.forcedIncludeCountWhere).length > 0) {
634
+ const includeContainer = validated.include;
635
+ if (includeContainer) {
636
+ applyForcedCountWhere(includeContainer, built.forcedIncludeCountWhere);
637
+ }
638
+ }
639
+ if (Object.keys(built.forcedSelectCountWhere).length > 0) {
640
+ const selectContainer = validated.select;
641
+ if (selectContainer) {
642
+ applyForcedCountWhere(selectContainer, built.forcedSelectCountWhere);
643
+ }
644
+ }
645
+ return validated;
646
+ }
647
+ function applyForcedTree(validated, key, tree) {
648
+ const container = validated[key];
649
+ if (!container)
650
+ return;
651
+ for (const [relName, forced] of Object.entries(tree)) {
652
+ const relVal = container[relName];
653
+ if (relVal === void 0)
654
+ continue;
655
+ if (relVal === true) {
656
+ const expanded = {};
657
+ if (forced.where)
658
+ expanded.where = structuredClone(forced.where);
659
+ if (forced.include) {
660
+ expanded.include = buildForcedOnlyContainer(forced.include);
661
+ applyForcedTree(expanded, "include", forced.include);
662
+ }
663
+ if (forced.select) {
664
+ expanded.select = buildForcedOnlyContainer(forced.select);
665
+ applyForcedTree(expanded, "select", forced.select);
666
+ }
667
+ if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
668
+ const countSelect = {};
669
+ for (const [countRel, countForced] of Object.entries(
670
+ forced._countWhere
671
+ )) {
672
+ countSelect[countRel] = { where: structuredClone(countForced) };
673
+ }
674
+ expanded._count = { select: countSelect };
675
+ }
676
+ if (expanded.include && expanded.select) {
677
+ throw new ShapeError(
678
+ `Forced tree for relation "${relName}" produces both "include" and "select". Prisma does not allow both at the same level.`
679
+ );
680
+ }
681
+ container[relName] = Object.keys(expanded).length > 0 ? expanded : true;
682
+ continue;
683
+ }
684
+ if (isPlainObject(relVal)) {
685
+ const relObj = relVal;
686
+ if (forced.where) {
687
+ relObj.where = mergeForced(
688
+ relObj.where,
689
+ structuredClone(forced.where)
690
+ );
691
+ }
692
+ if (forced.include) {
693
+ if (!relObj.include)
694
+ relObj.include = buildForcedOnlyContainer(forced.include);
695
+ applyForcedTree(relObj, "include", forced.include);
696
+ }
697
+ if (forced.select) {
698
+ if (!relObj.select)
699
+ relObj.select = buildForcedOnlyContainer(forced.select);
700
+ applyForcedTree(relObj, "select", forced.select);
701
+ }
702
+ if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
703
+ applyForcedCountWhere(relObj, forced._countWhere);
704
+ }
705
+ if (relObj.include && relObj.select) {
706
+ throw new ShapeError(
707
+ `Relation "${relName}" has both "include" and "select" after forced tree merge. Prisma does not allow both at the same level.`
708
+ );
709
+ }
710
+ }
711
+ }
712
+ }
713
+ function buildForcedOnlyContainer(tree) {
714
+ const result = {};
715
+ for (const [relName, forced] of Object.entries(tree)) {
716
+ const nested = {};
717
+ if (forced.where)
718
+ nested.where = structuredClone(forced.where);
719
+ if (forced.include)
720
+ nested.include = buildForcedOnlyContainer(forced.include);
721
+ if (forced.select)
722
+ nested.select = buildForcedOnlyContainer(forced.select);
723
+ if (forced._countWhere && Object.keys(forced._countWhere).length > 0) {
724
+ const countSelect = {};
725
+ for (const [countRel, countForced] of Object.entries(
726
+ forced._countWhere
727
+ )) {
728
+ countSelect[countRel] = { where: structuredClone(countForced) };
729
+ }
730
+ nested._count = { select: countSelect };
731
+ }
732
+ result[relName] = Object.keys(nested).length > 0 ? nested : true;
733
+ }
734
+ return result;
735
+ }
736
+ function applyForcedCountWhere(container, forcedCountWhere) {
737
+ const countVal = container._count;
738
+ if (!countVal || countVal === true || !isPlainObject(countVal))
739
+ return;
740
+ const countObj = countVal;
741
+ const selectVal = countObj.select;
742
+ if (!selectVal || !isPlainObject(selectVal))
743
+ return;
744
+ const selectObj = selectVal;
745
+ for (const [relName, forced] of Object.entries(forcedCountWhere)) {
746
+ const relVal = selectObj[relName];
747
+ if (relVal === void 0)
748
+ continue;
749
+ if (relVal === true) {
750
+ selectObj[relName] = { where: structuredClone(forced) };
751
+ } else if (isPlainObject(relVal)) {
752
+ const relObj = relVal;
753
+ relObj.where = mergeForced(
754
+ relObj.where,
755
+ structuredClone(forced)
756
+ );
757
+ }
758
+ }
759
+ }
760
+ function collectWhereFieldKeys(where) {
761
+ const keys = /* @__PURE__ */ new Set();
762
+ for (const [key, value] of Object.entries(where)) {
763
+ if (key === "AND") {
764
+ const items = Array.isArray(value) ? value : [value];
765
+ for (const item of items) {
766
+ if (isPlainObject(item)) {
767
+ for (const k of collectWhereFieldKeys(item))
768
+ keys.add(k);
769
+ }
770
+ }
771
+ } else if (key !== "OR" && key !== "NOT") {
772
+ keys.add(key);
773
+ }
774
+ }
775
+ return keys;
776
+ }
777
+ function validateResolvedUniqueWhere(model, where, method, uniqueMap) {
778
+ const constraints = uniqueMap[model];
779
+ if (!constraints || constraints.length === 0)
780
+ return;
781
+ const fieldKeys = collectWhereFieldKeys(where);
782
+ const covered = constraints.some(
783
+ (constraint) => constraint.every((field) => fieldKeys.has(field))
784
+ );
785
+ if (!covered) {
786
+ const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
787
+ throw new ShapeError(
788
+ `${method} on model "${model}" requires resolved where to cover a unique constraint: ${constraintDesc}`
789
+ );
790
+ }
791
+ }
792
+ function validateUniqueEquality(model, where, method, uniqueMap) {
793
+ const constraints = uniqueMap[model];
794
+ if (!constraints || constraints.length === 0)
795
+ return;
796
+ const whereFields = new Set(Object.keys(where));
797
+ const valid = constraints.some((constraint) => {
798
+ if (!constraint.every((field) => whereFields.has(field)))
799
+ return false;
800
+ return constraint.every((field) => {
801
+ const ops = where[field];
802
+ if (!ops)
803
+ return false;
804
+ return Object.keys(ops).every((op) => op === "equals");
805
+ });
806
+ });
807
+ if (!valid) {
808
+ const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
809
+ throw new ShapeError(
810
+ `${method} on model "${model}" requires where to cover a unique constraint with equality operators only: ${constraintDesc}`
811
+ );
812
+ }
813
+ }
814
+ function validateNestedKeys(keys, allowed, context) {
815
+ for (const key of keys) {
816
+ if (!allowed.has(key)) {
817
+ throw new ShapeError(
818
+ `Unknown key "${key}" in ${context}. Allowed: ${[...allowed].join(", ")}`
819
+ );
820
+ }
821
+ }
822
+ }
823
+ function createQueryBuilder(typeMap, enumMap, uniqueMap = {}) {
824
+ function isShapeConfig(obj) {
825
+ if (!isPlainObject(obj))
826
+ return false;
827
+ const keys = Object.keys(obj);
828
+ return keys.length === 0 || keys.every((k) => SHAPE_CONFIG_KEYS.has(k));
829
+ }
830
+ function buildWhereSchema(model, whereConfig) {
831
+ const modelFields = typeMap[model];
832
+ if (!modelFields)
833
+ throw new ShapeError(`Unknown model: ${model}`);
834
+ const fieldSchemas = {};
835
+ const forced = {};
836
+ for (const [fieldName, operators] of Object.entries(whereConfig)) {
837
+ const fieldMeta = modelFields[fieldName];
838
+ if (!fieldMeta)
839
+ throw new ShapeError(
840
+ `Unknown field "${fieldName}" on model "${model}"`
841
+ );
842
+ if (fieldMeta.isRelation)
843
+ throw new ShapeError(
844
+ `Relation field "${fieldName}" cannot be used in where`
845
+ );
846
+ if (UNSUPPORTED_WHERE_TYPES.has(fieldMeta.type) && !fieldMeta.isList) {
847
+ throw new ShapeError(
848
+ `${fieldMeta.type} field "${fieldName}" cannot be used in where filters`
849
+ );
850
+ }
851
+ const opSchemas = {};
852
+ const fieldForced = {};
853
+ let hasClientOps = false;
854
+ let hasStringModeOp = false;
855
+ const clientOpKeys = [];
856
+ for (const [op, value] of Object.entries(operators)) {
857
+ if (value === true) {
858
+ opSchemas[op] = createOperatorSchema(
859
+ fieldMeta,
860
+ op,
861
+ enumMap
862
+ ).optional();
863
+ hasClientOps = true;
864
+ clientOpKeys.push(op);
865
+ if (fieldMeta.type === "String" && !fieldMeta.isList && STRING_MODE_OPS.has(op)) {
866
+ hasStringModeOp = true;
867
+ }
868
+ } else {
869
+ const opSchema = createOperatorSchema(fieldMeta, op, enumMap);
870
+ let parsed;
871
+ try {
872
+ parsed = opSchema.parse(value);
873
+ } catch (err) {
874
+ throw new ShapeError(
875
+ `Invalid forced value for "${model}.${fieldName}.${op}": ${err.message}`
876
+ );
877
+ }
878
+ fieldForced[op] = parsed;
879
+ }
880
+ }
881
+ if (!hasClientOps && Object.keys(fieldForced).length === 0) {
882
+ throw new ShapeError(
883
+ `Empty operator config for where field "${fieldName}" on model "${model}". Define at least one operator.`
884
+ );
885
+ }
886
+ if (hasStringModeOp) {
887
+ opSchemas["mode"] = z4.enum(["default", "insensitive"]).optional();
888
+ }
889
+ if (hasClientOps) {
890
+ const opObj = z4.object(opSchemas).strict();
891
+ fieldSchemas[fieldName] = opObj.refine(
892
+ (v) => clientOpKeys.some(
893
+ (k) => v[k] !== void 0
894
+ ),
895
+ {
896
+ message: `At least one operator required for where field "${fieldName}"`
897
+ }
898
+ ).optional();
899
+ }
900
+ if (Object.keys(fieldForced).length > 0) {
901
+ forced[fieldName] = fieldForced;
902
+ }
903
+ }
904
+ const schema = Object.keys(fieldSchemas).length > 0 ? z4.object(fieldSchemas).strict().optional() : null;
905
+ return { schema, forced };
906
+ }
907
+ function buildCountFieldSchema(model, config, context) {
908
+ if (config === true) {
909
+ return z4.literal(true).optional();
910
+ }
911
+ const modelFields = typeMap[model];
912
+ if (!modelFields)
913
+ throw new ShapeError(`Unknown model: ${model}`);
914
+ const fieldSchemas = {};
915
+ for (const fieldName of Object.keys(config)) {
916
+ if (fieldName !== "_all") {
917
+ const fieldMeta = modelFields[fieldName];
918
+ if (!fieldMeta)
919
+ throw new ShapeError(
920
+ `Unknown field "${fieldName}" on model "${model}" in ${context}`
921
+ );
922
+ if (fieldMeta.isRelation)
923
+ throw new ShapeError(
924
+ `Relation field "${fieldName}" cannot be used in ${context}`
925
+ );
926
+ }
927
+ fieldSchemas[fieldName] = z4.literal(true).optional();
928
+ }
929
+ return z4.object(fieldSchemas).strict().optional();
930
+ }
931
+ function buildIncludeCountSchema(model, config) {
932
+ const modelFields = typeMap[model];
933
+ if (!modelFields)
934
+ throw new ShapeError(`Unknown model: ${model}`);
935
+ if (config === true) {
936
+ return { schema: z4.literal(true).optional(), forcedCountWhere: {} };
937
+ }
938
+ if (!isPlainObject(config) || !("select" in config)) {
939
+ throw new ShapeError(
940
+ `Invalid _count config on model "${model}". Expected true or { select: { ... } }`
941
+ );
942
+ }
943
+ for (const key of Object.keys(config)) {
944
+ if (key !== "select") {
945
+ throw new ShapeError(
946
+ `Unknown key "${key}" in _count config on model "${model}". Only "select" is allowed.`
947
+ );
948
+ }
949
+ }
950
+ const selectObj = config.select;
951
+ const countSelectFields = {};
952
+ const forcedCountWhere = {};
953
+ for (const [fieldName, fieldConfig] of Object.entries(selectObj)) {
954
+ const fieldMeta = modelFields[fieldName];
955
+ if (!fieldMeta)
956
+ throw new ShapeError(
957
+ `Unknown field "${fieldName}" on model "${model}" in _count.select`
958
+ );
959
+ if (!fieldMeta.isRelation)
960
+ throw new ShapeError(
961
+ `Field "${fieldName}" is not a relation on model "${model}" in _count.select`
962
+ );
963
+ if (fieldConfig === true) {
964
+ countSelectFields[fieldName] = z4.literal(true).optional();
965
+ } else if (isPlainObject(fieldConfig)) {
966
+ validateNestedKeys(
967
+ Object.keys(fieldConfig),
968
+ KNOWN_COUNT_SELECT_ENTRY_KEYS,
969
+ `_count.select.${fieldName} on model "${model}"`
970
+ );
971
+ if (fieldConfig.where) {
972
+ const relatedType = fieldMeta.type;
973
+ const { schema: whereSchema, forced } = buildWhereSchema(
974
+ relatedType,
975
+ fieldConfig.where
976
+ );
977
+ const nestedSchemas = {};
978
+ if (whereSchema)
979
+ nestedSchemas["where"] = whereSchema;
980
+ const nestedObj = z4.object(nestedSchemas).strict();
981
+ countSelectFields[fieldName] = z4.union([z4.literal(true), nestedObj]).optional();
982
+ if (Object.keys(forced).length > 0) {
983
+ forcedCountWhere[fieldName] = forced;
984
+ }
985
+ } else {
986
+ countSelectFields[fieldName] = z4.literal(true).optional();
987
+ }
988
+ } else {
989
+ throw new ShapeError(
990
+ `Invalid config for _count.select.${fieldName} on model "${model}". Expected true or { where: { ... } }`
991
+ );
992
+ }
993
+ }
994
+ const selectSchema = z4.object(countSelectFields).strict();
995
+ return {
996
+ schema: z4.object({ select: selectSchema }).strict().optional(),
997
+ forcedCountWhere
998
+ };
999
+ }
1000
+ function buildAggregateFieldSchema(model, opName, fieldConfig) {
1001
+ const modelFields = typeMap[model];
1002
+ if (!modelFields)
1003
+ throw new ShapeError(`Unknown model: ${model}`);
1004
+ const isNumericOnly = opName === "_avg" || opName === "_sum";
1005
+ const isComparableOnly = opName === "_min" || opName === "_max";
1006
+ const fieldSchemas = {};
1007
+ for (const fieldName of Object.keys(fieldConfig)) {
1008
+ if (fieldName === "_all" && opName === "_count") {
1009
+ fieldSchemas[fieldName] = z4.literal(true).optional();
1010
+ continue;
1011
+ }
1012
+ const fieldMeta = modelFields[fieldName];
1013
+ if (!fieldMeta)
1014
+ throw new ShapeError(
1015
+ `Unknown field "${fieldName}" on model "${model}" in ${opName}`
1016
+ );
1017
+ if (fieldMeta.isRelation)
1018
+ throw new ShapeError(
1019
+ `Relation field "${fieldName}" cannot be used in ${opName}`
1020
+ );
1021
+ if (isNumericOnly && !NUMERIC_TYPES.has(fieldMeta.type)) {
1022
+ throw new ShapeError(
1023
+ `Field "${fieldName}" (${fieldMeta.type}) cannot be used in ${opName}. Only numeric types (Int, Float, Decimal, BigInt) are supported.`
1024
+ );
1025
+ }
1026
+ if (isComparableOnly && !COMPARABLE_TYPES.has(fieldMeta.type)) {
1027
+ throw new ShapeError(
1028
+ `Field "${fieldName}" (${fieldMeta.type}) cannot be used in ${opName}. Only comparable types (Int, Float, Decimal, BigInt, String, DateTime) are supported.`
1029
+ );
1030
+ }
1031
+ fieldSchemas[fieldName] = z4.literal(true).optional();
1032
+ }
1033
+ return z4.object(fieldSchemas).strict().optional();
1034
+ }
1035
+ function buildBySchema(model, byConfig) {
1036
+ if (byConfig.length === 0) {
1037
+ throw new ShapeError('groupBy "by" must contain at least one field');
1038
+ }
1039
+ const modelFields = typeMap[model];
1040
+ if (!modelFields)
1041
+ throw new ShapeError(`Unknown model: ${model}`);
1042
+ for (const fieldName of byConfig) {
1043
+ const fieldMeta = modelFields[fieldName];
1044
+ if (!fieldMeta)
1045
+ throw new ShapeError(
1046
+ `Unknown field "${fieldName}" on model "${model}" in by`
1047
+ );
1048
+ if (fieldMeta.isRelation)
1049
+ throw new ShapeError(
1050
+ `Relation field "${fieldName}" cannot be used in by`
1051
+ );
1052
+ if (UNSUPPORTED_BY_TYPES.has(fieldMeta.type)) {
1053
+ throw new ShapeError(
1054
+ `${fieldMeta.type} field "${fieldName}" cannot be used in by`
1055
+ );
1056
+ }
1057
+ if (fieldMeta.isList) {
1058
+ throw new ShapeError(`List field "${fieldName}" cannot be used in by`);
1059
+ }
1060
+ }
1061
+ const enumSchema = z4.enum(byConfig);
1062
+ return z4.union([enumSchema, z4.array(enumSchema).min(1)]);
1063
+ }
1064
+ function buildCursorSchema(model, cursorConfig) {
1065
+ const modelFields = typeMap[model];
1066
+ if (!modelFields)
1067
+ throw new ShapeError(`Unknown model: ${model}`);
1068
+ const cursorFields = new Set(Object.keys(cursorConfig));
1069
+ const constraints = uniqueMap[model];
1070
+ if (constraints && constraints.length > 0) {
1071
+ const covered = constraints.some(
1072
+ (constraint) => constraint.every((field) => cursorFields.has(field))
1073
+ );
1074
+ if (!covered) {
1075
+ const constraintDesc = constraints.map((c) => `(${c.join(", ")})`).join(" | ");
1076
+ throw new ShapeError(
1077
+ `cursor on model "${model}" must cover a unique constraint: ${constraintDesc}`
1078
+ );
1079
+ }
1080
+ }
1081
+ const fieldSchemas = {};
1082
+ for (const fieldName of Object.keys(cursorConfig)) {
1083
+ const fieldMeta = modelFields[fieldName];
1084
+ if (!fieldMeta)
1085
+ throw new ShapeError(
1086
+ `Unknown field "${fieldName}" on model "${model}" in cursor`
1087
+ );
1088
+ if (fieldMeta.isRelation)
1089
+ throw new ShapeError(
1090
+ `Relation field "${fieldName}" cannot be used in cursor`
1091
+ );
1092
+ if (fieldMeta.isList)
1093
+ throw new ShapeError(
1094
+ `List field "${fieldName}" cannot be used in cursor`
1095
+ );
1096
+ fieldSchemas[fieldName] = createBaseType(fieldMeta, enumMap);
1097
+ }
1098
+ return z4.object(fieldSchemas).strict().optional();
1099
+ }
1100
+ function buildDistinctSchema(model, distinctConfig) {
1101
+ const modelFields = typeMap[model];
1102
+ if (!modelFields)
1103
+ throw new ShapeError(`Unknown model: ${model}`);
1104
+ for (const fieldName of distinctConfig) {
1105
+ const fieldMeta = modelFields[fieldName];
1106
+ if (!fieldMeta)
1107
+ throw new ShapeError(
1108
+ `Unknown field "${fieldName}" on model "${model}" in distinct`
1109
+ );
1110
+ if (fieldMeta.isRelation)
1111
+ throw new ShapeError(
1112
+ `Relation field "${fieldName}" cannot be used in distinct`
1113
+ );
1114
+ if (fieldMeta.isList)
1115
+ throw new ShapeError(
1116
+ `List field "${fieldName}" cannot be used in distinct`
1117
+ );
1118
+ }
1119
+ const enumSchema = z4.enum(distinctConfig);
1120
+ return z4.union([enumSchema, z4.array(enumSchema).min(1)]).optional();
1121
+ }
1122
+ function buildIncludeSchema(model, includeConfig) {
1123
+ const modelFields = typeMap[model];
1124
+ if (!modelFields)
1125
+ throw new ShapeError(`Unknown model: ${model}`);
1126
+ const fieldSchemas = {};
1127
+ const forcedTree = {};
1128
+ let topLevelForcedCountWhere = {};
1129
+ for (const [relName, config] of Object.entries(includeConfig)) {
1130
+ if (relName === "_count") {
1131
+ const countResult = buildIncludeCountSchema(
1132
+ model,
1133
+ config
1134
+ );
1135
+ fieldSchemas["_count"] = countResult.schema;
1136
+ topLevelForcedCountWhere = countResult.forcedCountWhere;
1137
+ continue;
1138
+ }
1139
+ const fieldMeta = modelFields[relName];
1140
+ if (!fieldMeta)
1141
+ throw new ShapeError(`Unknown field "${relName}" on model "${model}"`);
1142
+ if (!fieldMeta.isRelation)
1143
+ throw new ShapeError(
1144
+ `Field "${relName}" is not a relation on model "${model}"`
1145
+ );
1146
+ if (config === true) {
1147
+ fieldSchemas[relName] = z4.literal(true).optional();
1148
+ } else {
1149
+ validateNestedKeys(
1150
+ Object.keys(config),
1151
+ KNOWN_NESTED_INCLUDE_KEYS,
1152
+ `nested include for "${relName}" on model "${model}"`
1153
+ );
1154
+ if (config.select && config.include) {
1155
+ throw new ShapeError(
1156
+ `Nested include for "${relName}" cannot define both "select" and "include".`
1157
+ );
1158
+ }
1159
+ if (!fieldMeta.isList) {
1160
+ if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
1161
+ throw new ShapeError(
1162
+ `Relation "${relName}" on model "${model}" is to-one. Only "include" and "select" are supported for to-one nested reads, not where/orderBy/cursor/take/skip.`
1163
+ );
1164
+ }
1165
+ }
1166
+ const nestedSchemas = {};
1167
+ const relForced = {};
1168
+ if (config.where) {
1169
+ const { schema: whereSchema, forced } = buildWhereSchema(
1170
+ fieldMeta.type,
1171
+ config.where
1172
+ );
1173
+ if (whereSchema)
1174
+ nestedSchemas["where"] = whereSchema;
1175
+ if (Object.keys(forced).length > 0)
1176
+ relForced.where = forced;
1177
+ }
1178
+ if (config.include) {
1179
+ const nested = buildIncludeSchema(fieldMeta.type, config.include);
1180
+ nestedSchemas["include"] = nested.schema;
1181
+ if (Object.keys(nested.forcedTree).length > 0)
1182
+ relForced.include = nested.forcedTree;
1183
+ if (Object.keys(nested.forcedCountWhere).length > 0)
1184
+ relForced._countWhere = nested.forcedCountWhere;
1185
+ }
1186
+ if (config.select) {
1187
+ const nested = buildSelectSchema(fieldMeta.type, config.select);
1188
+ nestedSchemas["select"] = nested.schema;
1189
+ if (Object.keys(nested.forcedTree).length > 0)
1190
+ relForced.select = nested.forcedTree;
1191
+ if (Object.keys(nested.forcedCountWhere).length > 0)
1192
+ relForced._countWhere = nested.forcedCountWhere;
1193
+ }
1194
+ if (config.orderBy) {
1195
+ nestedSchemas["orderBy"] = buildOrderBySchema(
1196
+ fieldMeta.type,
1197
+ config.orderBy
1198
+ );
1199
+ }
1200
+ if (config.cursor) {
1201
+ nestedSchemas["cursor"] = buildCursorSchema(
1202
+ fieldMeta.type,
1203
+ config.cursor
1204
+ );
1205
+ }
1206
+ if (config.take) {
1207
+ nestedSchemas["take"] = buildTakeSchema(config.take);
1208
+ }
1209
+ if (config.skip) {
1210
+ nestedSchemas["skip"] = z4.number().int().min(0).optional();
1211
+ }
1212
+ const nestedObj = z4.object(nestedSchemas).strict();
1213
+ fieldSchemas[relName] = z4.union([z4.literal(true), nestedObj]).optional();
1214
+ if (Object.keys(relForced).length > 0)
1215
+ forcedTree[relName] = relForced;
1216
+ }
1217
+ }
1218
+ return {
1219
+ schema: z4.object(fieldSchemas).strict().optional(),
1220
+ forcedTree,
1221
+ forcedCountWhere: topLevelForcedCountWhere
1222
+ };
1223
+ }
1224
+ function buildSelectSchema(model, selectConfig) {
1225
+ const modelFields = typeMap[model];
1226
+ if (!modelFields)
1227
+ throw new ShapeError(`Unknown model: ${model}`);
1228
+ const fieldSchemas = {};
1229
+ const forcedTree = {};
1230
+ let topLevelForcedCountWhere = {};
1231
+ for (const [fieldName, config] of Object.entries(selectConfig)) {
1232
+ if (fieldName === "_count") {
1233
+ const countResult = buildIncludeCountSchema(
1234
+ model,
1235
+ config
1236
+ );
1237
+ fieldSchemas["_count"] = countResult.schema;
1238
+ topLevelForcedCountWhere = countResult.forcedCountWhere;
1239
+ continue;
1240
+ }
1241
+ const fieldMeta = modelFields[fieldName];
1242
+ if (!fieldMeta)
1243
+ throw new ShapeError(
1244
+ `Unknown field "${fieldName}" on model "${model}"`
1245
+ );
1246
+ if (config === true) {
1247
+ fieldSchemas[fieldName] = z4.literal(true).optional();
1248
+ } else {
1249
+ if (!fieldMeta.isRelation) {
1250
+ throw new ShapeError(
1251
+ `Nested select args only valid for relations, not scalar "${fieldName}"`
1252
+ );
1253
+ }
1254
+ validateNestedKeys(
1255
+ Object.keys(config),
1256
+ KNOWN_NESTED_SELECT_KEYS,
1257
+ `nested select for "${fieldName}" on model "${model}"`
1258
+ );
1259
+ if (!fieldMeta.isList) {
1260
+ if (config.where || config.orderBy || config.cursor || config.take || config.skip) {
1261
+ throw new ShapeError(
1262
+ `Relation "${fieldName}" on model "${model}" is to-one. Only "select" is supported for to-one nested reads, not where/orderBy/cursor/take/skip.`
1263
+ );
1264
+ }
1265
+ }
1266
+ const nestedSchemas = {};
1267
+ const relForced = {};
1268
+ if (config.select) {
1269
+ const nested = buildSelectSchema(fieldMeta.type, config.select);
1270
+ nestedSchemas["select"] = nested.schema;
1271
+ if (Object.keys(nested.forcedTree).length > 0)
1272
+ relForced.select = nested.forcedTree;
1273
+ if (Object.keys(nested.forcedCountWhere).length > 0)
1274
+ relForced._countWhere = nested.forcedCountWhere;
1275
+ }
1276
+ if (config.where) {
1277
+ const { schema: whereSchema, forced } = buildWhereSchema(
1278
+ fieldMeta.type,
1279
+ config.where
1280
+ );
1281
+ if (whereSchema)
1282
+ nestedSchemas["where"] = whereSchema;
1283
+ if (Object.keys(forced).length > 0)
1284
+ relForced.where = forced;
1285
+ }
1286
+ if (config.orderBy) {
1287
+ nestedSchemas["orderBy"] = buildOrderBySchema(
1288
+ fieldMeta.type,
1289
+ config.orderBy
1290
+ );
1291
+ }
1292
+ if (config.cursor) {
1293
+ nestedSchemas["cursor"] = buildCursorSchema(
1294
+ fieldMeta.type,
1295
+ config.cursor
1296
+ );
1297
+ }
1298
+ if (config.take) {
1299
+ nestedSchemas["take"] = buildTakeSchema(config.take);
1300
+ }
1301
+ if (config.skip) {
1302
+ nestedSchemas["skip"] = z4.number().int().min(0).optional();
1303
+ }
1304
+ const nestedObj = z4.object(nestedSchemas).strict();
1305
+ fieldSchemas[fieldName] = z4.union([z4.literal(true), nestedObj]).optional();
1306
+ if (Object.keys(relForced).length > 0)
1307
+ forcedTree[fieldName] = relForced;
1308
+ }
1309
+ }
1310
+ return {
1311
+ schema: z4.object(fieldSchemas).strict().optional(),
1312
+ forcedTree,
1313
+ forcedCountWhere: topLevelForcedCountWhere
1314
+ };
1315
+ }
1316
+ function buildOrderBySchema(model, orderByConfig) {
1317
+ const modelFields = typeMap[model];
1318
+ if (!modelFields)
1319
+ throw new ShapeError(`Unknown model: ${model}`);
1320
+ const fieldSchemas = {};
1321
+ for (const fieldName of Object.keys(orderByConfig)) {
1322
+ const fieldMeta = modelFields[fieldName];
1323
+ if (!fieldMeta)
1324
+ throw new ShapeError(
1325
+ `Unknown field "${fieldName}" on model "${model}"`
1326
+ );
1327
+ if (fieldMeta.isRelation)
1328
+ throw new ShapeError(
1329
+ `Relation field "${fieldName}" cannot be used in orderBy`
1330
+ );
1331
+ if (fieldMeta.type === "Json")
1332
+ throw new ShapeError(
1333
+ `Json field "${fieldName}" cannot be used in orderBy`
1334
+ );
1335
+ if (fieldMeta.isList)
1336
+ throw new ShapeError(
1337
+ `List field "${fieldName}" cannot be used in orderBy`
1338
+ );
1339
+ fieldSchemas[fieldName] = z4.enum(["asc", "desc"]).optional();
1340
+ }
1341
+ const singleSchema = z4.object(fieldSchemas).strict();
1342
+ return z4.union([singleSchema, z4.array(singleSchema)]).optional();
1343
+ }
1344
+ function buildTakeSchema(config) {
1345
+ if (!Number.isFinite(config.max) || !Number.isInteger(config.max)) {
1346
+ throw new ShapeError(
1347
+ `take max must be a finite integer, got ${config.max}`
1348
+ );
1349
+ }
1350
+ if (config.max < 1) {
1351
+ throw new ShapeError(`take max must be at least 1, got ${config.max}`);
1352
+ }
1353
+ if (config.default !== void 0) {
1354
+ if (!Number.isFinite(config.default) || !Number.isInteger(config.default)) {
1355
+ throw new ShapeError(
1356
+ `take default must be a finite integer, got ${config.default}`
1357
+ );
1358
+ }
1359
+ if (config.default < 1) {
1360
+ throw new ShapeError(
1361
+ `take default must be at least 1, got ${config.default}`
1362
+ );
1363
+ }
1364
+ if (config.default > config.max) {
1365
+ throw new ShapeError("take default cannot exceed max");
1366
+ }
1367
+ return z4.number().int().min(1).max(config.max).default(config.default);
1368
+ }
1369
+ return z4.number().int().min(1).max(config.max).optional();
1370
+ }
1371
+ function buildHavingSchema(model, havingConfig) {
1372
+ const modelFields = typeMap[model];
1373
+ if (!modelFields)
1374
+ throw new ShapeError(`Unknown model: ${model}`);
1375
+ const fieldSchemas = {};
1376
+ for (const fieldName of Object.keys(havingConfig)) {
1377
+ const fieldMeta = modelFields[fieldName];
1378
+ if (!fieldMeta)
1379
+ throw new ShapeError(
1380
+ `Unknown field "${fieldName}" on model "${model}" in having`
1381
+ );
1382
+ if (fieldMeta.isRelation)
1383
+ throw new ShapeError(
1384
+ `Relation field "${fieldName}" cannot be used in having`
1385
+ );
1386
+ if (fieldMeta.isList)
1387
+ throw new ShapeError(
1388
+ `List field "${fieldName}" cannot be used in having`
1389
+ );
1390
+ const ops = getSupportedOperators(fieldMeta);
1391
+ if (ops.length === 0) {
1392
+ throw new ShapeError(
1393
+ `${fieldMeta.type} field "${fieldName}" cannot be used in having filters`
1394
+ );
1395
+ }
1396
+ const opSchemas = {};
1397
+ const opKeys = [];
1398
+ for (const op of ops) {
1399
+ opSchemas[op] = createOperatorSchema(fieldMeta, op, enumMap).optional();
1400
+ opKeys.push(op);
1401
+ }
1402
+ if (fieldMeta.type === "String" && !fieldMeta.isList) {
1403
+ opSchemas["mode"] = z4.enum(["default", "insensitive"]).optional();
1404
+ }
1405
+ fieldSchemas[fieldName] = z4.object(opSchemas).strict().refine(
1406
+ (v) => opKeys.some((k) => v[k] !== void 0),
1407
+ {
1408
+ message: `At least one operator required for having field "${fieldName}"`
1409
+ }
1410
+ ).optional();
1411
+ }
1412
+ return z4.object(fieldSchemas).strict().optional();
1413
+ }
1414
+ function buildCountSelectSchema(model, selectConfig) {
1415
+ const modelFields = typeMap[model];
1416
+ if (!modelFields)
1417
+ throw new ShapeError(`Unknown model: ${model}`);
1418
+ const fieldSchemas = {};
1419
+ for (const fieldName of Object.keys(selectConfig)) {
1420
+ if (fieldName === "_all") {
1421
+ fieldSchemas["_all"] = z4.literal(true).optional();
1422
+ continue;
1423
+ }
1424
+ const fieldMeta = modelFields[fieldName];
1425
+ if (!fieldMeta)
1426
+ throw new ShapeError(
1427
+ `Unknown field "${fieldName}" on model "${model}" in count select`
1428
+ );
1429
+ if (fieldMeta.isRelation)
1430
+ throw new ShapeError(
1431
+ `Relation field "${fieldName}" cannot be used in count select`
1432
+ );
1433
+ fieldSchemas[fieldName] = z4.literal(true).optional();
1434
+ }
1435
+ return z4.object(fieldSchemas).strict().optional();
1436
+ }
1437
+ function validateShapeArgs(method, shape) {
1438
+ const allowed = METHOD_ALLOWED_ARGS[method];
1439
+ for (const key of Object.keys(shape)) {
1440
+ if (!SHAPE_CONFIG_KEYS.has(key)) {
1441
+ throw new ShapeError(`Unknown shape config key "${key}"`);
1442
+ }
1443
+ if (!allowed.has(key)) {
1444
+ throw new ShapeError(`Arg "${key}" not allowed for method "${method}"`);
1445
+ }
1446
+ }
1447
+ if (shape.include && shape.select) {
1448
+ throw new ShapeError(
1449
+ 'Shape config cannot define both "include" and "select".'
1450
+ );
1451
+ }
1452
+ if (method === "groupBy" && !shape.by) {
1453
+ throw new ShapeError('groupBy shape must define "by"');
1454
+ }
1455
+ if (method === "groupBy" && (shape.include || shape.select)) {
1456
+ throw new ShapeError('groupBy does not support "include" or "select"');
1457
+ }
1458
+ if (method === "aggregate" && (shape.include || shape.select)) {
1459
+ throw new ShapeError('aggregate does not support "include" or "select"');
1460
+ }
1461
+ if (method === "count" && shape.include) {
1462
+ throw new ShapeError('count does not support "include"');
1463
+ }
1464
+ if (method === "groupBy" && shape.orderBy) {
1465
+ const bySet = new Set(shape.by);
1466
+ for (const fieldName of Object.keys(shape.orderBy)) {
1467
+ if (!bySet.has(fieldName)) {
1468
+ throw new ShapeError(
1469
+ `orderBy field "${fieldName}" must be included in "by" for groupBy`
1470
+ );
1471
+ }
1472
+ }
1473
+ }
1474
+ if (method === "groupBy" && shape.having) {
1475
+ const bySet = new Set(shape.by);
1476
+ for (const fieldName of Object.keys(shape.having)) {
1477
+ if (!bySet.has(fieldName)) {
1478
+ throw new ShapeError(
1479
+ `having field "${fieldName}" must be included in "by" for groupBy`
1480
+ );
1481
+ }
1482
+ }
1483
+ }
1484
+ }
1485
+ function validateUniqueWhere(model, method, shape) {
1486
+ if (!UNIQUE_WHERE_METHODS.has(method))
1487
+ return;
1488
+ if (!shape.where)
1489
+ return;
1490
+ validateUniqueEquality(model, shape.where, method, uniqueMap);
1491
+ }
1492
+ function buildShapeZodSchema(model, method, shape) {
1493
+ validateShapeArgs(method, shape);
1494
+ validateUniqueWhere(model, method, shape);
1495
+ const schemaFields = {};
1496
+ let forcedWhere = {};
1497
+ let forcedIncludeTree = {};
1498
+ let forcedSelectTree = {};
1499
+ let forcedIncludeCountWhere = {};
1500
+ let forcedSelectCountWhere = {};
1501
+ if (shape.where) {
1502
+ const { schema, forced } = buildWhereSchema(model, shape.where);
1503
+ if (schema)
1504
+ schemaFields["where"] = schema;
1505
+ forcedWhere = forced;
1506
+ }
1507
+ if (shape.include) {
1508
+ const result = buildIncludeSchema(model, shape.include);
1509
+ schemaFields["include"] = result.schema;
1510
+ forcedIncludeTree = result.forcedTree;
1511
+ forcedIncludeCountWhere = result.forcedCountWhere;
1512
+ }
1513
+ if (shape.select) {
1514
+ if (method === "count") {
1515
+ schemaFields["select"] = buildCountSelectSchema(model, shape.select);
1516
+ } else {
1517
+ const result = buildSelectSchema(model, shape.select);
1518
+ schemaFields["select"] = result.schema;
1519
+ forcedSelectTree = result.forcedTree;
1520
+ forcedSelectCountWhere = result.forcedCountWhere;
1521
+ }
1522
+ }
1523
+ if (shape.orderBy) {
1524
+ schemaFields["orderBy"] = buildOrderBySchema(model, shape.orderBy);
1525
+ }
1526
+ if (shape.cursor) {
1527
+ schemaFields["cursor"] = buildCursorSchema(model, shape.cursor);
1528
+ }
1529
+ if (shape.take) {
1530
+ schemaFields["take"] = buildTakeSchema(shape.take);
1531
+ }
1532
+ if (shape.skip) {
1533
+ schemaFields["skip"] = z4.number().int().min(0).optional();
1534
+ }
1535
+ if (shape.distinct) {
1536
+ schemaFields["distinct"] = buildDistinctSchema(model, shape.distinct);
1537
+ }
1538
+ if (shape._count) {
1539
+ schemaFields["_count"] = buildCountFieldSchema(
1540
+ model,
1541
+ shape._count,
1542
+ "_count"
1543
+ );
1544
+ }
1545
+ if (shape._avg) {
1546
+ schemaFields["_avg"] = buildAggregateFieldSchema(
1547
+ model,
1548
+ "_avg",
1549
+ shape._avg
1550
+ );
1551
+ }
1552
+ if (shape._sum) {
1553
+ schemaFields["_sum"] = buildAggregateFieldSchema(
1554
+ model,
1555
+ "_sum",
1556
+ shape._sum
1557
+ );
1558
+ }
1559
+ if (shape._min) {
1560
+ schemaFields["_min"] = buildAggregateFieldSchema(
1561
+ model,
1562
+ "_min",
1563
+ shape._min
1564
+ );
1565
+ }
1566
+ if (shape._max) {
1567
+ schemaFields["_max"] = buildAggregateFieldSchema(
1568
+ model,
1569
+ "_max",
1570
+ shape._max
1571
+ );
1572
+ }
1573
+ if (shape.by) {
1574
+ schemaFields["by"] = buildBySchema(model, shape.by);
1575
+ }
1576
+ if (shape.having) {
1577
+ schemaFields["having"] = buildHavingSchema(model, shape.having);
1578
+ }
1579
+ return {
1580
+ zodSchema: z4.object(schemaFields).strict(),
1581
+ forcedWhere,
1582
+ forcedIncludeTree,
1583
+ forcedSelectTree,
1584
+ forcedIncludeCountWhere,
1585
+ forcedSelectCountWhere
1586
+ };
1587
+ }
1588
+ function matchCaller(shapes, caller) {
1589
+ const matched = matchCallerPattern(Object.keys(shapes), caller);
1590
+ if (!matched)
1591
+ return null;
1592
+ return { key: matched, shape: shapes[matched] };
1593
+ }
1594
+ function buildQuerySchema(model, method, config) {
1595
+ const isSingleShape2 = typeof config === "function" || isShapeConfig(config);
1596
+ const builtCache = /* @__PURE__ */ new Map();
1597
+ if (isSingleShape2 && typeof config !== "function") {
1598
+ const built = buildShapeZodSchema(model, method, config);
1599
+ builtCache.set("_default", built);
1600
+ }
1601
+ if (!isSingleShape2) {
1602
+ for (const key of Object.keys(config)) {
1603
+ if (SHAPE_CONFIG_KEYS.has(key)) {
1604
+ throw new ShapeError(
1605
+ `Caller key "${key}" collides with reserved shape config key. Rename the caller path.`
1606
+ );
1607
+ }
1608
+ }
1609
+ for (const [key, shapeOrFn] of Object.entries(
1610
+ config
1611
+ )) {
1612
+ if (typeof shapeOrFn !== "function") {
1613
+ const built = buildShapeZodSchema(
1614
+ model,
1615
+ method,
1616
+ shapeOrFn
1617
+ );
1618
+ builtCache.set(key, built);
1619
+ }
1620
+ }
1621
+ }
1622
+ const isUnique = UNIQUE_WHERE_METHODS.has(method);
1623
+ return {
1624
+ schemas: Object.fromEntries(
1625
+ [...builtCache.entries()].map(([k, v]) => [k, v.zodSchema])
1626
+ ),
1627
+ parse(body, opts) {
1628
+ let built;
1629
+ if (isSingleShape2) {
1630
+ if (typeof config === "function") {
1631
+ requireContext(opts?.ctx, "shape function");
1632
+ const resolvedShape = config(opts.ctx);
1633
+ built = buildShapeZodSchema(model, method, resolvedShape);
1634
+ } else {
1635
+ built = builtCache.get("_default");
1636
+ }
1637
+ } else {
1638
+ if (!isPlainObject(body)) {
1639
+ throw new ShapeError("Request body must be an object");
1640
+ }
1641
+ const caller = body.caller;
1642
+ if (typeof caller !== "string") {
1643
+ throw new CallerError('Missing "caller" field in request body');
1644
+ }
1645
+ const matched = matchCaller(
1646
+ config,
1647
+ caller
1648
+ );
1649
+ if (!matched) {
1650
+ const allowed = Object.keys(
1651
+ config
1652
+ );
1653
+ throw new CallerError(
1654
+ `Unknown caller: "${caller}". Allowed: ${allowed.map((k) => `"${k}"`).join(", ")}`
1655
+ );
1656
+ }
1657
+ const shapeKey = matched.key;
1658
+ const shapeOrFn = matched.shape;
1659
+ if (typeof shapeOrFn === "function") {
1660
+ requireContext(opts?.ctx, "shape function");
1661
+ const resolvedShape = shapeOrFn(opts.ctx);
1662
+ built = buildShapeZodSchema(model, method, resolvedShape);
1663
+ } else {
1664
+ built = builtCache.get(shapeKey);
1665
+ }
1666
+ const { caller: _, ...rest } = body;
1667
+ body = rest;
1668
+ }
1669
+ return applyBuiltShape(built, body, isUnique);
1670
+ }
1671
+ };
1672
+ }
1673
+ return {
1674
+ buildQuerySchema,
1675
+ buildShapeZodSchema,
1676
+ buildWhereSchema,
1677
+ buildIncludeSchema,
1678
+ buildSelectSchema
1679
+ };
1680
+ }
1681
+
1682
+ // src/runtime/scope-extension.ts
1683
+ var READ_OPS = /* @__PURE__ */ new Set([
1684
+ "findMany",
1685
+ "findFirst",
1686
+ "findFirstOrThrow",
1687
+ "count"
1688
+ ]);
1689
+ var AGGREGATE_OPS = /* @__PURE__ */ new Set([
1690
+ "aggregate",
1691
+ "groupBy"
1692
+ ]);
1693
+ var FIND_UNIQUE_OPS = /* @__PURE__ */ new Set([
1694
+ "findUnique",
1695
+ "findUniqueOrThrow"
1696
+ ]);
1697
+ var CREATE_OPS = /* @__PURE__ */ new Set([
1698
+ "create",
1699
+ "createMany",
1700
+ "createManyAndReturn"
1701
+ ]);
1702
+ var UNIQUE_MUTATION_OPS = /* @__PURE__ */ new Set([
1703
+ "update",
1704
+ "delete"
1705
+ ]);
1706
+ var MULTI_MUTATION_OPS = /* @__PURE__ */ new Set([
1707
+ "updateMany",
1708
+ "updateManyAndReturn",
1709
+ "deleteMany"
1710
+ ]);
1711
+ function buildAndConditions(existingWhere, conditions) {
1712
+ if (existingWhere)
1713
+ return { AND: [existingWhere, ...conditions] };
1714
+ if (conditions.length === 1)
1715
+ return conditions[0];
1716
+ return { AND: conditions };
1717
+ }
1718
+ function buildScopedUniqueWhere(existingWhere, conditions) {
1719
+ if (!existingWhere) {
1720
+ return conditions.length === 1 ? conditions[0] : { AND: conditions };
1721
+ }
1722
+ const { AND: existingAnd, ...topLevel } = existingWhere;
1723
+ const allConditions = [];
1724
+ if (existingAnd !== void 0) {
1725
+ if (Array.isArray(existingAnd)) {
1726
+ allConditions.push(...existingAnd);
1727
+ } else {
1728
+ allConditions.push(existingAnd);
1729
+ }
1730
+ }
1731
+ allConditions.push(...conditions);
1732
+ return { ...topLevel, AND: allConditions };
1733
+ }
1734
+ function isComparableScopeValue(v) {
1735
+ const t = typeof v;
1736
+ return t === "string" || t === "number" || t === "bigint";
1737
+ }
1738
+ function looseEqual(a, b, log, fk) {
1739
+ if (a === b)
1740
+ return true;
1741
+ if (!isComparableScopeValue(a) || !isComparableScopeValue(b))
1742
+ return false;
1743
+ const eq = String(a) === String(b);
1744
+ if (eq && log && fk) {
1745
+ log.warn(
1746
+ `prisma-guard: Scope value for "${fk}" matched via type coercion (${typeof a} ${String(a)} vs ${typeof b} ${String(b)}). Consider normalizing types in the context function.`
1747
+ );
1748
+ }
1749
+ return eq;
1750
+ }
1751
+ function buildFkSelect(fks) {
1752
+ const select = {};
1753
+ for (const fk of fks)
1754
+ select[fk] = true;
1755
+ return select;
1756
+ }
1757
+ function pickMissingFksFromResult(result, fks) {
1758
+ const missing = [];
1759
+ for (const fk of fks) {
1760
+ if (!(fk in result))
1761
+ missing.push(fk);
1762
+ }
1763
+ return missing;
1764
+ }
1765
+ function validateScopeValue(root, value) {
1766
+ if (typeof value === "string" && value.length === 0) {
1767
+ throw new PolicyError(
1768
+ `Empty string scope value for root "${root}". This is almost certainly a bug in the context function.`
1769
+ );
1770
+ }
1771
+ if (typeof value === "number" && !Number.isFinite(value)) {
1772
+ throw new PolicyError(
1773
+ `Invalid numeric scope value for root "${root}": ${value}. This is almost certainly a bug in the context function.`
1774
+ );
1775
+ }
1776
+ }
1777
+ function enforceDataScope(data, scopes, overrides, log, model, operation, onScopeRelationWrite, mode) {
1778
+ for (const scope of scopes) {
1779
+ if (scope.fk in data) {
1780
+ log.warn(
1781
+ `prisma-guard: Scope FK "${scope.fk}" in ${operation} data for model "${model}" was overridden by scope context.`
1782
+ );
1783
+ }
1784
+ if (scope.relationName in data) {
1785
+ if (onScopeRelationWrite === "error") {
1786
+ throw new ShapeError(
1787
+ `Scope relation "${scope.relationName}" cannot be set directly in ${operation} data for model "${model}". The scope extension manages this relation automatically.`
1788
+ );
1789
+ }
1790
+ if (onScopeRelationWrite === "warn") {
1791
+ log.warn(
1792
+ `prisma-guard: Scope relation "${scope.relationName}" in ${operation} data for model "${model}" was removed by scope context.`
1793
+ );
1794
+ }
1795
+ delete data[scope.relationName];
1796
+ }
1797
+ }
1798
+ if (mode === "create") {
1799
+ Object.assign(data, overrides);
1800
+ } else {
1801
+ for (const scope of scopes) {
1802
+ delete data[scope.fk];
1803
+ }
1804
+ }
1805
+ }
1806
+ var VALID_FIND_UNIQUE_MODES = /* @__PURE__ */ new Set(["verify", "reject"]);
1807
+ var VALID_ON_SCOPE_RELATION_WRITES = /* @__PURE__ */ new Set(["error", "warn", "strip"]);
1808
+ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
1809
+ const log = logger ?? { warn: (msg) => console.warn(msg) };
1810
+ const findUniqueMode = guardConfig.findUniqueMode ?? "reject";
1811
+ const onScopeRelationWrite = guardConfig.onScopeRelationWrite ?? "error";
1812
+ if (!VALID_FIND_UNIQUE_MODES.has(findUniqueMode)) {
1813
+ throw new ShapeError(
1814
+ `prisma-guard: Invalid findUniqueMode "${findUniqueMode}". Allowed: ${[...VALID_FIND_UNIQUE_MODES].join(", ")}`
1815
+ );
1816
+ }
1817
+ if (!VALID_ON_SCOPE_RELATION_WRITES.has(onScopeRelationWrite)) {
1818
+ throw new ShapeError(
1819
+ `prisma-guard: Invalid onScopeRelationWrite "${onScopeRelationWrite}". Allowed: ${[...VALID_ON_SCOPE_RELATION_WRITES].join(", ")}`
1820
+ );
1821
+ }
1822
+ return {
1823
+ name: "prisma-guard-scope",
1824
+ query: {
1825
+ $allOperations({ model, operation, args, query }) {
1826
+ if (!model || !scopeMap[model])
1827
+ return query(args);
1828
+ const ctx = contextFn();
1829
+ const scopes = scopeMap[model];
1830
+ const presentScopes = scopes.filter((s) => ctx[s.root] != null);
1831
+ for (const s of presentScopes) {
1832
+ validateScopeValue(s.root, ctx[s.root]);
1833
+ }
1834
+ const presentConditions = presentScopes.map((s) => ({ [s.fk]: ctx[s.root] }));
1835
+ const missingRoots = scopes.filter((s) => ctx[s.root] == null).map((s) => s.root);
1836
+ const isMutation = CREATE_OPS.has(operation) || UNIQUE_MUTATION_OPS.has(operation) || MULTI_MUTATION_OPS.has(operation) || operation === "upsert";
1837
+ if (missingRoots.length > 0) {
1838
+ if (isMutation || guardConfig.onMissingScopeContext === "error") {
1839
+ throw new PolicyError(
1840
+ `Missing scope context for model "${model}": roots ${missingRoots.map((r) => `"${r}"`).join(", ")} not provided. All scope roots must be present.`
1841
+ );
1842
+ }
1843
+ if (guardConfig.onMissingScopeContext === "warn") {
1844
+ log.warn(
1845
+ `prisma-guard: Missing scope context for model "${model}": roots ${missingRoots.map((r) => `"${r}"`).join(", ")} not provided. Read proceeding with partial scope.`
1846
+ );
1847
+ }
1848
+ if (presentConditions.length === 0) {
1849
+ return query(args);
1850
+ }
1851
+ }
1852
+ const conditions = presentConditions;
1853
+ const overrides = Object.fromEntries(
1854
+ presentScopes.map((s) => [s.fk, ctx[s.root]])
1855
+ );
1856
+ if (operation === "upsert") {
1857
+ throw new PolicyError(
1858
+ `Scoped model "${model}" cannot use upsert via extension. Handle upsert explicitly in route logic.`
1859
+ );
1860
+ }
1861
+ if (FIND_UNIQUE_OPS.has(operation)) {
1862
+ if (findUniqueMode === "reject") {
1863
+ throw new PolicyError(
1864
+ `Scoped model "${model}" does not allow ${operation} via scope extension (findUniqueMode is "reject"). Use findFirst with explicit where conditions instead.`
1865
+ );
1866
+ }
1867
+ return handleFindUnique(args, query, conditions, scopes, operation, log);
1868
+ }
1869
+ const nextArgs = { ...args };
1870
+ if (READ_OPS.has(operation)) {
1871
+ nextArgs.where = buildAndConditions(args.where, conditions);
1872
+ return query(nextArgs);
1873
+ }
1874
+ if (AGGREGATE_OPS.has(operation)) {
1875
+ nextArgs.where = buildAndConditions(args.where, conditions);
1876
+ if (operation === "groupBy" && !nextArgs.by) {
1877
+ throw new ShapeError(
1878
+ `prisma-guard: groupBy on scoped model "${model}" requires "by" argument.`
1879
+ );
1880
+ }
1881
+ return query(nextArgs);
1882
+ }
1883
+ if (CREATE_OPS.has(operation)) {
1884
+ if (args.data === void 0 || args.data === null) {
1885
+ throw new ShapeError(`${operation} expects data`);
1886
+ }
1887
+ if (operation === "createMany" || operation === "createManyAndReturn") {
1888
+ if (!Array.isArray(args.data)) {
1889
+ throw new ShapeError(`${operation} expects data to be an array`);
1890
+ }
1891
+ if (args.data.length === 0) {
1892
+ throw new ShapeError(`${operation} received empty data array`);
1893
+ }
1894
+ nextArgs.data = args.data.map((d) => {
1895
+ const item = { ...d };
1896
+ enforceDataScope(item, scopes, overrides, log, model, operation, onScopeRelationWrite, "create");
1897
+ return item;
1898
+ });
1899
+ } else {
1900
+ if (typeof args.data !== "object" || Array.isArray(args.data)) {
1901
+ throw new ShapeError(`${operation} expects data to be an object`);
1902
+ }
1903
+ nextArgs.data = { ...args.data };
1904
+ enforceDataScope(nextArgs.data, scopes, overrides, log, model, operation, onScopeRelationWrite, "create");
1905
+ }
1906
+ return query(nextArgs);
1907
+ }
1908
+ if (UNIQUE_MUTATION_OPS.has(operation)) {
1909
+ nextArgs.where = buildScopedUniqueWhere(args.where, conditions);
1910
+ if (args.data !== void 0 && args.data !== null) {
1911
+ if (typeof args.data !== "object" || Array.isArray(args.data)) {
1912
+ throw new ShapeError(`${operation} expects data to be an object`);
1913
+ }
1914
+ nextArgs.data = { ...args.data };
1915
+ enforceDataScope(nextArgs.data, scopes, overrides, log, model, operation, onScopeRelationWrite, "mutate");
1916
+ }
1917
+ return query(nextArgs);
1918
+ }
1919
+ if (MULTI_MUTATION_OPS.has(operation)) {
1920
+ nextArgs.where = buildAndConditions(args.where, conditions);
1921
+ if (args.data !== void 0 && args.data !== null) {
1922
+ if (typeof args.data !== "object" || Array.isArray(args.data)) {
1923
+ throw new ShapeError(`${operation} expects data to be an object`);
1924
+ }
1925
+ nextArgs.data = { ...args.data };
1926
+ enforceDataScope(nextArgs.data, scopes, overrides, log, model, operation, onScopeRelationWrite, "mutate");
1927
+ }
1928
+ return query(nextArgs);
1929
+ }
1930
+ throw new ShapeError(
1931
+ `Unknown operation "${operation}" on scoped model "${model}". Update prisma-guard to handle this operation.`
1932
+ );
1933
+ }
1934
+ }
1935
+ };
1936
+ }
1937
+ async function handleFindUnique(args, query, conditions, scopes, operation, log) {
1938
+ const nextArgs = { ...args };
1939
+ const injectedFks = [];
1940
+ const originalSelect = args?.select;
1941
+ const fks = scopes.map((s) => s.fk);
1942
+ if (originalSelect) {
1943
+ nextArgs.select = { ...originalSelect };
1944
+ for (const fk of fks) {
1945
+ if (!originalSelect[fk]) {
1946
+ nextArgs.select[fk] = true;
1947
+ injectedFks.push(fk);
1948
+ }
1949
+ }
1950
+ }
1951
+ const result = await query(nextArgs);
1952
+ if (result === null)
1953
+ return result;
1954
+ if (typeof result !== "object" || result === null) {
1955
+ throw new ShapeError("findUnique result must be an object or null");
1956
+ }
1957
+ const resultObj = result;
1958
+ let verifyObj = resultObj;
1959
+ const missingFks = pickMissingFksFromResult(resultObj, fks);
1960
+ if (missingFks.length > 0) {
1961
+ const where = args?.where;
1962
+ if (!where || typeof where !== "object" || Array.isArray(where)) {
1963
+ throw new PolicyError(
1964
+ `prisma-guard: Cannot verify scope \u2014 missing FK fields (${missingFks.join(", ")}) and findUnique args.where is not a valid object.`
1965
+ );
1966
+ }
1967
+ let verifyResult;
1968
+ try {
1969
+ verifyResult = await query({ where, select: buildFkSelect(fks) });
1970
+ } catch (err) {
1971
+ throw new PolicyError(
1972
+ `prisma-guard: Scope verification query failed for findUnique: ${err?.message ?? String(err)}`
1973
+ );
1974
+ }
1975
+ if (verifyResult === null) {
1976
+ throw new PolicyError("prisma-guard: Scope verification query returned null for an existing findUnique result");
1977
+ }
1978
+ if (typeof verifyResult !== "object" || verifyResult === null) {
1979
+ throw new PolicyError("prisma-guard: Scope verification result must be an object");
1980
+ }
1981
+ verifyObj = verifyResult;
1982
+ }
1983
+ for (const condition of conditions) {
1984
+ const [fk, value] = Object.entries(condition)[0];
1985
+ if (!(fk in verifyObj)) {
1986
+ throw new PolicyError(
1987
+ `prisma-guard: Cannot verify scope on "${fk}" \u2014 field not present in verification result. Ensure FK fields are selectable.`
1988
+ );
1989
+ }
1990
+ if (!looseEqual(verifyObj[fk], value, log, fk)) {
1991
+ if (operation === "findUniqueOrThrow") {
1992
+ throw new PolicyError("Record not accessible in current scope");
1993
+ }
1994
+ return null;
1995
+ }
1996
+ }
1997
+ if (injectedFks.length > 0) {
1998
+ const cleaned = { ...resultObj };
1999
+ for (const fk of injectedFks) {
2000
+ delete cleaned[fk];
2001
+ }
2002
+ return cleaned;
2003
+ }
2004
+ return result;
2005
+ }
2006
+
2007
+ // src/runtime/model-guard.ts
2008
+ import { z as z5 } from "zod";
2009
+ var ALLOWED_BODY_KEYS_CREATE = /* @__PURE__ */ new Set(["data"]);
2010
+ var ALLOWED_BODY_KEYS_CREATE_PROJECTION = /* @__PURE__ */ new Set(["data", "select", "include"]);
2011
+ var ALLOWED_BODY_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
2012
+ var ALLOWED_BODY_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set(["data", "where", "select", "include"]);
2013
+ var ALLOWED_BODY_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
2014
+ var ALLOWED_BODY_KEYS_DELETE_PROJECTION = /* @__PURE__ */ new Set(["where", "select", "include"]);
2015
+ var VALID_SHAPE_KEYS_CREATE = /* @__PURE__ */ new Set(["data"]);
2016
+ var VALID_SHAPE_KEYS_CREATE_PROJECTION = /* @__PURE__ */ new Set(["data", "select", "include"]);
2017
+ var VALID_SHAPE_KEYS_UPDATE = /* @__PURE__ */ new Set(["data", "where"]);
2018
+ var VALID_SHAPE_KEYS_UPDATE_PROJECTION = /* @__PURE__ */ new Set(["data", "where", "select", "include"]);
2019
+ var VALID_SHAPE_KEYS_DELETE = /* @__PURE__ */ new Set(["where"]);
2020
+ var VALID_SHAPE_KEYS_DELETE_PROJECTION = /* @__PURE__ */ new Set(["where", "select", "include"]);
2021
+ var UNIQUE_MUTATION_METHODS = /* @__PURE__ */ new Set(["update", "delete"]);
2022
+ var UNIQUE_READ_METHODS = /* @__PURE__ */ new Set(["findUnique", "findUniqueOrThrow"]);
2023
+ var BULK_MUTATION_METHODS = /* @__PURE__ */ new Set([
2024
+ "updateMany",
2025
+ "updateManyAndReturn",
2026
+ "deleteMany"
2027
+ ]);
2028
+ var PROJECTION_MUTATION_METHODS = /* @__PURE__ */ new Set([
2029
+ "create",
2030
+ "update",
2031
+ "delete",
2032
+ "createManyAndReturn",
2033
+ "updateManyAndReturn"
2034
+ ]);
2035
+ function isGuardShape(obj) {
2036
+ if (!isPlainObject(obj))
2037
+ return false;
2038
+ const keys = Object.keys(obj);
2039
+ return keys.length === 0 || keys.every((k) => GUARD_SHAPE_KEYS.has(k));
2040
+ }
2041
+ function isSingleShape(input) {
2042
+ return typeof input === "function" || isGuardShape(input);
2043
+ }
2044
+ function validateMutationBodyKeys(body, allowed, method) {
2045
+ for (const key of Object.keys(body)) {
2046
+ if (!allowed.has(key)) {
2047
+ throw new ShapeError(
2048
+ `Unexpected key "${key}" in ${method} body. Allowed keys: ${[...allowed].join(", ")}`
2049
+ );
2050
+ }
2051
+ }
2052
+ }
2053
+ function validateMutationShapeKeys(shape, allowed, method) {
2054
+ for (const key of Object.keys(shape)) {
2055
+ if (!allowed.has(key)) {
2056
+ throw new ShapeError(
2057
+ `Shape key "${key}" not valid for ${method}. Allowed: ${[...allowed].join(", ")}`
2058
+ );
2059
+ }
2060
+ }
2061
+ }
2062
+ function formatZodError(err) {
2063
+ return err.issues.map((i) => {
2064
+ const p = i.path.length > 0 ? `${i.path.join(".")}: ` : "";
2065
+ return `${p}${i.message}`;
2066
+ }).join("; ");
2067
+ }
2068
+ function createModelGuardExtension(config) {
2069
+ const { typeMap, enumMap, zodChains, uniqueMap, scopeMap, contextFn } = config;
2070
+ const wrapZodErrors = config.wrapZodErrors ?? false;
2071
+ const schemaBuilder = createSchemaBuilder(typeMap, zodChains, enumMap);
2072
+ const queryBuilder = createQueryBuilder(typeMap, enumMap, uniqueMap);
2073
+ const modelScopeFks = /* @__PURE__ */ new Map();
2074
+ for (const [model, entries] of Object.entries(scopeMap)) {
2075
+ const fks = /* @__PURE__ */ new Set();
2076
+ for (const entry of entries) {
2077
+ fks.add(entry.fk);
2078
+ }
2079
+ modelScopeFks.set(model, fks);
2080
+ }
2081
+ function validateCreateCompleteness(modelName, dataConfig) {
2082
+ const modelFields = typeMap[modelName];
2083
+ if (!modelFields)
2084
+ return;
2085
+ const fks = modelScopeFks.get(modelName) ?? /* @__PURE__ */ new Set();
2086
+ for (const [fieldName, meta] of Object.entries(modelFields)) {
2087
+ if (meta.isRelation)
2088
+ continue;
2089
+ if (meta.isUpdatedAt)
2090
+ continue;
2091
+ if (meta.hasDefault)
2092
+ continue;
2093
+ if (!meta.isRequired)
2094
+ continue;
2095
+ if (fieldName in dataConfig)
2096
+ continue;
2097
+ if (fks.has(fieldName))
2098
+ continue;
2099
+ throw new ShapeError(
2100
+ `Required field "${fieldName}" on model "${modelName}" is missing from create data shape, has no default, and is not a scope FK`
2101
+ );
2102
+ }
2103
+ }
2104
+ function buildDataSchema(model, dataConfig, mode) {
2105
+ const modelFields = typeMap[model];
2106
+ if (!modelFields)
2107
+ throw new ShapeError(`Unknown model: ${model}`);
2108
+ const schemaMap = {};
2109
+ const forced = {};
2110
+ for (const [fieldName, value] of Object.entries(dataConfig)) {
2111
+ const fieldMeta = modelFields[fieldName];
2112
+ if (!fieldMeta)
2113
+ throw new ShapeError(`Unknown field "${fieldName}" on model "${model}"`);
2114
+ if (fieldMeta.isRelation)
2115
+ throw new ShapeError(`Relation field "${fieldName}" cannot be used in data shape`);
2116
+ if (fieldMeta.isUpdatedAt)
2117
+ throw new ShapeError(`updatedAt field "${fieldName}" cannot be used in data shape`);
2118
+ if (typeof value === "function") {
2119
+ let baseSchema = schemaBuilder.buildBaseFieldSchema(model, fieldName);
2120
+ let fieldSchema;
2121
+ try {
2122
+ fieldSchema = value(baseSchema);
2123
+ } catch (err) {
2124
+ throw new ShapeError(
2125
+ `Invalid inline refine for "${model}.${fieldName}": ${err.message}`,
2126
+ { cause: err }
2127
+ );
2128
+ }
2129
+ if (mode === "create") {
2130
+ if (!fieldMeta.isRequired || fieldMeta.hasDefault) {
2131
+ fieldSchema = fieldSchema.optional();
2132
+ }
2133
+ } else {
2134
+ if (!fieldMeta.isRequired) {
2135
+ fieldSchema = fieldSchema.nullable().optional();
2136
+ } else {
2137
+ fieldSchema = fieldSchema.optional();
2138
+ }
2139
+ }
2140
+ schemaMap[fieldName] = fieldSchema;
2141
+ } else if (value === true) {
2142
+ let fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
2143
+ if (mode === "create") {
2144
+ if (!fieldMeta.isRequired || fieldMeta.hasDefault) {
2145
+ fieldSchema = fieldSchema.optional();
2146
+ }
2147
+ } else {
2148
+ if (!fieldMeta.isRequired) {
2149
+ fieldSchema = fieldSchema.nullable().optional();
2150
+ } else {
2151
+ fieldSchema = fieldSchema.optional();
2152
+ }
2153
+ }
2154
+ schemaMap[fieldName] = fieldSchema;
2155
+ } else {
2156
+ let fieldSchema = schemaBuilder.buildFieldSchema(model, fieldName);
2157
+ if (!fieldMeta.isRequired) {
2158
+ fieldSchema = fieldSchema.nullable();
2159
+ }
2160
+ let parsed;
2161
+ try {
2162
+ parsed = fieldSchema.parse(value);
2163
+ } catch (err) {
2164
+ throw new ShapeError(
2165
+ `Invalid forced data value for "${model}.${fieldName}": ${err.message}`
2166
+ );
2167
+ }
2168
+ forced[fieldName] = parsed;
2169
+ }
2170
+ }
2171
+ return {
2172
+ schema: z5.object(schemaMap).strict(),
2173
+ forced
2174
+ };
2175
+ }
2176
+ function resolveShape(input, body) {
2177
+ if (isSingleShape(input)) {
2178
+ const wasDynamic2 = typeof input === "function";
2179
+ const shape2 = wasDynamic2 ? input(contextFn()) : input;
2180
+ const parsed2 = body === void 0 || body === null ? {} : requireBody(body);
2181
+ if ("caller" in parsed2) {
2182
+ throw new CallerError(
2183
+ 'Named shape routing is not configured on this guard. Remove "caller" from the request body or use a named shape map.'
2184
+ );
2185
+ }
2186
+ return { shape: shape2, body: parsed2, matchedKey: "_default", wasDynamic: wasDynamic2 };
2187
+ }
2188
+ const namedMap = input;
2189
+ for (const key of Object.keys(namedMap)) {
2190
+ if (GUARD_SHAPE_KEYS.has(key)) {
2191
+ throw new ShapeError(
2192
+ `Caller key "${key}" collides with reserved shape config key. Rename the caller path.`
2193
+ );
2194
+ }
2195
+ const val = namedMap[key];
2196
+ if (typeof val !== "function" && !isGuardShape(val)) {
2197
+ throw new ShapeError(
2198
+ `Named shape value for "${key}" must be a guard shape object or function`
2199
+ );
2200
+ }
2201
+ }
2202
+ const parsed = requireBody(body);
2203
+ const caller = parsed.caller;
2204
+ if (typeof caller !== "string") {
2205
+ throw new CallerError('Missing "caller" field in request body');
2206
+ }
2207
+ const patterns = Object.keys(namedMap);
2208
+ const matched = matchCallerPattern(patterns, caller);
2209
+ if (!matched) {
2210
+ throw new CallerError(
2211
+ `Unknown caller: "${caller}". Allowed: ${patterns.map((k) => `"${k}"`).join(", ")}`
2212
+ );
2213
+ }
2214
+ const shapeOrFn = namedMap[matched];
2215
+ const wasDynamic = typeof shapeOrFn === "function";
2216
+ const shape = wasDynamic ? shapeOrFn(contextFn()) : shapeOrFn;
2217
+ const { caller: _, ...rest } = parsed;
2218
+ return { shape, body: rest, matchedKey: matched, wasDynamic };
2219
+ }
2220
+ function requireBody(body) {
2221
+ if (!isPlainObject(body))
2222
+ throw new ShapeError("Request body must be an object");
2223
+ return body;
2224
+ }
2225
+ function validateAndMergeData(bodyData, cached, method) {
2226
+ if (bodyData === void 0 || bodyData === null) {
2227
+ throw new ShapeError(`${method} requires "data" in request body`);
2228
+ }
2229
+ const validated = cached.schema.parse(bodyData);
2230
+ return { ...validated, ...cached.forced };
2231
+ }
2232
+ function maybeValidateUniqueWhere(modelName, shape, method) {
2233
+ if (!UNIQUE_MUTATION_METHODS.has(method))
2234
+ return;
2235
+ if (!shape.where)
2236
+ return;
2237
+ validateUniqueEquality(modelName, shape.where, method, uniqueMap);
2238
+ }
2239
+ function hasDataRefines(dataConfig) {
2240
+ for (const value of Object.values(dataConfig)) {
2241
+ if (typeof value === "function")
2242
+ return true;
2243
+ }
2244
+ return false;
2245
+ }
2246
+ function createGuardedMethods(modelName, modelDelegate, input) {
2247
+ function callDelegate(method, args) {
2248
+ if (typeof modelDelegate[method] !== "function") {
2249
+ throw new ShapeError(`Method "${method}" is not available on this model`);
2250
+ }
2251
+ return modelDelegate[method](args);
2252
+ }
2253
+ const readShapeCache = /* @__PURE__ */ new Map();
2254
+ const dataSchemaCache = /* @__PURE__ */ new Map();
2255
+ const whereBuiltCache = /* @__PURE__ */ new Map();
2256
+ const projectionCache = /* @__PURE__ */ new Map();
2257
+ function getReadShape(method, queryShape, matchedKey, wasDynamic) {
2258
+ if (!wasDynamic) {
2259
+ const cacheKey = `${method}\0${matchedKey}`;
2260
+ const cached = readShapeCache.get(cacheKey);
2261
+ if (cached)
2262
+ return cached;
2263
+ const built = queryBuilder.buildShapeZodSchema(modelName, method, queryShape);
2264
+ readShapeCache.set(cacheKey, built);
2265
+ return built;
2266
+ }
2267
+ return queryBuilder.buildShapeZodSchema(modelName, method, queryShape);
2268
+ }
2269
+ function getDataSchema(mode, dataConfig, matchedKey, wasDynamic) {
2270
+ if (!wasDynamic && !hasDataRefines(dataConfig)) {
2271
+ const cacheKey = `${mode}\0${matchedKey}`;
2272
+ const cached = dataSchemaCache.get(cacheKey);
2273
+ if (cached)
2274
+ return cached;
2275
+ const built = buildDataSchema(modelName, dataConfig, mode);
2276
+ dataSchemaCache.set(cacheKey, built);
2277
+ return built;
2278
+ }
2279
+ return buildDataSchema(modelName, dataConfig, mode);
2280
+ }
2281
+ function getWhereBuilt(whereConfig, matchedKey, wasDynamic) {
2282
+ if (!wasDynamic) {
2283
+ const cached = whereBuiltCache.get(matchedKey);
2284
+ if (cached)
2285
+ return cached;
2286
+ const built = queryBuilder.buildWhereSchema(modelName, whereConfig);
2287
+ whereBuiltCache.set(matchedKey, built);
2288
+ return built;
2289
+ }
2290
+ return queryBuilder.buildWhereSchema(modelName, whereConfig);
2291
+ }
2292
+ function buildProjectionSchema(shape) {
2293
+ if (shape.select && shape.include) {
2294
+ throw new ShapeError('Shape cannot define both "select" and "include"');
2295
+ }
2296
+ const schemaFields = {};
2297
+ let forcedIncludeTree = {};
2298
+ let forcedSelectTree = {};
2299
+ let forcedIncludeCountWhere = {};
2300
+ let forcedSelectCountWhere = {};
2301
+ if (shape.include) {
2302
+ const result = queryBuilder.buildIncludeSchema(
2303
+ modelName,
2304
+ shape.include
2305
+ );
2306
+ schemaFields["include"] = result.schema;
2307
+ forcedIncludeTree = result.forcedTree;
2308
+ forcedIncludeCountWhere = result.forcedCountWhere;
2309
+ }
2310
+ if (shape.select) {
2311
+ const result = queryBuilder.buildSelectSchema(
2312
+ modelName,
2313
+ shape.select
2314
+ );
2315
+ schemaFields["select"] = result.schema;
2316
+ forcedSelectTree = result.forcedTree;
2317
+ forcedSelectCountWhere = result.forcedCountWhere;
2318
+ }
2319
+ return {
2320
+ zodSchema: z5.object(schemaFields).strict(),
2321
+ forcedIncludeTree,
2322
+ forcedSelectTree,
2323
+ forcedIncludeCountWhere,
2324
+ forcedSelectCountWhere
2325
+ };
2326
+ }
2327
+ function getProjection(shape, matchedKey, wasDynamic) {
2328
+ if (!wasDynamic) {
2329
+ const cacheKey = `projection\0${matchedKey}`;
2330
+ const cached = projectionCache.get(cacheKey);
2331
+ if (cached)
2332
+ return cached;
2333
+ const built = buildProjectionSchema(shape);
2334
+ projectionCache.set(cacheKey, built);
2335
+ return built;
2336
+ }
2337
+ return buildProjectionSchema(shape);
2338
+ }
2339
+ function resolveProjection(shape, parsed, method, matchedKey, wasDynamic) {
2340
+ const hasBodyProjection = "select" in parsed || "include" in parsed;
2341
+ const hasShapeProjection = !!shape.select || !!shape.include;
2342
+ if (hasBodyProjection && !hasShapeProjection) {
2343
+ throw new ShapeError(
2344
+ `Guard shape does not define "select" or "include" for ${method} return projection`
2345
+ );
2346
+ }
2347
+ if (!hasShapeProjection)
2348
+ return {};
2349
+ const projection = getProjection(shape, matchedKey, wasDynamic);
2350
+ const projectionBody = {};
2351
+ if ("select" in parsed)
2352
+ projectionBody.select = parsed.select;
2353
+ if ("include" in parsed)
2354
+ projectionBody.include = parsed.include;
2355
+ const validated = projection.zodSchema.parse(projectionBody);
2356
+ if (Object.keys(projection.forcedIncludeTree).length > 0) {
2357
+ applyForcedTree(validated, "include", projection.forcedIncludeTree);
2358
+ }
2359
+ if (Object.keys(projection.forcedSelectTree).length > 0) {
2360
+ applyForcedTree(validated, "select", projection.forcedSelectTree);
2361
+ }
2362
+ if (Object.keys(projection.forcedIncludeCountWhere).length > 0) {
2363
+ const ic = validated.include;
2364
+ if (ic)
2365
+ applyForcedCountWhere(ic, projection.forcedIncludeCountWhere);
2366
+ }
2367
+ if (Object.keys(projection.forcedSelectCountWhere).length > 0) {
2368
+ const sc = validated.select;
2369
+ if (sc)
2370
+ applyForcedCountWhere(sc, projection.forcedSelectCountWhere);
2371
+ }
2372
+ return validated;
2373
+ }
2374
+ function buildWhereFromShape(shape, bodyWhere, preserveUnique, matchedKey, wasDynamic) {
2375
+ if (!shape.where) {
2376
+ if (bodyWhere !== void 0) {
2377
+ throw new ShapeError('Guard shape does not allow "where"');
2378
+ }
2379
+ return {};
2380
+ }
2381
+ const built = getWhereBuilt(shape.where, matchedKey, wasDynamic);
2382
+ let validatedWhere;
2383
+ if (built.schema) {
2384
+ validatedWhere = built.schema.parse(bodyWhere);
2385
+ }
2386
+ if (Object.keys(built.forced).length > 0) {
2387
+ return preserveUnique ? mergeUniqueForced(validatedWhere, built.forced) : mergeForced(validatedWhere, built.forced);
2388
+ }
2389
+ return validatedWhere ?? {};
2390
+ }
2391
+ function requireWhere(shape, bodyWhere, method, preserveUnique, matchedKey, wasDynamic) {
2392
+ const where = buildWhereFromShape(shape, bodyWhere, preserveUnique, matchedKey, wasDynamic);
2393
+ if (Object.keys(where).length === 0) {
2394
+ throw new ShapeError(`${method} requires a where condition`);
2395
+ }
2396
+ return where;
2397
+ }
2398
+ function makeReadMethod(method) {
2399
+ return (body) => {
2400
+ const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2401
+ if (shape.data) {
2402
+ throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
2403
+ }
2404
+ const { data: _, ...queryShape } = shape;
2405
+ const built = getReadShape(method, queryShape, matchedKey, wasDynamic);
2406
+ const isUnique = UNIQUE_READ_METHODS.has(method);
2407
+ const args = applyBuiltShape(built, parsed, isUnique);
2408
+ if (isUnique && args.where) {
2409
+ validateResolvedUniqueWhere(
2410
+ modelName,
2411
+ args.where,
2412
+ method,
2413
+ uniqueMap
2414
+ );
2415
+ }
2416
+ return callDelegate(method, args);
2417
+ };
2418
+ }
2419
+ function makeCreateMethod(method) {
2420
+ const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
2421
+ const allowedBodyKeys = supportsProjection ? ALLOWED_BODY_KEYS_CREATE_PROJECTION : ALLOWED_BODY_KEYS_CREATE;
2422
+ const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_CREATE_PROJECTION : VALID_SHAPE_KEYS_CREATE;
2423
+ return (body) => {
2424
+ const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2425
+ if (!shape.data)
2426
+ throw new ShapeError(`Guard shape requires "data" for ${method}`);
2427
+ validateMutationShapeKeys(shape, allowedShapeKeys, method);
2428
+ validateMutationBodyKeys(parsed, allowedBodyKeys, method);
2429
+ validateCreateCompleteness(modelName, shape.data);
2430
+ const dataSchema = getDataSchema("create", shape.data, matchedKey, wasDynamic);
2431
+ let args;
2432
+ if (method === "create") {
2433
+ const data = validateAndMergeData(parsed.data, dataSchema, method);
2434
+ args = { data };
2435
+ } else {
2436
+ if (!Array.isArray(parsed.data))
2437
+ throw new ShapeError(`${method} expects data to be an array`);
2438
+ if (parsed.data.length === 0)
2439
+ throw new ShapeError(`${method} received empty data array`);
2440
+ const data = parsed.data.map(
2441
+ (item) => validateAndMergeData(item, dataSchema, method)
2442
+ );
2443
+ args = { data };
2444
+ }
2445
+ if (supportsProjection) {
2446
+ const projectionArgs = resolveProjection(shape, parsed, method, matchedKey, wasDynamic);
2447
+ Object.assign(args, projectionArgs);
2448
+ }
2449
+ return callDelegate(method, args);
2450
+ };
2451
+ }
2452
+ function makeUpdateMethod(method) {
2453
+ const isUniqueWhere = method === "update";
2454
+ const isBulk = BULK_MUTATION_METHODS.has(method);
2455
+ const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
2456
+ const allowedBodyKeys = supportsProjection ? ALLOWED_BODY_KEYS_UPDATE_PROJECTION : ALLOWED_BODY_KEYS_UPDATE;
2457
+ const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_UPDATE_PROJECTION : VALID_SHAPE_KEYS_UPDATE;
2458
+ return (body) => {
2459
+ const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2460
+ if (!shape.data)
2461
+ throw new ShapeError(`Guard shape requires "data" for ${method}`);
2462
+ validateMutationShapeKeys(shape, allowedShapeKeys, method);
2463
+ validateMutationBodyKeys(parsed, allowedBodyKeys, method);
2464
+ if (isBulk && !shape.where) {
2465
+ throw new ShapeError(`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`);
2466
+ }
2467
+ maybeValidateUniqueWhere(modelName, shape, method);
2468
+ const dataSchema = getDataSchema("update", shape.data, matchedKey, wasDynamic);
2469
+ const data = validateAndMergeData(parsed.data, dataSchema, method);
2470
+ const where = isUniqueWhere ? requireWhere(shape, parsed.where, method, true, matchedKey, wasDynamic) : buildWhereFromShape(shape, parsed.where, false, matchedKey, wasDynamic);
2471
+ if (isBulk && Object.keys(where).length === 0) {
2472
+ throw new ShapeError(`${method} requires at least one where condition`);
2473
+ }
2474
+ if (isUniqueWhere) {
2475
+ validateResolvedUniqueWhere(modelName, where, method, uniqueMap);
2476
+ }
2477
+ const args = { data, where };
2478
+ if (supportsProjection) {
2479
+ const projectionArgs = resolveProjection(shape, parsed, method, matchedKey, wasDynamic);
2480
+ Object.assign(args, projectionArgs);
2481
+ }
2482
+ return callDelegate(method, args);
2483
+ };
2484
+ }
2485
+ function makeDeleteMethod(method) {
2486
+ const isUniqueWhere = method === "delete";
2487
+ const isBulk = BULK_MUTATION_METHODS.has(method);
2488
+ const supportsProjection = PROJECTION_MUTATION_METHODS.has(method);
2489
+ const allowedBodyKeys = supportsProjection ? ALLOWED_BODY_KEYS_DELETE_PROJECTION : ALLOWED_BODY_KEYS_DELETE;
2490
+ const allowedShapeKeys = supportsProjection ? VALID_SHAPE_KEYS_DELETE_PROJECTION : VALID_SHAPE_KEYS_DELETE;
2491
+ return (body) => {
2492
+ const { shape, body: parsed, matchedKey, wasDynamic } = resolveShape(input, body);
2493
+ if (shape.data)
2494
+ throw new ShapeError(`Guard shape "data" is not valid for ${method}`);
2495
+ validateMutationShapeKeys(shape, allowedShapeKeys, method);
2496
+ validateMutationBodyKeys(parsed, allowedBodyKeys, method);
2497
+ if (isBulk && !shape.where) {
2498
+ throw new ShapeError(`Guard shape requires "where" for ${method} to prevent unconstrained bulk mutations`);
2499
+ }
2500
+ maybeValidateUniqueWhere(modelName, shape, method);
2501
+ const where = isUniqueWhere ? requireWhere(shape, parsed.where, method, true, matchedKey, wasDynamic) : buildWhereFromShape(shape, parsed.where, false, matchedKey, wasDynamic);
2502
+ if (isBulk && Object.keys(where).length === 0) {
2503
+ throw new ShapeError(`${method} requires at least one where condition`);
2504
+ }
2505
+ if (isUniqueWhere) {
2506
+ validateResolvedUniqueWhere(modelName, where, method, uniqueMap);
2507
+ }
2508
+ const args = { where };
2509
+ if (supportsProjection) {
2510
+ const projectionArgs = resolveProjection(shape, parsed, method, matchedKey, wasDynamic);
2511
+ Object.assign(args, projectionArgs);
2512
+ }
2513
+ return callDelegate(method, args);
2514
+ };
2515
+ }
2516
+ return {
2517
+ findMany: makeReadMethod("findMany"),
2518
+ findFirst: makeReadMethod("findFirst"),
2519
+ findFirstOrThrow: makeReadMethod("findFirstOrThrow"),
2520
+ findUnique: makeReadMethod("findUnique"),
2521
+ findUniqueOrThrow: makeReadMethod("findUniqueOrThrow"),
2522
+ count: makeReadMethod("count"),
2523
+ aggregate: makeReadMethod("aggregate"),
2524
+ groupBy: makeReadMethod("groupBy"),
2525
+ create: makeCreateMethod("create"),
2526
+ createMany: makeCreateMethod("createMany"),
2527
+ createManyAndReturn: makeCreateMethod("createManyAndReturn"),
2528
+ update: makeUpdateMethod("update"),
2529
+ updateMany: makeUpdateMethod("updateMany"),
2530
+ updateManyAndReturn: makeUpdateMethod("updateManyAndReturn"),
2531
+ delete: makeDeleteMethod("delete"),
2532
+ deleteMany: makeDeleteMethod("deleteMany")
2533
+ };
2534
+ }
2535
+ function wrapMethods(methods) {
2536
+ const wrapped = {};
2537
+ for (const [key, fn] of Object.entries(methods)) {
2538
+ wrapped[key] = (body) => {
2539
+ try {
2540
+ return fn(body);
2541
+ } catch (err) {
2542
+ if (err instanceof z5.ZodError) {
2543
+ throw new ShapeError(
2544
+ `Validation failed: ${formatZodError(err)}`,
2545
+ { cause: err }
2546
+ );
2547
+ }
2548
+ throw err;
2549
+ }
2550
+ };
2551
+ }
2552
+ return wrapped;
2553
+ }
2554
+ return {
2555
+ $allModels: {
2556
+ guard(input) {
2557
+ const modelName = this.$name;
2558
+ const delegateKey = modelName[0].toLowerCase() + modelName.slice(1);
2559
+ const modelDelegate = this.$parent[delegateKey];
2560
+ if (!modelDelegate) {
2561
+ throw new ShapeError(
2562
+ `Could not resolve Prisma delegate for model "${modelName}" (key: "${delegateKey}")`
2563
+ );
2564
+ }
2565
+ const methods = createGuardedMethods(modelName, modelDelegate, input);
2566
+ if (!wrapZodErrors)
2567
+ return methods;
2568
+ return wrapMethods(methods);
2569
+ }
2570
+ }
2571
+ };
2572
+ }
2573
+
2574
+ // src/runtime/guard.ts
2575
+ function formatZodError2(err) {
2576
+ return err.issues.map((i) => {
2577
+ const p = i.path.length > 0 ? `${i.path.join(".")}: ` : "";
2578
+ return `${p}${i.message}`;
2579
+ }).join("; ");
2580
+ }
2581
+ function createGuard(config) {
2582
+ const schemaBuilder = createSchemaBuilder(
2583
+ config.typeMap,
2584
+ config.zodChains,
2585
+ config.enumMap
2586
+ );
2587
+ const queryBuilder = createQueryBuilder(
2588
+ config.typeMap,
2589
+ config.enumMap,
2590
+ config.uniqueMap ?? {}
2591
+ );
2592
+ const log = config.logger ?? { warn: (msg) => console.warn(msg) };
2593
+ const wrapZodErrors = config.wrapZodErrors ?? false;
2594
+ function rethrowZod(err) {
2595
+ if (err instanceof ZodError) {
2596
+ throw new ShapeError(`Validation failed: ${formatZodError2(err)}`, { cause: err });
2597
+ }
2598
+ throw err;
2599
+ }
2600
+ return {
2601
+ input: (model, opts) => {
2602
+ const result = schemaBuilder.buildInputSchema(model, opts);
2603
+ if (!wrapZodErrors)
2604
+ return result;
2605
+ return {
2606
+ schema: result.schema,
2607
+ parse(data) {
2608
+ try {
2609
+ return result.parse(data);
2610
+ } catch (err) {
2611
+ rethrowZod(err);
2612
+ }
2613
+ }
2614
+ };
2615
+ },
2616
+ model: (model, opts) => schemaBuilder.buildModelSchema(model, opts),
2617
+ query: (model, method, config_) => {
2618
+ const qs = queryBuilder.buildQuerySchema(model, method, config_);
2619
+ if (!wrapZodErrors)
2620
+ return qs;
2621
+ return {
2622
+ schemas: qs.schemas,
2623
+ parse(body, opts) {
2624
+ try {
2625
+ return qs.parse(body, opts);
2626
+ } catch (err) {
2627
+ rethrowZod(err);
2628
+ }
2629
+ }
2630
+ };
2631
+ },
2632
+ extension: (contextFn) => {
2633
+ const scopeCtxFn = () => {
2634
+ const ctx = contextFn();
2635
+ const scopeCtx = {};
2636
+ for (const key of Object.keys(ctx)) {
2637
+ const val = ctx[key];
2638
+ if (typeof val === "string" || typeof val === "number" || typeof val === "bigint") {
2639
+ scopeCtx[key] = val;
2640
+ } else if (val !== null && val !== void 0) {
2641
+ log.warn(
2642
+ `prisma-guard: Context key "${key}" has non-primitive value (${typeof val}). Only string, number, and bigint values are used for scope context.`
2643
+ );
2644
+ }
2645
+ }
2646
+ return scopeCtx;
2647
+ };
2648
+ const scopeExt = createScopeExtension(
2649
+ config.scopeMap,
2650
+ scopeCtxFn,
2651
+ config.guardConfig,
2652
+ config.logger
2653
+ );
2654
+ const modelGuardExt = createModelGuardExtension({
2655
+ typeMap: config.typeMap,
2656
+ enumMap: config.enumMap,
2657
+ zodChains: config.zodChains,
2658
+ uniqueMap: config.uniqueMap ?? {},
2659
+ scopeMap: config.scopeMap,
2660
+ contextFn,
2661
+ wrapZodErrors
2662
+ });
2663
+ return {
2664
+ name: "prisma-guard",
2665
+ model: modelGuardExt,
2666
+ query: scopeExt.query
2667
+ };
2668
+ }
2669
+ };
2670
+ }
2671
+ export {
2672
+ CallerError,
2673
+ PolicyError,
2674
+ ShapeError,
2675
+ createGuard
2676
+ };
2677
+ //# sourceMappingURL=index.js.map