@zenstackhq/runtime 1.0.0-beta.20 → 1.0.0-beta.21
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/constants.d.ts +0 -12
- package/constants.js +1 -13
- package/constants.js.map +1 -1
- package/enhancements/policy/handler.d.ts +13 -7
- package/enhancements/policy/handler.js +127 -100
- package/enhancements/policy/handler.js.map +1 -1
- package/enhancements/policy/index.d.ts +1 -1
- package/enhancements/policy/policy-utils.d.ts +7 -3
- package/enhancements/policy/policy-utils.js +211 -224
- package/enhancements/policy/policy-utils.js.map +1 -1
- package/enhancements/policy/promise.d.ts +5 -0
- package/enhancements/policy/promise.js +42 -0
- package/enhancements/policy/promise.js.map +1 -0
- package/enhancements/proxy.js +27 -21
- package/enhancements/proxy.js.map +1 -1
- package/enhancements/utils.js +1 -2
- package/enhancements/utils.js.map +1 -1
- package/package.json +1 -1
- package/types.d.ts +14 -13
- package/types.js.map +1 -1
- package/validation.d.ts +5 -0
- package/validation.js +13 -1
- package/validation.js.map +1 -1
- package/zod/index.d.ts +1 -0
- package/zod/index.js +1 -0
- package/zod/objects.d.ts +1 -0
- package/zod/objects.js +8 -0
package/constants.d.ts
CHANGED
|
@@ -2,18 +2,6 @@
|
|
|
2
2
|
* Default length of password hash salt (used by bcryptjs to hash password)
|
|
3
3
|
*/
|
|
4
4
|
export declare const DEFAULT_PASSWORD_SALT_LENGTH = 12;
|
|
5
|
-
/**
|
|
6
|
-
* Auxiliary database field for supporting policy check for nested writes
|
|
7
|
-
*/
|
|
8
|
-
export declare const TRANSACTION_FIELD_NAME = "zenstack_transaction";
|
|
9
|
-
/**
|
|
10
|
-
* Auxiliary database field for building up policy check queries
|
|
11
|
-
*/
|
|
12
|
-
export declare const GUARD_FIELD_NAME = "zenstack_guard";
|
|
13
|
-
/**
|
|
14
|
-
* All Auxiliary fields.
|
|
15
|
-
*/
|
|
16
|
-
export declare const AUXILIARY_FIELDS: string[];
|
|
17
5
|
/**
|
|
18
6
|
* Reasons for a CRUD operation to fail
|
|
19
7
|
*/
|
package/constants.js
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HAS_FIELD_LEVEL_POLICY_FLAG = exports.FIELD_LEVEL_UPDATE_GUARD_PREFIX = exports.FIELD_LEVEL_READ_CHECKER_SELECTOR = exports.FIELD_LEVEL_READ_CHECKER_PREFIX = exports.PRE_UPDATE_VALUE_SELECTOR = exports.PRISMA_MINIMUM_VERSION = exports.PRISMA_PROXY_ENHANCER = exports.PRISMA_TX_FLAG = exports.PrismaErrorCode = exports.CrudFailureReason = exports.
|
|
3
|
+
exports.HAS_FIELD_LEVEL_POLICY_FLAG = exports.FIELD_LEVEL_UPDATE_GUARD_PREFIX = exports.FIELD_LEVEL_READ_CHECKER_SELECTOR = exports.FIELD_LEVEL_READ_CHECKER_PREFIX = exports.PRE_UPDATE_VALUE_SELECTOR = exports.PRISMA_MINIMUM_VERSION = exports.PRISMA_PROXY_ENHANCER = exports.PRISMA_TX_FLAG = exports.PrismaErrorCode = exports.CrudFailureReason = exports.DEFAULT_PASSWORD_SALT_LENGTH = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Default length of password hash salt (used by bcryptjs to hash password)
|
|
6
6
|
*/
|
|
7
7
|
exports.DEFAULT_PASSWORD_SALT_LENGTH = 12;
|
|
8
|
-
/**
|
|
9
|
-
* Auxiliary database field for supporting policy check for nested writes
|
|
10
|
-
*/
|
|
11
|
-
exports.TRANSACTION_FIELD_NAME = 'zenstack_transaction';
|
|
12
|
-
/**
|
|
13
|
-
* Auxiliary database field for building up policy check queries
|
|
14
|
-
*/
|
|
15
|
-
exports.GUARD_FIELD_NAME = 'zenstack_guard';
|
|
16
|
-
/**
|
|
17
|
-
* All Auxiliary fields.
|
|
18
|
-
*/
|
|
19
|
-
exports.AUXILIARY_FIELDS = [exports.TRANSACTION_FIELD_NAME, exports.GUARD_FIELD_NAME];
|
|
20
8
|
/**
|
|
21
9
|
* Reasons for a CRUD operation to fail
|
|
22
10
|
*/
|
package/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,4BAA4B,GAAG,EAAE,CAAC;AAE/C;;GAEG;
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACU,QAAA,4BAA4B,GAAG,EAAE,CAAC;AAE/C;;GAEG;AACH,IAAY,iBAUX;AAVD,WAAY,iBAAiB;IACzB;;OAEG;IACH,gEAA2C,CAAA;IAE3C;;OAEG;IACH,4EAAuD,CAAA;AAC3D,CAAC,EAVW,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAU5B;AAED;;GAEG;AACH,IAAY,eAoBX;AApBD,WAAY,eAAe;IACvB;;OAEG;IACH,qDAAkC,CAAA;IAElC;;OAEG;IACH,+CAA4B,CAAA;IAE5B;;OAEG;IACH,gEAA6C,CAAA;IAE7C;;OAEG;IACH,uDAAoC,CAAA;AACxC,CAAC,EApBW,eAAe,GAAf,uBAAe,KAAf,uBAAe,QAoB1B;AAED;;GAEG;AACU,QAAA,cAAc,GAAG,gBAAgB,CAAC;AAE/C;;GAEG;AACU,QAAA,qBAAqB,GAAG,sBAAsB,CAAC;AAE5D;;GAEG;AACU,QAAA,sBAAsB,GAAG,OAAO,CAAC;AAE9C;;GAEG;AACU,QAAA,yBAAyB,GAAG,gBAAgB,CAAC;AAE1D;;GAEG;AACU,QAAA,+BAA+B,GAAG,iBAAiB,CAAC;AAEjE;;GAEG;AACU,QAAA,iCAAiC,GAAG,iBAAiB,CAAC;AAEnE;;GAEG;AACU,QAAA,+BAA+B,GAAG,mBAAmB,CAAC;AAEnE;;GAEG;AACU,QAAA,2BAA2B,GAAG,qBAAqB,CAAC"}
|
|
@@ -9,18 +9,22 @@ export declare class PolicyProxyHandler<DbClient extends DbClientContract> imple
|
|
|
9
9
|
private readonly policy;
|
|
10
10
|
private readonly modelMeta;
|
|
11
11
|
private readonly zodSchemas;
|
|
12
|
-
private readonly model;
|
|
13
12
|
private readonly user?;
|
|
14
13
|
private readonly logPrismaQuery?;
|
|
15
14
|
private readonly logger;
|
|
16
15
|
private readonly utils;
|
|
16
|
+
private readonly model;
|
|
17
17
|
constructor(prisma: DbClient, policy: PolicyDef, modelMeta: ModelMeta, zodSchemas: ZodSchemas | undefined, model: string, user?: AuthUser | undefined, logPrismaQuery?: boolean | undefined);
|
|
18
18
|
private get modelClient();
|
|
19
19
|
findUnique(args: any): Promise<unknown>;
|
|
20
20
|
findUniqueOrThrow(args: any): Promise<unknown>;
|
|
21
|
-
findFirst(args
|
|
21
|
+
findFirst(args?: any): Promise<unknown>;
|
|
22
22
|
findFirstOrThrow(args: any): Promise<unknown>;
|
|
23
|
-
findMany(args
|
|
23
|
+
findMany(args?: any): Promise<unknown[]>;
|
|
24
|
+
private findWithFluentCallStubs;
|
|
25
|
+
private doFind;
|
|
26
|
+
private fluentCall;
|
|
27
|
+
private addFluentFunctions;
|
|
24
28
|
create(args: any): Promise<any>;
|
|
25
29
|
private doCreate;
|
|
26
30
|
private hasNestedCreateOrConnect;
|
|
@@ -38,11 +42,13 @@ export declare class PolicyProxyHandler<DbClient extends DbClientContract> imple
|
|
|
38
42
|
deleteMany(args: any): Promise<{
|
|
39
43
|
count: number;
|
|
40
44
|
}>;
|
|
41
|
-
aggregate(args: any): Promise<
|
|
42
|
-
groupBy(args: any): Promise<
|
|
43
|
-
count(args: any): Promise<
|
|
44
|
-
subscribe(args: any): Promise<
|
|
45
|
+
aggregate(args: any): Promise<any>;
|
|
46
|
+
groupBy(args: any): Promise<any>;
|
|
47
|
+
count(args: any): Promise<any>;
|
|
48
|
+
subscribe(args: any): Promise<any>;
|
|
45
49
|
private get shouldLogQuery();
|
|
46
50
|
private transaction;
|
|
47
51
|
private runPostWriteChecks;
|
|
52
|
+
private makeHandler;
|
|
53
|
+
private requireBackLink;
|
|
48
54
|
}
|
|
@@ -22,6 +22,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
24
|
exports.PolicyProxyHandler = void 0;
|
|
25
|
+
const lower_case_first_1 = require("lower-case-first");
|
|
25
26
|
const upper_case_first_1 = require("upper-case-first");
|
|
26
27
|
const zod_validation_error_1 = require("zod-validation-error");
|
|
27
28
|
const constants_1 = require("../../constants");
|
|
@@ -31,6 +32,7 @@ const nested_write_vistor_1 = require("../nested-write-vistor");
|
|
|
31
32
|
const utils_1 = require("../utils");
|
|
32
33
|
const logger_1 = require("./logger");
|
|
33
34
|
const policy_utils_1 = require("./policy-utils");
|
|
35
|
+
const promise_1 = require("./promise");
|
|
34
36
|
/**
|
|
35
37
|
* Prisma proxy handler for injecting access policy check.
|
|
36
38
|
*/
|
|
@@ -40,11 +42,11 @@ class PolicyProxyHandler {
|
|
|
40
42
|
this.policy = policy;
|
|
41
43
|
this.modelMeta = modelMeta;
|
|
42
44
|
this.zodSchemas = zodSchemas;
|
|
43
|
-
this.model = model;
|
|
44
45
|
this.user = user;
|
|
45
46
|
this.logPrismaQuery = logPrismaQuery;
|
|
46
47
|
this.logger = new logger_1.Logger(prisma);
|
|
47
48
|
this.utils = new policy_utils_1.PolicyUtil(this.prisma, this.modelMeta, this.policy, this.zodSchemas, this.user, this.shouldLogQuery);
|
|
49
|
+
this.model = (0, lower_case_first_1.lowerCaseFirst)(model);
|
|
48
50
|
}
|
|
49
51
|
get modelClient() {
|
|
50
52
|
return this.prisma[this.model];
|
|
@@ -52,96 +54,111 @@ class PolicyProxyHandler {
|
|
|
52
54
|
//#region Find
|
|
53
55
|
// find operations behaves as if the entities that don't match access policies don't exist
|
|
54
56
|
findUnique(args) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const origArgs = args;
|
|
63
|
-
args = this.utils.clone(args);
|
|
64
|
-
if (!(yield this.utils.injectForRead(this.prisma, this.model, args))) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
this.utils.injectReadCheckSelect(this.model, args);
|
|
68
|
-
if (this.shouldLogQuery) {
|
|
69
|
-
this.logger.info(`[policy] \`findUnique\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
70
|
-
}
|
|
71
|
-
const result = yield this.modelClient.findUnique(args);
|
|
72
|
-
this.utils.postProcessForRead(result, this.model, origArgs);
|
|
73
|
-
return result;
|
|
74
|
-
});
|
|
57
|
+
if (!args) {
|
|
58
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
59
|
+
}
|
|
60
|
+
if (!args.where) {
|
|
61
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
62
|
+
}
|
|
63
|
+
return this.findWithFluentCallStubs(args, 'findUnique', false, () => null);
|
|
75
64
|
}
|
|
76
65
|
findUniqueOrThrow(args) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
args = this.utils.clone(args);
|
|
86
|
-
if (!(yield this.utils.injectForRead(this.prisma, this.model, args))) {
|
|
87
|
-
throw this.utils.notFound(this.model);
|
|
88
|
-
}
|
|
89
|
-
this.utils.injectReadCheckSelect(this.model, args);
|
|
90
|
-
if (this.shouldLogQuery) {
|
|
91
|
-
this.logger.info(`[policy] \`findUniqueOrThrow\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
92
|
-
}
|
|
93
|
-
const result = yield this.modelClient.findUniqueOrThrow(args);
|
|
94
|
-
this.utils.postProcessForRead(result, this.model, origArgs);
|
|
95
|
-
return result;
|
|
66
|
+
if (!args) {
|
|
67
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'query argument is required');
|
|
68
|
+
}
|
|
69
|
+
if (!args.where) {
|
|
70
|
+
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
71
|
+
}
|
|
72
|
+
return this.findWithFluentCallStubs(args, 'findUniqueOrThrow', true, () => {
|
|
73
|
+
throw this.utils.notFound(this.model);
|
|
96
74
|
});
|
|
97
75
|
}
|
|
98
76
|
findFirst(args) {
|
|
99
|
-
return
|
|
100
|
-
const origArgs = args;
|
|
101
|
-
args = args ? this.utils.clone(args) : {};
|
|
102
|
-
if (!(yield this.utils.injectForRead(this.prisma, this.model, args))) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
this.utils.injectReadCheckSelect(this.model, args);
|
|
106
|
-
if (this.shouldLogQuery) {
|
|
107
|
-
this.logger.info(`[policy] \`findFirst\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
108
|
-
}
|
|
109
|
-
const result = yield this.modelClient.findFirst(args);
|
|
110
|
-
this.utils.postProcessForRead(result, this.model, origArgs);
|
|
111
|
-
return result;
|
|
112
|
-
});
|
|
77
|
+
return this.findWithFluentCallStubs(args, 'findFirst', false, () => null);
|
|
113
78
|
}
|
|
114
79
|
findFirstOrThrow(args) {
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
args = args ? this.utils.clone(args) : {};
|
|
118
|
-
if (!(yield this.utils.injectForRead(this.prisma, this.model, args))) {
|
|
119
|
-
throw this.utils.notFound(this.model);
|
|
120
|
-
}
|
|
121
|
-
this.utils.injectReadCheckSelect(this.model, args);
|
|
122
|
-
if (this.shouldLogQuery) {
|
|
123
|
-
this.logger.info(`[policy] \`findFirstOrThrow\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
124
|
-
}
|
|
125
|
-
const result = yield this.modelClient.findFirstOrThrow(args);
|
|
126
|
-
this.utils.postProcessForRead(result, this.model, origArgs);
|
|
127
|
-
return result;
|
|
80
|
+
return this.findWithFluentCallStubs(args, 'findFirstOrThrow', true, () => {
|
|
81
|
+
throw this.utils.notFound(this.model);
|
|
128
82
|
});
|
|
129
83
|
}
|
|
130
84
|
findMany(args) {
|
|
131
|
-
return
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
85
|
+
return (0, promise_1.createDeferredPromise)(() => this.doFind(args, 'findMany', () => []));
|
|
86
|
+
}
|
|
87
|
+
// returns a promise for the given find operation, together with function stubs for fluent API calls
|
|
88
|
+
findWithFluentCallStubs(args, actionName, resolveRoot, handleRejection) {
|
|
89
|
+
// create a deferred promise so it's only evaluated when awaited or .then() is called
|
|
90
|
+
const result = (0, promise_1.createDeferredPromise)(() => this.doFind(args, actionName, handleRejection));
|
|
91
|
+
this.addFluentFunctions(result, this.model, args === null || args === void 0 ? void 0 : args.where, resolveRoot ? result : undefined);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
doFind(args, actionName, handleRejection) {
|
|
95
|
+
const origArgs = args;
|
|
96
|
+
const _args = this.utils.clone(args);
|
|
97
|
+
if (!this.utils.injectForRead(this.prisma, this.model, _args)) {
|
|
98
|
+
return handleRejection();
|
|
99
|
+
}
|
|
100
|
+
this.utils.injectReadCheckSelect(this.model, _args);
|
|
101
|
+
if (this.shouldLogQuery) {
|
|
102
|
+
this.logger.info(`[policy] \`${actionName}\` ${this.model}:\n${(0, utils_1.formatObject)(_args)}`);
|
|
103
|
+
}
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
this.modelClient[actionName](_args).then((value) => {
|
|
106
|
+
this.utils.postProcessForRead(value, this.model, origArgs);
|
|
107
|
+
resolve(value);
|
|
108
|
+
}, (err) => reject(err));
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
// returns a fluent API call function
|
|
112
|
+
fluentCall(filter, fieldInfo, rootPromise) {
|
|
113
|
+
return (args) => {
|
|
114
|
+
args = this.utils.clone(args);
|
|
115
|
+
// combine the parent filter with the current one
|
|
116
|
+
const backLinkField = this.requireBackLink(fieldInfo);
|
|
117
|
+
const condition = backLinkField.isArray
|
|
118
|
+
? { [backLinkField.name]: { some: filter } }
|
|
119
|
+
: { [backLinkField.name]: { is: filter } };
|
|
120
|
+
args.where = this.utils.and(args.where, condition);
|
|
121
|
+
const promise = (0, promise_1.createDeferredPromise)(() => {
|
|
122
|
+
// Promise for fetching
|
|
123
|
+
const fetchFluent = (resolve, reject) => {
|
|
124
|
+
const handler = this.makeHandler(fieldInfo.type);
|
|
125
|
+
if (fieldInfo.isArray) {
|
|
126
|
+
// fluent call stops here
|
|
127
|
+
handler.findMany(args).then((value) => resolve(value), (err) => reject(err));
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
handler.findFirst(args).then((value) => resolve(value), (err) => reject(err));
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
if (rootPromise) {
|
|
135
|
+
// if a root promise exists, resolve it before fluent API call,
|
|
136
|
+
// so that fluent calls start with `findUniqueOrThrow` and `findFirstOrThrow`
|
|
137
|
+
// can throw error properly if the root promise is rejected
|
|
138
|
+
rootPromise.then(() => fetchFluent(resolve, reject), (err) => reject(err));
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
fetchFluent(resolve, reject);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
if (!fieldInfo.isArray) {
|
|
146
|
+
// prepare for a chained fluent API call
|
|
147
|
+
this.addFluentFunctions(promise, fieldInfo.type, args.where, rootPromise);
|
|
136
148
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
return promise;
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// add fluent API functions to the given promise
|
|
153
|
+
addFluentFunctions(promise, model, filter, rootPromise) {
|
|
154
|
+
const fields = this.utils.getModelFields(model);
|
|
155
|
+
if (fields) {
|
|
156
|
+
for (const [field, fieldInfo] of Object.entries(fields)) {
|
|
157
|
+
if (fieldInfo.isDataModel) {
|
|
158
|
+
promise[field] = this.fluentCall(filter, fieldInfo, rootPromise);
|
|
159
|
+
}
|
|
140
160
|
}
|
|
141
|
-
|
|
142
|
-
this.utils.postProcessForRead(result, this.model, origArgs);
|
|
143
|
-
return result;
|
|
144
|
-
});
|
|
161
|
+
}
|
|
145
162
|
}
|
|
146
163
|
//#endregion
|
|
147
164
|
//#region Create
|
|
@@ -153,7 +170,7 @@ class PolicyProxyHandler {
|
|
|
153
170
|
if (!args.data) {
|
|
154
171
|
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
155
172
|
}
|
|
156
|
-
|
|
173
|
+
this.utils.tryReject(this.prisma, this.model, 'create');
|
|
157
174
|
const origArgs = args;
|
|
158
175
|
args = this.utils.clone(args);
|
|
159
176
|
// static input policy check for top-level create data
|
|
@@ -517,7 +534,7 @@ class PolicyProxyHandler {
|
|
|
517
534
|
let createData = args;
|
|
518
535
|
if ((_a = context.field) === null || _a === void 0 ? void 0 : _a.backLink) {
|
|
519
536
|
// handles the connection to upstream entity
|
|
520
|
-
const reversedQuery =
|
|
537
|
+
const reversedQuery = this.utils.buildReversedQuery(context);
|
|
521
538
|
if (reversedQuery[context.field.backLink]) {
|
|
522
539
|
// the built reverse query contains a condition for the backlink field, build a "connect" with it
|
|
523
540
|
createData = Object.assign(Object.assign({}, createData), { [context.field.backLink]: {
|
|
@@ -537,7 +554,7 @@ class PolicyProxyHandler {
|
|
|
537
554
|
var _b;
|
|
538
555
|
if ((_b = context.field) === null || _b === void 0 ? void 0 : _b.backLink) {
|
|
539
556
|
// handles the connection to upstream entity
|
|
540
|
-
const reversedQuery =
|
|
557
|
+
const reversedQuery = this.utils.buildReversedQuery(context);
|
|
541
558
|
for (const item of (0, utils_1.enumerate)(args.data)) {
|
|
542
559
|
Object.assign(item, reversedQuery);
|
|
543
560
|
}
|
|
@@ -563,7 +580,7 @@ class PolicyProxyHandler {
|
|
|
563
580
|
update: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
564
581
|
var _d;
|
|
565
582
|
// build a unique query including upstream conditions
|
|
566
|
-
const uniqueFilter =
|
|
583
|
+
const uniqueFilter = this.utils.buildReversedQuery(context);
|
|
567
584
|
// handle not-found
|
|
568
585
|
const existing = yield this.utils.checkExistence(db, model, uniqueFilter, true);
|
|
569
586
|
// check if the update actually writes to this model
|
|
@@ -606,7 +623,7 @@ class PolicyProxyHandler {
|
|
|
606
623
|
}),
|
|
607
624
|
updateMany: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
608
625
|
// injects auth guard into where clause
|
|
609
|
-
|
|
626
|
+
this.utils.injectAuthGuard(db, args, model, 'update');
|
|
610
627
|
// prepare for post-update check
|
|
611
628
|
if (this.utils.hasAuthGuard(model, 'postUpdate') || this.utils.getZodSchema(model)) {
|
|
612
629
|
let select = this.utils.makeIdSelection(model);
|
|
@@ -614,9 +631,9 @@ class PolicyProxyHandler {
|
|
|
614
631
|
if (preValueSelect) {
|
|
615
632
|
select = Object.assign(Object.assign({}, select), preValueSelect);
|
|
616
633
|
}
|
|
617
|
-
const reversedQuery =
|
|
634
|
+
const reversedQuery = this.utils.buildReversedQuery(context);
|
|
618
635
|
const currentSetQuery = { select, where: reversedQuery };
|
|
619
|
-
|
|
636
|
+
this.utils.injectAuthGuard(db, currentSetQuery, model, 'read');
|
|
620
637
|
if (this.shouldLogQuery) {
|
|
621
638
|
this.logger.info(`[policy] \`findMany\` ${model}:\n${(0, utils_1.formatObject)(currentSetQuery)}`);
|
|
622
639
|
}
|
|
@@ -647,7 +664,7 @@ class PolicyProxyHandler {
|
|
|
647
664
|
}),
|
|
648
665
|
upsert: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
649
666
|
// build a unique query including upstream conditions
|
|
650
|
-
const uniqueFilter =
|
|
667
|
+
const uniqueFilter = this.utils.buildReversedQuery(context);
|
|
651
668
|
// branch based on if the update target exists
|
|
652
669
|
const existing = yield this.utils.checkExistence(db, model, uniqueFilter);
|
|
653
670
|
if (existing) {
|
|
@@ -688,7 +705,7 @@ class PolicyProxyHandler {
|
|
|
688
705
|
disconnect: (model, args, context) => __awaiter(this, void 0, void 0, function* () { return _connectDisconnect(model, args, context); }),
|
|
689
706
|
set: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
690
707
|
// find the set of items to be replaced
|
|
691
|
-
const reversedQuery =
|
|
708
|
+
const reversedQuery = this.utils.buildReversedQuery(context);
|
|
692
709
|
const findCurrSetArgs = {
|
|
693
710
|
select: this.utils.makeIdSelection(model),
|
|
694
711
|
where: reversedQuery,
|
|
@@ -704,7 +721,7 @@ class PolicyProxyHandler {
|
|
|
704
721
|
}),
|
|
705
722
|
delete: (model, args, context) => __awaiter(this, void 0, void 0, function* () {
|
|
706
723
|
// build a unique query including upstream conditions
|
|
707
|
-
const uniqueFilter =
|
|
724
|
+
const uniqueFilter = this.utils.buildReversedQuery(context);
|
|
708
725
|
// handle not-found
|
|
709
726
|
yield this.utils.checkExistence(db, model, uniqueFilter, true);
|
|
710
727
|
// check delete guard
|
|
@@ -737,9 +754,9 @@ class PolicyProxyHandler {
|
|
|
737
754
|
if (!args.data) {
|
|
738
755
|
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'data field is required in query argument');
|
|
739
756
|
}
|
|
740
|
-
|
|
757
|
+
this.utils.tryReject(this.prisma, this.model, 'update');
|
|
741
758
|
args = this.utils.clone(args);
|
|
742
|
-
|
|
759
|
+
this.utils.injectAuthGuard(this.prisma, args, this.model, 'update');
|
|
743
760
|
if (this.utils.hasAuthGuard(this.model, 'postUpdate') || this.utils.getZodSchema(this.model)) {
|
|
744
761
|
// use a transaction to do post-update checks
|
|
745
762
|
const postWriteChecks = [];
|
|
@@ -751,7 +768,7 @@ class PolicyProxyHandler {
|
|
|
751
768
|
select = Object.assign(Object.assign({}, select), preValueSelect);
|
|
752
769
|
}
|
|
753
770
|
const currentSetQuery = { select, where: args.where };
|
|
754
|
-
|
|
771
|
+
this.utils.injectAuthGuard(tx, currentSetQuery, this.model, 'read');
|
|
755
772
|
if (this.shouldLogQuery) {
|
|
756
773
|
this.logger.info(`[policy] \`findMany\` ${this.model}: ${(0, utils_1.formatObject)(currentSetQuery)}`);
|
|
757
774
|
}
|
|
@@ -792,8 +809,8 @@ class PolicyProxyHandler {
|
|
|
792
809
|
if (!args.update) {
|
|
793
810
|
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'update field is required in query argument');
|
|
794
811
|
}
|
|
795
|
-
|
|
796
|
-
|
|
812
|
+
this.utils.tryReject(this.prisma, this.model, 'create');
|
|
813
|
+
this.utils.tryReject(this.prisma, this.model, 'update');
|
|
797
814
|
args = this.utils.clone(args);
|
|
798
815
|
// We can call the native "upsert" because we can't tell if an entity was created or updated
|
|
799
816
|
// for doing post-write check accordingly. Instead, decompose it into create or update.
|
|
@@ -833,7 +850,7 @@ class PolicyProxyHandler {
|
|
|
833
850
|
if (!args.where) {
|
|
834
851
|
throw (0, utils_1.prismaClientValidationError)(this.prisma, 'where field is required in query argument');
|
|
835
852
|
}
|
|
836
|
-
|
|
853
|
+
this.utils.tryReject(this.prisma, this.model, 'delete');
|
|
837
854
|
const { result, error } = yield this.transaction((tx) => __awaiter(this, void 0, void 0, function* () {
|
|
838
855
|
// do a read-back before delete
|
|
839
856
|
const r = yield this.utils.readBack(tx, this.model, 'delete', args, args.where);
|
|
@@ -860,10 +877,10 @@ class PolicyProxyHandler {
|
|
|
860
877
|
}
|
|
861
878
|
deleteMany(args) {
|
|
862
879
|
return __awaiter(this, void 0, void 0, function* () {
|
|
863
|
-
|
|
880
|
+
this.utils.tryReject(this.prisma, this.model, 'delete');
|
|
864
881
|
// inject policy conditions
|
|
865
882
|
args = args !== null && args !== void 0 ? args : {};
|
|
866
|
-
|
|
883
|
+
this.utils.injectAuthGuard(this.prisma, args, this.model, 'delete');
|
|
867
884
|
// conduct the deletion
|
|
868
885
|
if (this.shouldLogQuery) {
|
|
869
886
|
this.logger.info(`[policy] \`deleteMany\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
@@ -880,7 +897,7 @@ class PolicyProxyHandler {
|
|
|
880
897
|
}
|
|
881
898
|
args = this.utils.clone(args);
|
|
882
899
|
// inject policy conditions
|
|
883
|
-
|
|
900
|
+
this.utils.injectAuthGuard(this.prisma, args, this.model, 'read');
|
|
884
901
|
if (this.shouldLogQuery) {
|
|
885
902
|
this.logger.info(`[policy] \`aggregate\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
886
903
|
}
|
|
@@ -894,7 +911,7 @@ class PolicyProxyHandler {
|
|
|
894
911
|
}
|
|
895
912
|
args = this.utils.clone(args);
|
|
896
913
|
// inject policy conditions
|
|
897
|
-
|
|
914
|
+
this.utils.injectAuthGuard(this.prisma, args, this.model, 'read');
|
|
898
915
|
if (this.shouldLogQuery) {
|
|
899
916
|
this.logger.info(`[policy] \`groupBy\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
900
917
|
}
|
|
@@ -905,7 +922,7 @@ class PolicyProxyHandler {
|
|
|
905
922
|
return __awaiter(this, void 0, void 0, function* () {
|
|
906
923
|
// inject policy conditions
|
|
907
924
|
args = args ? this.utils.clone(args) : {};
|
|
908
|
-
|
|
925
|
+
this.utils.injectAuthGuard(this.prisma, args, this.model, 'read');
|
|
909
926
|
if (this.shouldLogQuery) {
|
|
910
927
|
this.logger.info(`[policy] \`count\` ${this.model}:\n${(0, utils_1.formatObject)(args)}`);
|
|
911
928
|
}
|
|
@@ -975,6 +992,16 @@ class PolicyProxyHandler {
|
|
|
975
992
|
yield Promise.all(postWriteChecks.map(({ model, operation, uniqueFilter, preValue }) => __awaiter(this, void 0, void 0, function* () { return this.utils.checkPolicyForUnique(model, uniqueFilter, operation, db, undefined, preValue); })));
|
|
976
993
|
});
|
|
977
994
|
}
|
|
995
|
+
makeHandler(model) {
|
|
996
|
+
return new PolicyProxyHandler(this.prisma, this.policy, this.modelMeta, this.zodSchemas, model, this.user, this.logPrismaQuery);
|
|
997
|
+
}
|
|
998
|
+
requireBackLink(fieldInfo) {
|
|
999
|
+
const backLinkField = fieldInfo.backLink && (0, model_meta_1.resolveField)(this.modelMeta, fieldInfo.type, fieldInfo.backLink);
|
|
1000
|
+
if (!backLinkField) {
|
|
1001
|
+
throw new Error('Missing back link for field: ' + fieldInfo.name);
|
|
1002
|
+
}
|
|
1003
|
+
return backLinkField;
|
|
1004
|
+
}
|
|
978
1005
|
}
|
|
979
1006
|
exports.PolicyProxyHandler = PolicyProxyHandler;
|
|
980
1007
|
//# sourceMappingURL=handler.js.map
|