prisma-guard 1.31.0 → 1.32.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/README.md +61 -11
- package/dist/runtime/index.cjs +127 -102
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.js +127 -102
- package/dist/runtime/index.js.map +1 -1
- package/package.json +1 -1
package/dist/runtime/index.js
CHANGED
|
@@ -944,40 +944,75 @@ function unsupported() {
|
|
|
944
944
|
return marker;
|
|
945
945
|
}
|
|
946
946
|
|
|
947
|
-
// src/shared/
|
|
948
|
-
function
|
|
949
|
-
|
|
950
|
-
return null;
|
|
951
|
-
if (patterns.includes(caller))
|
|
952
|
-
return caller;
|
|
947
|
+
// src/shared/guard-variant-routing.ts
|
|
948
|
+
function matchVariantPatterns(keys, caller) {
|
|
949
|
+
const callerParts = caller.split("/");
|
|
953
950
|
const matches = [];
|
|
954
|
-
for (const pattern of
|
|
951
|
+
for (const pattern of keys) {
|
|
955
952
|
if (!pattern.includes(":"))
|
|
956
953
|
continue;
|
|
957
954
|
const patternParts = pattern.split("/");
|
|
958
|
-
const callerParts = caller.split("/");
|
|
959
955
|
if (patternParts.length !== callerParts.length)
|
|
960
956
|
continue;
|
|
961
|
-
let
|
|
962
|
-
for (let
|
|
963
|
-
if (patternParts[
|
|
957
|
+
let matchesCaller = true;
|
|
958
|
+
for (let index = 0; index < patternParts.length; index++) {
|
|
959
|
+
if (patternParts[index].startsWith(":"))
|
|
964
960
|
continue;
|
|
965
|
-
if (patternParts[
|
|
966
|
-
|
|
961
|
+
if (patternParts[index] !== callerParts[index]) {
|
|
962
|
+
matchesCaller = false;
|
|
967
963
|
break;
|
|
968
964
|
}
|
|
969
965
|
}
|
|
970
|
-
if (
|
|
966
|
+
if (matchesCaller)
|
|
971
967
|
matches.push(pattern);
|
|
972
968
|
}
|
|
973
|
-
|
|
974
|
-
|
|
969
|
+
return matches;
|
|
970
|
+
}
|
|
971
|
+
function resolveGuardVariantKey(input) {
|
|
972
|
+
if (input.kind === "single") {
|
|
973
|
+
return { ok: true, key: "_default" };
|
|
974
|
+
}
|
|
975
|
+
const { keys, caller, reservedKeys } = input;
|
|
976
|
+
for (const key of keys) {
|
|
977
|
+
if (reservedKeys.has(key)) {
|
|
978
|
+
return {
|
|
979
|
+
ok: false,
|
|
980
|
+
code: "reserved-key",
|
|
981
|
+
key,
|
|
982
|
+
keys
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
const hasDefault = keys.includes("default");
|
|
987
|
+
if (typeof caller !== "string") {
|
|
988
|
+
if (hasDefault)
|
|
989
|
+
return { ok: true, key: "default" };
|
|
990
|
+
return { ok: false, code: "missing-caller", keys };
|
|
991
|
+
}
|
|
992
|
+
if (caller.trim().length === 0) {
|
|
993
|
+
if (hasDefault)
|
|
994
|
+
return { ok: true, key: "default" };
|
|
995
|
+
return { ok: false, code: "unknown-caller", caller, keys };
|
|
996
|
+
}
|
|
997
|
+
if (keys.includes(caller)) {
|
|
998
|
+
return { ok: true, key: caller };
|
|
999
|
+
}
|
|
1000
|
+
const matches = matchVariantPatterns(keys, caller);
|
|
1001
|
+
if (matches.length === 1) {
|
|
1002
|
+
return { ok: true, key: matches[0] };
|
|
1003
|
+
}
|
|
975
1004
|
if (matches.length > 1) {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1005
|
+
return {
|
|
1006
|
+
ok: false,
|
|
1007
|
+
code: "ambiguous-caller",
|
|
1008
|
+
caller,
|
|
1009
|
+
keys,
|
|
1010
|
+
matches
|
|
1011
|
+
};
|
|
979
1012
|
}
|
|
980
|
-
|
|
1013
|
+
if (hasDefault)
|
|
1014
|
+
return { ok: true, key: "default" };
|
|
1015
|
+
return { ok: false, code: "unknown-caller", caller, keys };
|
|
981
1016
|
}
|
|
982
1017
|
|
|
983
1018
|
// src/runtime/policy.ts
|
|
@@ -3410,22 +3445,27 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3410
3445
|
forcedSelectCountWhere
|
|
3411
3446
|
};
|
|
3412
3447
|
}
|
|
3413
|
-
function
|
|
3414
|
-
const
|
|
3415
|
-
if (
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
built = buildShapeZodSchema(model, method, resolved);
|
|
3425
|
-
} else {
|
|
3426
|
-
built = builtCache.get("default");
|
|
3448
|
+
function throwQueryVariantResolution(resolution) {
|
|
3449
|
+
const keys = resolution.keys.map((key) => `"${key}"`).join(", ");
|
|
3450
|
+
if (resolution.code === "reserved-key") {
|
|
3451
|
+
throw new ShapeError(
|
|
3452
|
+
`Caller key "${resolution.key}" collides with reserved shape config key. Rename the caller path.`
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
3455
|
+
if (resolution.code === "missing-caller") {
|
|
3456
|
+
throw new CallerError(
|
|
3457
|
+
`Missing caller. This query uses named shape routing with keys: ${keys}. Provide caller via opts.caller.`
|
|
3458
|
+
);
|
|
3427
3459
|
}
|
|
3428
|
-
|
|
3460
|
+
if (resolution.code === "ambiguous-caller") {
|
|
3461
|
+
const matches = (resolution.matches ?? []).map((pattern) => `"${pattern}"`).join(", ");
|
|
3462
|
+
throw new CallerError(
|
|
3463
|
+
`Ambiguous caller "${resolution.caller}" matches multiple patterns: ${matches}`
|
|
3464
|
+
);
|
|
3465
|
+
}
|
|
3466
|
+
throw new CallerError(
|
|
3467
|
+
`Unknown caller: "${resolution.caller}". Allowed: ${keys}`
|
|
3468
|
+
);
|
|
3429
3469
|
}
|
|
3430
3470
|
function buildQuerySchema(model, method, config) {
|
|
3431
3471
|
const isSingle = typeof config === "function" || isShapeConfig(config);
|
|
@@ -3437,12 +3477,15 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3437
3477
|
);
|
|
3438
3478
|
}
|
|
3439
3479
|
if (!isSingle) {
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3480
|
+
const keys = Object.keys(config);
|
|
3481
|
+
const validation = resolveGuardVariantKey({
|
|
3482
|
+
kind: "named",
|
|
3483
|
+
keys,
|
|
3484
|
+
caller: void 0,
|
|
3485
|
+
reservedKeys: SHAPE_CONFIG_KEYS
|
|
3486
|
+
});
|
|
3487
|
+
if (!validation.ok && validation.code === "reserved-key") {
|
|
3488
|
+
throwQueryVariantResolution(validation);
|
|
3446
3489
|
}
|
|
3447
3490
|
for (const [key, shapeOrFn] of Object.entries(
|
|
3448
3491
|
config
|
|
@@ -3480,47 +3523,20 @@ function createQueryBuilder(typeMap, enumMap, uniqueMap, scalarBase) {
|
|
|
3480
3523
|
);
|
|
3481
3524
|
}
|
|
3482
3525
|
const namedConfig = config;
|
|
3483
|
-
const
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
);
|
|
3495
|
-
}
|
|
3496
|
-
const allowed = Object.keys(namedConfig);
|
|
3497
|
-
throw new CallerError(
|
|
3498
|
-
`Missing caller. This query uses named shape routing with keys: ${allowed.map((k) => `"${k}"`).join(", ")}. Provide caller via opts.caller.`
|
|
3499
|
-
);
|
|
3500
|
-
}
|
|
3501
|
-
const matched = matchCaller(namedConfig, caller);
|
|
3502
|
-
if (!matched) {
|
|
3503
|
-
if ("default" in namedConfig) {
|
|
3504
|
-
return resolveDefaultShape(
|
|
3505
|
-
namedConfig,
|
|
3506
|
-
model,
|
|
3507
|
-
method,
|
|
3508
|
-
normalizedBody,
|
|
3509
|
-
opts,
|
|
3510
|
-
builtCache,
|
|
3511
|
-
isUnique
|
|
3512
|
-
);
|
|
3513
|
-
}
|
|
3514
|
-
const allowed = Object.keys(namedConfig);
|
|
3515
|
-
throw new CallerError(
|
|
3516
|
-
`Unknown caller: "${caller}". Allowed: ${allowed.map((k) => `"${k}"`).join(", ")}`
|
|
3517
|
-
);
|
|
3518
|
-
}
|
|
3519
|
-
if (typeof matched.shape === "function") {
|
|
3520
|
-
const resolved = resolveAndValidateShape(matched.shape, opts?.ctx);
|
|
3526
|
+
const resolution = resolveGuardVariantKey({
|
|
3527
|
+
kind: "named",
|
|
3528
|
+
keys: Object.keys(namedConfig),
|
|
3529
|
+
caller: opts?.caller,
|
|
3530
|
+
reservedKeys: SHAPE_CONFIG_KEYS
|
|
3531
|
+
});
|
|
3532
|
+
if (!resolution.ok)
|
|
3533
|
+
throwQueryVariantResolution(resolution);
|
|
3534
|
+
const shapeOrFn = namedConfig[resolution.key];
|
|
3535
|
+
if (typeof shapeOrFn === "function") {
|
|
3536
|
+
const resolved = resolveAndValidateShape(shapeOrFn, opts?.ctx);
|
|
3521
3537
|
built = buildShapeZodSchema(model, method, resolved);
|
|
3522
3538
|
} else {
|
|
3523
|
-
built = builtCache.get(
|
|
3539
|
+
built = builtCache.get(resolution.key);
|
|
3524
3540
|
}
|
|
3525
3541
|
}
|
|
3526
3542
|
return applyBuiltShape(built, normalizedBody, isUnique);
|
|
@@ -4755,34 +4771,43 @@ function resolveDynamicShape(shapeFn, ctx, context) {
|
|
|
4755
4771
|
}
|
|
4756
4772
|
return result;
|
|
4757
4773
|
}
|
|
4758
|
-
function
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
throw new ShapeError(
|
|
4765
|
-
`Caller key "${key}" collides with reserved guard shape key. Rename the caller path.`
|
|
4766
|
-
);
|
|
4767
|
-
}
|
|
4774
|
+
function throwVariantResolution(resolution) {
|
|
4775
|
+
const keys = resolution.keys.map((key) => `"${key}"`).join(", ");
|
|
4776
|
+
if (resolution.code === "reserved-key") {
|
|
4777
|
+
throw new ShapeError(
|
|
4778
|
+
`Caller key "${resolution.key}" collides with reserved guard shape key. Rename the caller path.`
|
|
4779
|
+
);
|
|
4768
4780
|
}
|
|
4769
|
-
if (
|
|
4770
|
-
if ("default" in input) {
|
|
4771
|
-
return resolveShapeEntry(input.default, body, contextFn, "default");
|
|
4772
|
-
}
|
|
4781
|
+
if (resolution.code === "missing-caller") {
|
|
4773
4782
|
throw new CallerError(
|
|
4774
|
-
`Missing caller. This guard uses named shape routing with keys: ${keys
|
|
4783
|
+
`Missing caller. This guard uses named shape routing with keys: ${keys}. Provide caller via guard(input, caller).`
|
|
4775
4784
|
);
|
|
4776
4785
|
}
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
return resolveShapeEntry(input.default, body, contextFn, "default");
|
|
4786
|
+
if (resolution.code === "ambiguous-caller") {
|
|
4787
|
+
const matches = (resolution.matches ?? []).map((pattern) => `"${pattern}"`).join(", ");
|
|
4788
|
+
throw new CallerError(
|
|
4789
|
+
`Ambiguous caller "${resolution.caller}" matches multiple patterns: ${matches}`
|
|
4790
|
+
);
|
|
4783
4791
|
}
|
|
4784
4792
|
throw new CallerError(
|
|
4785
|
-
`Unknown caller: "${caller}". Allowed: ${keys
|
|
4793
|
+
`Unknown caller: "${resolution.caller}". Allowed: ${keys}`
|
|
4794
|
+
);
|
|
4795
|
+
}
|
|
4796
|
+
function resolveNamedShape(input, body, contextFn, explicitCaller) {
|
|
4797
|
+
assertNoCallerInBody(body);
|
|
4798
|
+
const resolution = resolveGuardVariantKey({
|
|
4799
|
+
kind: "named",
|
|
4800
|
+
keys: Object.keys(input),
|
|
4801
|
+
caller: explicitCaller,
|
|
4802
|
+
reservedKeys: GUARD_SHAPE_KEYS
|
|
4803
|
+
});
|
|
4804
|
+
if (!resolution.ok)
|
|
4805
|
+
throwVariantResolution(resolution);
|
|
4806
|
+
return resolveShapeEntry(
|
|
4807
|
+
input[resolution.key],
|
|
4808
|
+
body,
|
|
4809
|
+
contextFn,
|
|
4810
|
+
resolution.key
|
|
4786
4811
|
);
|
|
4787
4812
|
}
|
|
4788
4813
|
function resolveShapeEntry(entry, body, contextFn, matchedKey) {
|