prisma-guard 1.21.0 → 1.22.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.
- package/dist/generator/index.js +113 -10
- package/dist/generator/index.js.map +1 -1
- package/dist/runtime/index.cjs +106 -79
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +138 -4
- package/dist/runtime/index.d.ts +138 -4
- package/dist/runtime/index.js +105 -79
- package/dist/runtime/index.js.map +1 -1
- package/package.json +1 -1
package/dist/runtime/index.cjs
CHANGED
|
@@ -25,6 +25,7 @@ __export(runtime_exports, {
|
|
|
25
25
|
ShapeError: () => ShapeError,
|
|
26
26
|
createGuard: () => createGuard,
|
|
27
27
|
force: () => force,
|
|
28
|
+
namedShapes: () => namedShapes,
|
|
28
29
|
unsupported: () => unsupported
|
|
29
30
|
});
|
|
30
31
|
module.exports = __toCommonJS(runtime_exports);
|
|
@@ -222,7 +223,13 @@ function createScalarBase(strictDecimal) {
|
|
|
222
223
|
import_zod.z.string().regex(/^-?\d+$/).transform((v) => BigInt(v))
|
|
223
224
|
]),
|
|
224
225
|
Boolean: () => import_zod.z.boolean(),
|
|
225
|
-
DateTime: () => import_zod.z.union([
|
|
226
|
+
DateTime: () => import_zod.z.union([
|
|
227
|
+
import_zod.z.date(),
|
|
228
|
+
import_zod.z.string().refine(
|
|
229
|
+
(s) => !isNaN(Date.parse(s)),
|
|
230
|
+
"Invalid date string"
|
|
231
|
+
)
|
|
232
|
+
]).pipe(import_zod.z.coerce.date()),
|
|
226
233
|
Json: () => import_zod.z.unknown().refine(
|
|
227
234
|
isJsonSafe,
|
|
228
235
|
"Value must be JSON-serializable (no undefined, functions, symbols, class instances, NaN, Infinity, or circular references)"
|
|
@@ -239,8 +246,8 @@ function wrapWithInputCoercion(fieldType, isList, schema) {
|
|
|
239
246
|
break;
|
|
240
247
|
case "Int":
|
|
241
248
|
itemCoercion = import_zod.z.union([
|
|
242
|
-
import_zod.z.number().int(),
|
|
243
|
-
import_zod.z.string().regex(/^-?\d
|
|
249
|
+
import_zod.z.number().transform((v) => Math.trunc(v)).pipe(import_zod.z.number().int()),
|
|
250
|
+
import_zod.z.string().regex(/^-?\d+(\.\d+)?$/).transform((v) => Math.trunc(Number(v)))
|
|
244
251
|
]);
|
|
245
252
|
break;
|
|
246
253
|
case "Float":
|
|
@@ -818,7 +825,7 @@ function createSchemaBuilder(typeMap, zodChains, enumMap, scalarBase, zodDefault
|
|
|
818
825
|
var import_zod7 = require("zod");
|
|
819
826
|
|
|
820
827
|
// src/shared/constants.ts
|
|
821
|
-
var
|
|
828
|
+
var SHAPE_CONFIG_KEY_LIST = [
|
|
822
829
|
"where",
|
|
823
830
|
"include",
|
|
824
831
|
"select",
|
|
@@ -834,13 +841,15 @@ var SHAPE_CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
|
834
841
|
"_min",
|
|
835
842
|
"_max",
|
|
836
843
|
"by"
|
|
837
|
-
]
|
|
838
|
-
var
|
|
844
|
+
];
|
|
845
|
+
var SHAPE_CONFIG_KEYS = new Set(SHAPE_CONFIG_KEY_LIST);
|
|
846
|
+
var GUARD_SHAPE_KEY_LIST = [
|
|
839
847
|
"data",
|
|
840
848
|
"create",
|
|
841
849
|
"update",
|
|
842
|
-
...
|
|
843
|
-
]
|
|
850
|
+
...SHAPE_CONFIG_KEY_LIST
|
|
851
|
+
];
|
|
852
|
+
var GUARD_SHAPE_KEYS = new Set(GUARD_SHAPE_KEY_LIST);
|
|
844
853
|
var COMBINATOR_KEYS = /* @__PURE__ */ new Set(["AND", "OR", "NOT"]);
|
|
845
854
|
var TO_MANY_RELATION_OPS = /* @__PURE__ */ new Set(["some", "every", "none"]);
|
|
846
855
|
var TO_ONE_RELATION_OPS = /* @__PURE__ */ new Set(["is", "isNot"]);
|
|
@@ -2478,67 +2487,51 @@ function createProjectionBuilder(typeMap, enumMap, deps) {
|
|
|
2478
2487
|
return { buildIncludeSchema, buildSelectSchema, buildIncludeCountSchema };
|
|
2479
2488
|
}
|
|
2480
2489
|
|
|
2481
|
-
// src/
|
|
2482
|
-
var
|
|
2483
|
-
findMany:
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
]
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
"distinct"
|
|
2502
|
-
]),
|
|
2503
|
-
findFirstOrThrow: /* @__PURE__ */ new Set([
|
|
2504
|
-
"where",
|
|
2505
|
-
"include",
|
|
2506
|
-
"select",
|
|
2507
|
-
"orderBy",
|
|
2508
|
-
"cursor",
|
|
2509
|
-
"take",
|
|
2510
|
-
"skip",
|
|
2511
|
-
"distinct"
|
|
2512
|
-
]),
|
|
2513
|
-
findUnique: /* @__PURE__ */ new Set(["where", "include", "select"]),
|
|
2514
|
-
findUniqueOrThrow: /* @__PURE__ */ new Set(["where", "include", "select"]),
|
|
2515
|
-
count: /* @__PURE__ */ new Set(["where", "select", "cursor", "orderBy", "skip", "take"]),
|
|
2516
|
-
aggregate: /* @__PURE__ */ new Set([
|
|
2517
|
-
"where",
|
|
2518
|
-
"orderBy",
|
|
2519
|
-
"cursor",
|
|
2520
|
-
"take",
|
|
2521
|
-
"skip",
|
|
2522
|
-
"_count",
|
|
2523
|
-
"_avg",
|
|
2524
|
-
"_sum",
|
|
2525
|
-
"_min",
|
|
2526
|
-
"_max"
|
|
2527
|
-
]),
|
|
2528
|
-
groupBy: /* @__PURE__ */ new Set([
|
|
2529
|
-
"where",
|
|
2530
|
-
"by",
|
|
2531
|
-
"having",
|
|
2532
|
-
"_count",
|
|
2533
|
-
"_avg",
|
|
2534
|
-
"_sum",
|
|
2535
|
-
"_min",
|
|
2536
|
-
"_max",
|
|
2537
|
-
"orderBy",
|
|
2538
|
-
"take",
|
|
2539
|
-
"skip"
|
|
2540
|
-
])
|
|
2490
|
+
// src/shared/operation-shape-keys.ts
|
|
2491
|
+
var OPERATION_SHAPE_KEYS = {
|
|
2492
|
+
findMany: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2493
|
+
findFirst: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2494
|
+
findFirstOrThrow: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2495
|
+
findUnique: ["where", "include", "select"],
|
|
2496
|
+
findUniqueOrThrow: ["where", "include", "select"],
|
|
2497
|
+
findManyPaginated: ["where", "include", "select", "orderBy", "cursor", "take", "skip", "distinct"],
|
|
2498
|
+
count: ["where", "select", "cursor", "orderBy", "skip", "take"],
|
|
2499
|
+
aggregate: ["where", "orderBy", "cursor", "take", "skip", "_count", "_avg", "_sum", "_min", "_max"],
|
|
2500
|
+
groupBy: ["where", "by", "having", "_count", "_avg", "_sum", "_min", "_max", "orderBy", "take", "skip"],
|
|
2501
|
+
create: ["data", "select", "include"],
|
|
2502
|
+
createMany: ["data"],
|
|
2503
|
+
createManyAndReturn: ["data", "select", "include"],
|
|
2504
|
+
update: ["data", "where", "select", "include"],
|
|
2505
|
+
updateMany: ["data", "where"],
|
|
2506
|
+
updateManyAndReturn: ["data", "where", "select", "include"],
|
|
2507
|
+
upsert: ["where", "create", "update", "select", "include"],
|
|
2508
|
+
delete: ["where", "select", "include"],
|
|
2509
|
+
deleteMany: ["where"]
|
|
2541
2510
|
};
|
|
2511
|
+
var READ_METHOD_ALLOWED_ARGS = {
|
|
2512
|
+
findMany: new Set(OPERATION_SHAPE_KEYS.findMany),
|
|
2513
|
+
findFirst: new Set(OPERATION_SHAPE_KEYS.findFirst),
|
|
2514
|
+
findFirstOrThrow: new Set(OPERATION_SHAPE_KEYS.findFirstOrThrow),
|
|
2515
|
+
findUnique: new Set(OPERATION_SHAPE_KEYS.findUnique),
|
|
2516
|
+
findUniqueOrThrow: new Set(OPERATION_SHAPE_KEYS.findUniqueOrThrow),
|
|
2517
|
+
count: new Set(OPERATION_SHAPE_KEYS.count),
|
|
2518
|
+
aggregate: new Set(OPERATION_SHAPE_KEYS.aggregate),
|
|
2519
|
+
groupBy: new Set(OPERATION_SHAPE_KEYS.groupBy)
|
|
2520
|
+
};
|
|
2521
|
+
var MUTATION_SHAPE_KEYS = {
|
|
2522
|
+
create: new Set(OPERATION_SHAPE_KEYS.create),
|
|
2523
|
+
createMany: new Set(OPERATION_SHAPE_KEYS.createMany),
|
|
2524
|
+
createManyAndReturn: new Set(OPERATION_SHAPE_KEYS.createManyAndReturn),
|
|
2525
|
+
update: new Set(OPERATION_SHAPE_KEYS.update),
|
|
2526
|
+
updateMany: new Set(OPERATION_SHAPE_KEYS.updateMany),
|
|
2527
|
+
updateManyAndReturn: new Set(OPERATION_SHAPE_KEYS.updateManyAndReturn),
|
|
2528
|
+
upsert: new Set(OPERATION_SHAPE_KEYS.upsert),
|
|
2529
|
+
delete: new Set(OPERATION_SHAPE_KEYS.delete),
|
|
2530
|
+
deleteMany: new Set(OPERATION_SHAPE_KEYS.deleteMany)
|
|
2531
|
+
};
|
|
2532
|
+
|
|
2533
|
+
// src/runtime/query-builder.ts
|
|
2534
|
+
var METHOD_ALLOWED_ARGS = READ_METHOD_ALLOWED_ARGS;
|
|
2542
2535
|
var UNIQUE_WHERE_METHODS = /* @__PURE__ */ new Set([
|
|
2543
2536
|
"findUnique",
|
|
2544
2537
|
"findUniqueOrThrow"
|
|
@@ -2949,11 +2942,29 @@ function buildAndConditions(existingWhere, conditions) {
|
|
|
2949
2942
|
return conditions[0];
|
|
2950
2943
|
return { AND: conditions };
|
|
2951
2944
|
}
|
|
2952
|
-
function
|
|
2953
|
-
|
|
2945
|
+
function stripScopeFksFromWhere(where, scopeFks, log, model) {
|
|
2946
|
+
let result = where;
|
|
2947
|
+
for (const fk of scopeFks) {
|
|
2948
|
+
if (fk in result) {
|
|
2949
|
+
if (result === where)
|
|
2950
|
+
result = { ...where };
|
|
2951
|
+
log.warn(
|
|
2952
|
+
`prisma-guard: Scope FK "${fk}" found in where for model "${model}". Stripped in favor of scope context.`
|
|
2953
|
+
);
|
|
2954
|
+
delete result[fk];
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
return result;
|
|
2958
|
+
}
|
|
2959
|
+
function buildScopedUniqueWhere(existingWhere, conditions, scopeFks, log, model) {
|
|
2960
|
+
let cleaned = existingWhere;
|
|
2961
|
+
if (cleaned) {
|
|
2962
|
+
cleaned = stripScopeFksFromWhere(cleaned, scopeFks, log, model);
|
|
2963
|
+
}
|
|
2964
|
+
if (!cleaned || Object.keys(cleaned).length === 0) {
|
|
2954
2965
|
return conditions.length === 1 ? conditions[0] : { AND: conditions };
|
|
2955
2966
|
}
|
|
2956
|
-
const { AND: existingAnd, ...topLevel } =
|
|
2967
|
+
const { AND: existingAnd, ...topLevel } = cleaned;
|
|
2957
2968
|
const allConditions = [];
|
|
2958
2969
|
if (existingAnd !== void 0) {
|
|
2959
2970
|
if (Array.isArray(existingAnd)) {
|
|
@@ -3053,6 +3064,13 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
|
|
|
3053
3064
|
`prisma-guard: Invalid onScopeRelationWrite "${onScopeRelationWrite}". Allowed: ${[...VALID_ON_SCOPE_RELATION_WRITES].join(", ")}`
|
|
3054
3065
|
);
|
|
3055
3066
|
}
|
|
3067
|
+
const scopeFkSets = /* @__PURE__ */ new Map();
|
|
3068
|
+
for (const [model, entries] of Object.entries(scopeMap)) {
|
|
3069
|
+
const fks = /* @__PURE__ */ new Set();
|
|
3070
|
+
for (const entry of entries)
|
|
3071
|
+
fks.add(entry.fk);
|
|
3072
|
+
scopeFkSets.set(model, fks);
|
|
3073
|
+
}
|
|
3056
3074
|
return {
|
|
3057
3075
|
name: "prisma-guard-scope",
|
|
3058
3076
|
query: {
|
|
@@ -3073,7 +3091,7 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
|
|
|
3073
3091
|
if (missingRoots.length > 0) {
|
|
3074
3092
|
if (isMutation || guardConfig.onMissingScopeContext === "error") {
|
|
3075
3093
|
throw new PolicyError(
|
|
3076
|
-
`Missing scope context for model "${model}": roots ${missingRoots.map((r) => `"${r}"`).join(", ")} not provided. All scope roots must be present.`
|
|
3094
|
+
`prisma-guard: Missing scope context for model "${model}": roots ${missingRoots.map((r) => `"${r}"`).join(", ")} not provided. All scope roots must be present.`
|
|
3077
3095
|
);
|
|
3078
3096
|
}
|
|
3079
3097
|
if (guardConfig.onMissingScopeContext === "warn") {
|
|
@@ -3089,9 +3107,10 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
|
|
|
3089
3107
|
const overrides = Object.fromEntries(
|
|
3090
3108
|
presentScopes.map((s) => [s.fk, ctx[s.root]])
|
|
3091
3109
|
);
|
|
3110
|
+
const modelFks = scopeFkSets.get(model) ?? /* @__PURE__ */ new Set();
|
|
3092
3111
|
const nextArgs = { ...args };
|
|
3093
3112
|
if (operation === "upsert") {
|
|
3094
|
-
nextArgs.where = buildScopedUniqueWhere(args.where, conditions);
|
|
3113
|
+
nextArgs.where = buildScopedUniqueWhere(args.where, conditions, modelFks, log, model);
|
|
3095
3114
|
if (args.create !== void 0 && args.create !== null) {
|
|
3096
3115
|
if (typeof args.create !== "object" || Array.isArray(args.create)) {
|
|
3097
3116
|
throw new ShapeError(`upsert expects create to be an object`);
|
|
@@ -3129,7 +3148,7 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
|
|
|
3129
3148
|
if (FIND_UNIQUE_OPS.has(operation)) {
|
|
3130
3149
|
if (findUniqueMode === "reject") {
|
|
3131
3150
|
throw new PolicyError(
|
|
3132
|
-
`Scoped model "${model}" does not allow ${operation} via scope extension (findUniqueMode is "reject"). Use findFirst with explicit where conditions instead.`
|
|
3151
|
+
`prisma-guard: Scoped model "${model}" does not allow ${operation} via scope extension (findUniqueMode is "reject"). Use findFirst with explicit where conditions instead.`
|
|
3133
3152
|
);
|
|
3134
3153
|
}
|
|
3135
3154
|
return handleFindUnique(
|
|
@@ -3199,7 +3218,7 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
|
|
|
3199
3218
|
return query(nextArgs);
|
|
3200
3219
|
}
|
|
3201
3220
|
if (UNIQUE_MUTATION_OPS.has(operation)) {
|
|
3202
|
-
nextArgs.where = buildScopedUniqueWhere(args.where, conditions);
|
|
3221
|
+
nextArgs.where = buildScopedUniqueWhere(args.where, conditions, modelFks, log, model);
|
|
3203
3222
|
if (args.data !== void 0 && args.data !== null) {
|
|
3204
3223
|
if (typeof args.data !== "object" || Array.isArray(args.data)) {
|
|
3205
3224
|
throw new ShapeError(`${operation} expects data to be an object`);
|
|
@@ -3239,7 +3258,7 @@ function createScopeExtension(scopeMap, contextFn, guardConfig, logger) {
|
|
|
3239
3258
|
return query(nextArgs);
|
|
3240
3259
|
}
|
|
3241
3260
|
throw new ShapeError(
|
|
3242
|
-
`Unknown operation "${operation}" on scoped model "${model}". Update prisma-guard to handle this operation.`
|
|
3261
|
+
`prisma-guard: Unknown operation "${operation}" on scoped model "${model}". Update prisma-guard to handle this operation.`
|
|
3243
3262
|
);
|
|
3244
3263
|
}
|
|
3245
3264
|
}
|
|
@@ -3310,7 +3329,7 @@ async function handleFindUnique(args, query, conditions, scopes, operation, log,
|
|
|
3310
3329
|
if (!looseEqual(verifyObj[fk], value, log, fk)) {
|
|
3311
3330
|
if (operation === "findUniqueOrThrow") {
|
|
3312
3331
|
throw new PolicyError(
|
|
3313
|
-
`Record on model "${model}" not accessible in current scope`
|
|
3332
|
+
`prisma-guard: Record on model "${model}" not accessible in current scope`
|
|
3314
3333
|
);
|
|
3315
3334
|
}
|
|
3316
3335
|
return null;
|
|
@@ -4382,8 +4401,10 @@ function createModelGuardExtension(config) {
|
|
|
4382
4401
|
equalityFields.add(key);
|
|
4383
4402
|
continue;
|
|
4384
4403
|
}
|
|
4385
|
-
if (isPlainObject(value)
|
|
4386
|
-
|
|
4404
|
+
if (isPlainObject(value)) {
|
|
4405
|
+
if ("equals" in value) {
|
|
4406
|
+
equalityFields.add(key);
|
|
4407
|
+
}
|
|
4387
4408
|
continue;
|
|
4388
4409
|
}
|
|
4389
4410
|
if (value !== null && value !== void 0) {
|
|
@@ -5258,6 +5279,11 @@ function createGuard(config) {
|
|
|
5258
5279
|
}
|
|
5259
5280
|
};
|
|
5260
5281
|
}
|
|
5282
|
+
|
|
5283
|
+
// src/shared/typed-shape.ts
|
|
5284
|
+
function namedShapes(shapes) {
|
|
5285
|
+
return shapes;
|
|
5286
|
+
}
|
|
5261
5287
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5262
5288
|
0 && (module.exports = {
|
|
5263
5289
|
CallerError,
|
|
@@ -5265,6 +5291,7 @@ function createGuard(config) {
|
|
|
5265
5291
|
ShapeError,
|
|
5266
5292
|
createGuard,
|
|
5267
5293
|
force,
|
|
5294
|
+
namedShapes,
|
|
5268
5295
|
unsupported
|
|
5269
5296
|
});
|
|
5270
5297
|
//# sourceMappingURL=index.cjs.map
|