@cerebruminc/yates 4.0.0-beta.dangerous.df71802 → 4.0.1

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/index.js CHANGED
@@ -1,4 +1,8 @@
1
1
  "use strict";
2
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
3
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
4
+ return cooked;
5
+ };
2
6
  var __assign = (this && this.__assign) || function () {
3
7
  __assign = Object.assign || function(t) {
4
8
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -10,6 +14,29 @@ var __assign = (this && this.__assign) || function () {
10
14
  };
11
15
  return __assign.apply(this, arguments);
12
16
  };
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
13
40
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
41
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
42
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -46,17 +73,6 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
46
73
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
74
  }
48
75
  };
49
- var __values = (this && this.__values) || function(o) {
50
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
51
- if (m) return m.call(o);
52
- if (o && typeof o.length === "number") return {
53
- next: function () {
54
- if (o && i >= o.length) o = void 0;
55
- return { value: o && o[i++], done: !o };
56
- }
57
- };
58
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
59
- };
60
76
  var __read = (this && this.__read) || function (o, n) {
61
77
  var m = typeof Symbol === "function" && o[Symbol.iterator];
62
78
  if (!m) return o;
@@ -82,17 +98,59 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
82
98
  }
83
99
  return to.concat(ar || Array.prototype.slice.call(from));
84
100
  };
101
+ var __values = (this && this.__values) || function(o) {
102
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
103
+ if (m) return m.call(o);
104
+ if (o && typeof o.length === "number") return {
105
+ next: function () {
106
+ if (o && i >= o.length) o = void 0;
107
+ return { value: o && o[i++], done: !o };
108
+ }
109
+ };
110
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
111
+ };
85
112
  var __importDefault = (this && this.__importDefault) || function (mod) {
86
113
  return (mod && mod.__esModule) ? mod : { "default": mod };
87
114
  };
88
115
  Object.defineProperty(exports, "__esModule", { value: true });
89
- exports.setup = exports.__private = exports.Yates = exports.sanitizeSlug = void 0;
116
+ exports.setup = exports.Yates = exports.sanitizeSlug = void 0;
117
+ var crypto = __importStar(require("crypto"));
90
118
  var debug_1 = __importDefault(require("debug"));
91
119
  var cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
92
120
  var difference_1 = __importDefault(require("lodash/difference"));
93
- var isEqual_1 = __importDefault(require("lodash/isEqual"));
121
+ var flatMap_1 = __importDefault(require("lodash/flatMap"));
122
+ var map_1 = __importDefault(require("lodash/map"));
123
+ var toPairs_1 = __importDefault(require("lodash/toPairs"));
124
+ var expressions_1 = require("./expressions");
94
125
  var VALID_OPERATIONS = ["SELECT", "UPDATE", "INSERT", "DELETE"];
126
+ var SETUP_MANIFEST_VERSION = "1";
127
+ var YATES_VERSION = require("../package.json").version;
95
128
  var debug = (0, debug_1.default)("yates");
129
+ /**
130
+ * This function is used to take a lock that is automatically released at the end of the current transaction.
131
+ * This is very convenient for ensuring we don't hit concurrency issues when running setup code.
132
+ */
133
+ var takeLock = function (prisma) {
134
+ return prisma.$executeRawUnsafe("SELECT pg_advisory_xact_lock(2142616474639426746);");
135
+ };
136
+ var upsertAbility = function (prisma, ability) {
137
+ var ability_model = ability.ability_model, ability_name = ability.ability_name, ability_policy_name = ability.ability_policy_name, ability_description = ability.ability_description, ability_operation = ability.ability_operation, ability_expression = ability.ability_expression;
138
+ return prisma.$queryRaw(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n\t\tINSERT INTO _yates._yates_abilities (ability_model, ability_name, ability_policy_name, ability_description, ability_operation, ability_expression)\n\t\tVALUES (", ", ", ", ", ", ", ", ", ", ", ")\n\t\tON CONFLICT (ability_policy_name) DO UPDATE\n\t\tSET ability_model = EXCLUDED.ability_model, ability_name = EXCLUDED.ability_name, ability_description = EXCLUDED.ability_description, ability_operation = EXCLUDED.ability_operation, ability_expression = EXCLUDED.ability_expression, updated_at = now();\n\t"], ["\n\t\tINSERT INTO _yates._yates_abilities (ability_model, ability_name, ability_policy_name, ability_description, ability_operation, ability_expression)\n\t\tVALUES (", ", ", ", ", ", ", ", ", ", ", ")\n\t\tON CONFLICT (ability_policy_name) DO UPDATE\n\t\tSET ability_model = EXCLUDED.ability_model, ability_name = EXCLUDED.ability_name, ability_description = EXCLUDED.ability_description, ability_operation = EXCLUDED.ability_operation, ability_expression = EXCLUDED.ability_expression, updated_at = now();\n\t"])), ability_model, ability_name, ability_policy_name, ability_description, ability_operation, ability_expression);
139
+ };
140
+ /**
141
+ * In PostgreSQL, the maximum length for a role or policy name is 63 bytes.
142
+ * This limitation is derived from the value of the NAMEDATALEN configuration parameter,
143
+ * which is set to 64 bytes by default. One byte is reserved for the null-terminator,
144
+ * leaving 63 bytes for the actual role name.
145
+ * This function hashes the ability name to ensure it is within the 63 byte limit.
146
+ */
147
+ var hashWithPrefix = function (prefix, abilityName) {
148
+ var hash = crypto.createHash("sha256");
149
+ hash.update(abilityName);
150
+ var hashedAbilityName = hash.digest("hex");
151
+ var maxLength = 63 - prefix.length;
152
+ return prefix + hashedAbilityName.slice(0, maxLength);
153
+ };
96
154
  // Sanitize a single string by ensuring the it has only lowercase alpha characters and underscores
97
155
  var sanitizeSlug = function (slug) {
98
156
  return slug
@@ -101,1155 +159,215 @@ var sanitizeSlug = function (slug) {
101
159
  .replace(/[^a-z0-9_]/gi, "");
102
160
  };
103
161
  exports.sanitizeSlug = sanitizeSlug;
104
- var OPERATION_MAP = {
105
- findUnique: "SELECT",
106
- findUniqueOrThrow: "SELECT",
107
- findFirst: "SELECT",
108
- findFirstOrThrow: "SELECT",
109
- findMany: "SELECT",
110
- count: "SELECT",
111
- aggregate: "SELECT",
112
- groupBy: "SELECT",
113
- create: "INSERT",
114
- createMany: "INSERT",
115
- update: "UPDATE",
116
- updateMany: "UPDATE",
117
- delete: "DELETE",
118
- deleteMany: "DELETE",
119
- upsert: "UPDATE",
120
- };
121
- var UNIQUE_OPERATIONS = new Set([
122
- "findUnique",
123
- "findUniqueOrThrow",
124
- "update",
125
- "delete",
126
- "upsert",
127
- ]);
128
- var SELECT_OPERATIONS = new Set([
129
- "findUnique",
130
- "findUniqueOrThrow",
131
- "findFirst",
132
- "findFirstOrThrow",
133
- "findMany",
134
- "count",
135
- "aggregate",
136
- "groupBy",
137
- ]);
138
- var isPlainObject = function (value) {
139
- return !!value && typeof value === "object" && !Array.isArray(value);
140
- };
141
- var lowerModelName = function (model) {
142
- return model.length ? "".concat(model[0].toLowerCase()).concat(model.slice(1)) : model;
143
- };
144
- var isFieldRef = function (value) {
145
- return isPlainObject(value) &&
146
- typeof value.modelName === "string" &&
147
- typeof value.name === "string";
148
- };
149
- var isEmptyWhere = function (where) {
150
- return !where || (isPlainObject(where) && Object.keys(where).length === 0);
151
- };
152
- var combineAbilityFilters = function (filters) {
153
- if (filters.length === 0)
154
- return null;
155
- if (filters.some(function (filter) { return isEmptyWhere(filter); }))
156
- return {};
157
- if (filters.length === 1)
158
- return filters[0];
159
- return { OR: filters };
160
- };
161
- var mergeWhere = function (base, extra) {
162
- var _a;
163
- if (!extra || isEmptyWhere(extra))
164
- return (_a = base !== null && base !== void 0 ? base : extra) !== null && _a !== void 0 ? _a : undefined;
165
- if (!base || isEmptyWhere(base))
166
- return extra;
167
- return { AND: [base, extra] };
168
- };
169
- var getFluentSelectionField = function (runtimeDataModel, model, args) {
170
- var selection = args.select;
171
- if (!isPlainObject(selection))
172
- return null;
173
- var keys = Object.keys(selection);
174
- if (keys.length !== 1)
175
- return null;
176
- var field = keys[0];
177
- var modelData = runtimeDataModel.models[model];
178
- var fieldData = modelData === null || modelData === void 0 ? void 0 : modelData.fields.find(function (f) { return f.name === field; });
179
- if (!fieldData || fieldData.kind !== "object")
180
- return null;
181
- return field;
182
- };
183
- var getIdField = function (runtimeDataModel, model) {
184
- var _a;
185
- var modelData = runtimeDataModel.models[model];
186
- if (!modelData)
187
- return null;
188
- var idField = modelData.fields.find(function (field) { return field.isId; });
189
- return (_a = idField === null || idField === void 0 ? void 0 : idField.name) !== null && _a !== void 0 ? _a : null;
190
- };
191
- var denyWhere = function (runtimeDataModel, model) {
192
- var _a;
193
- var idField = getIdField(runtimeDataModel, model);
194
- if (idField) {
195
- return _a = {},
196
- _a[idField] = {
197
- in: [],
198
- },
199
- _a;
200
- }
201
- throw new Error("Model \"".concat(model, "\" has no @id field. Yates requires an ID to safely deny queries."));
202
- };
203
- var validateContext = function (context) {
204
- var e_1, _a, e_2, _b;
205
- if (!context)
206
- return;
207
- try {
208
- for (var _c = __values(Object.keys(context)), _d = _c.next(); !_d.done; _d = _c.next()) {
209
- var key = _d.value;
210
- if (!key.match(/^[a-z_\.]+$/)) {
211
- throw new Error("Context variable \"".concat(key, "\" contains invalid characters. Context variables must only contain lowercase letters, numbers, periods and underscores."));
162
+ var Yates = /** @class */ (function () {
163
+ function Yates(prisma) {
164
+ var _this = this;
165
+ this.prisma = prisma;
166
+ this.databaseScope = null;
167
+ this.init = function () { return __awaiter(_this, void 0, void 0, function () {
168
+ return __generator(this, function (_a) {
169
+ switch (_a.label) {
170
+ case 0: return [4 /*yield*/, this.ensureDatabaseScope()];
171
+ case 1:
172
+ _a.sent();
173
+ debug("Setting up ability table");
174
+ return [4 /*yield*/, this.setupAbilityTable()];
175
+ case 2:
176
+ _a.sent();
177
+ return [2 /*return*/];
178
+ }
179
+ });
180
+ }); };
181
+ this.createDatabaseScope = function (databaseName) {
182
+ var sanitizedName = (0, exports.sanitizeSlug)(databaseName);
183
+ if (sanitizedName.length > 0) {
184
+ return sanitizedName;
212
185
  }
213
- var value = context[key];
214
- if (typeof value !== "number" &&
215
- typeof value !== "string" &&
216
- !Array.isArray(value)) {
217
- throw new Error("Context variable \"".concat(key, "\" must be a string, number or array. Got ").concat(typeof value));
186
+ var hash = crypto.createHash("sha256");
187
+ hash.update(databaseName);
188
+ return hash.digest("hex").slice(0, 8);
189
+ };
190
+ this.getDatabaseScope = function () {
191
+ if (!_this.databaseScope) {
192
+ throw new Error("Yates database scope has not been initialised. Ensure setup() has been called before using the client.");
218
193
  }
219
- if (Array.isArray(value)) {
220
- try {
221
- for (var _e = (e_2 = void 0, __values(value)), _f = _e.next(); !_f.done; _f = _e.next()) {
222
- var entry = _f.value;
223
- if (typeof entry !== "string") {
224
- throw new Error("Context variable \"".concat(key, "\" must be an array of strings. Got ").concat(typeof entry));
194
+ return _this.databaseScope;
195
+ };
196
+ this.ensureDatabaseScope = function () { return __awaiter(_this, void 0, void 0, function () {
197
+ var result, currentDatabase;
198
+ var _a;
199
+ return __generator(this, function (_b) {
200
+ switch (_b.label) {
201
+ case 0:
202
+ if (this.databaseScope) {
203
+ return [2 /*return*/, this.databaseScope];
225
204
  }
226
- }
205
+ return [4 /*yield*/, this.prisma.$queryRawUnsafe("select current_database() as current_database;")];
206
+ case 1:
207
+ result = _b.sent();
208
+ currentDatabase = (_a = result[0]) === null || _a === void 0 ? void 0 : _a.current_database;
209
+ debug("Current database for Yates:", currentDatabase);
210
+ if (!currentDatabase) {
211
+ throw new Error("Failed to determine the current database for scoping Yates roles.");
212
+ }
213
+ this.databaseScope = this.createDatabaseScope(currentDatabase);
214
+ return [2 /*return*/, this.databaseScope];
227
215
  }
228
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
229
- finally {
230
- try {
231
- if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
232
- }
233
- finally { if (e_2) throw e_2.error; }
216
+ });
217
+ }); };
218
+ /*
219
+ * This function creates a table used to track the abilities that have been
220
+ * defined in the system. We can use this to see if an ability needs to be updated.
221
+ * We can't look up the pg policy table for this, as pg performs formatting on
222
+ * the expression, making it very hard to check if the two expressions are equivalent.
223
+ *
224
+ * We also need to create a schema for this table, as we don't want to pollute the public schema.
225
+ * If we use the public schema, we could potentially conflict with a user's table and we will
226
+ * also cause issues for Prisma's migrate tooling, as it will detect a DB drift.
227
+ */
228
+ this.setupAbilityTable = function () {
229
+ return _this.prisma.$transaction([
230
+ takeLock(_this.prisma),
231
+ _this.prisma.$executeRawUnsafe("\n\t\t\t\tCREATE SCHEMA IF NOT EXISTS _yates;\n\t\t\t"),
232
+ _this.prisma.$executeRawUnsafe("\n\t\t\t\tCREATE TABLE IF NOT EXISTS _yates._yates_abilities (\n\t\t\t\t\tid SERIAL PRIMARY KEY,\n\t\t\t\t\tability_model TEXT NOT NULL,\n\t\t\t\t\tability_name TEXT NOT NULL,\n\t\t\t\t\tability_policy_name TEXT NOT NULL UNIQUE,\n\t\t\t\t\tability_description TEXT NOT NULL,\n\t\t\t\t\tability_operation TEXT NOT NULL,\n\t\t\t\t\tability_expression TEXT NOT NULL,\n\t\t\t\t\tcreated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n\t\t\t\t\tupdated_at TIMESTAMP\n\t\t\t\t);\n\t\t\t"),
233
+ _this.prisma.$executeRawUnsafe("\n\t\t\t\tCREATE TABLE IF NOT EXISTS _yates._yates_schema_syncs (\n\t\t\t\t\tid TEXT PRIMARY KEY,\n\t\t\t\t\tmanifest_hash TEXT NOT NULL,\n\t\t\t\t\tmanifest_version TEXT,\n\t\t\t\t\tyates_version TEXT,\n\t\t\t\t\tapp_name TEXT,\n\t\t\t\t\tapplied_at TIMESTAMPTZ NOT NULL DEFAULT now()\n\t\t\t\t);\n\t\t\t"),
234
+ _this.prisma.$executeRawUnsafe("\n\t\t\t\tDO $$\n\t\t\t\tBEGIN\n\t\t\t\t\tIF EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM information_schema.columns\n\t\t\t\t\t\tWHERE table_schema = '_yates'\n\t\t\t\t\t\tAND table_name = '_yates_schema_syncs'\n\t\t\t\t\t\tAND column_name = 'yates_version'\n\t\t\t\t\t) AND NOT EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM information_schema.columns\n\t\t\t\t\t\tWHERE table_schema = '_yates'\n\t\t\t\t\t\tAND table_name = '_yates_schema_syncs'\n\t\t\t\t\t\tAND column_name = 'manifest_version'\n\t\t\t\t\t) THEN\n\t\t\t\t\t\tALTER TABLE _yates._yates_schema_syncs RENAME COLUMN yates_version TO manifest_version;\n\t\t\t\t\tELSIF NOT EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM information_schema.columns\n\t\t\t\t\t\tWHERE table_schema = '_yates'\n\t\t\t\t\t\tAND table_name = '_yates_schema_syncs'\n\t\t\t\t\t\tAND column_name = 'manifest_version'\n\t\t\t\t\t) THEN\n\t\t\t\t\t\tALTER TABLE _yates._yates_schema_syncs ADD COLUMN manifest_version TEXT;\n\t\t\t\t\tEND IF;\n\n\t\t\t\t\tIF NOT EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM information_schema.columns\n\t\t\t\t\t\tWHERE table_schema = '_yates'\n\t\t\t\t\t\tAND table_name = '_yates_schema_syncs'\n\t\t\t\t\t\tAND column_name = 'yates_version'\n\t\t\t\t\t) THEN\n\t\t\t\t\t\tALTER TABLE _yates._yates_schema_syncs ADD COLUMN yates_version TEXT;\n\t\t\t\t\tEND IF;\n\t\t\t\tEND\n\t\t\t\t$$;\n\t\t\t"),
235
+ ]);
236
+ };
237
+ this.createAbilityName = function (model, ability) {
238
+ var scope = _this.getDatabaseScope();
239
+ return (0, exports.sanitizeSlug)(hashWithPrefix("yates_ability_", "".concat(scope, "_").concat(model, "_").concat(ability)));
240
+ };
241
+ this.createRoleName = function (name) {
242
+ var scope = _this.getDatabaseScope();
243
+ return (0, exports.sanitizeSlug)(hashWithPrefix("yates_role_", "".concat(scope, "_").concat(name)));
244
+ };
245
+ this.quoteIdentifier = function (identifier) {
246
+ return "\"".concat(identifier.replace(/"/g, '""'), "\"");
247
+ };
248
+ this.enableRowLevelSecurityIfNeeded = function (prisma, table) { return __awaiter(_this, void 0, void 0, function () {
249
+ var rlsState;
250
+ var _a;
251
+ return __generator(this, function (_b) {
252
+ switch (_b.label) {
253
+ case 0: return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\tSELECT c.relrowsecurity\n\t\t\t\tFROM pg_catalog.pg_class c\n\t\t\t\tJOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n\t\t\t\tWHERE n.nspname = 'public'\n\t\t\t\tAND c.relname = $1\n\t\t\t\tAND c.relkind IN ('r', 'p')\n\t\t\t\tLIMIT 1;\n\t\t\t", table)];
254
+ case 1:
255
+ rlsState = _b.sent();
256
+ if ((_a = rlsState[0]) === null || _a === void 0 ? void 0 : _a.relrowsecurity) {
257
+ debug("Row level security already enabled for", table);
258
+ return [2 /*return*/];
259
+ }
260
+ debug("Enabling row level security for", table);
261
+ return [4 /*yield*/, prisma.$executeRawUnsafe("ALTER table ".concat(this.quoteIdentifier("public"), ".").concat(this.quoteIdentifier(table), " enable row level security;"))];
262
+ case 2:
263
+ _b.sent();
264
+ return [2 /*return*/];
234
265
  }
235
- }
236
- }
237
- }
238
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
239
- finally {
240
- try {
241
- if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
242
- }
243
- finally { if (e_1) throw e_1.error; }
244
- }
245
- };
246
- var permissionError = function (model, operation) {
247
- return new Error("You do not have permission to perform this action: ".concat(model, ".").concat(operation, "(...)"));
248
- };
249
- var updateNotFoundError = function () { return new Error("Record to update not found"); };
250
- var deleteNotFoundError = function () { return new Error("Record to delete does not exist"); };
251
- var matchesScalarFilter = function (value, filter, data) {
252
- if (!isPlainObject(filter)) {
253
- if (isFieldRef(filter)) {
254
- return value === data[filter.name];
255
- }
256
- return value === filter;
257
- }
258
- if ("equals" in filter) {
259
- var target = filter.equals;
260
- if (isFieldRef(target)) {
261
- return value === data[target.name];
262
- }
263
- return value === target;
264
- }
265
- if ("in" in filter) {
266
- return Array.isArray(filter.in) && filter.in.includes(value);
267
- }
268
- if ("notIn" in filter) {
269
- return Array.isArray(filter.notIn) && !filter.notIn.includes(value);
270
- }
271
- if ("lt" in filter)
272
- return value < filter.lt;
273
- if ("lte" in filter)
274
- return value <= filter.lte;
275
- if ("gt" in filter)
276
- return value > filter.gt;
277
- if ("gte" in filter)
278
- return value >= filter.gte;
279
- if ("contains" in filter)
280
- return typeof value === "string" && value.includes(filter.contains);
281
- if ("startsWith" in filter)
282
- return typeof value === "string" && value.startsWith(filter.startsWith);
283
- if ("endsWith" in filter)
284
- return typeof value === "string" && value.endsWith(filter.endsWith);
285
- if ("not" in filter)
286
- return !matchesScalarFilter(value, filter.not, data);
287
- return value === filter;
288
- };
289
- var getRelationConstraints = function (data, fieldData) {
290
- var e_3, _a;
291
- var _b, _c;
292
- var constraints = [];
293
- var relationInput = data[fieldData.name];
294
- if (isPlainObject(relationInput)) {
295
- var connect = relationInput.connect;
296
- if (connect) {
297
- var items = Array.isArray(connect) ? connect : [connect];
266
+ });
267
+ }); };
268
+ this.createSetupManifestHash = function (manifest) {
269
+ var normalizedManifest = {
270
+ abilities: __spreadArray([], __read(manifest.abilities), false).sort(function (a, b) {
271
+ return "".concat(a.model, ":").concat(a.slug, ":").concat(a.operation, ":").concat(a.policyName).localeCompare("".concat(b.model, ":").concat(b.slug, ":").concat(b.operation, ":").concat(b.policyName));
272
+ }),
273
+ databaseScope: manifest.databaseScope,
274
+ roles: __spreadArray([], __read(manifest.roles), false).map(function (role) { return (__assign(__assign({}, role), { grants: Array.isArray(role.grants)
275
+ ? __spreadArray([], __read(role.grants), false).sort()
276
+ : role.grants })); })
277
+ .sort(function (a, b) { return a.roleName.localeCompare(b.roleName); }),
278
+ version: SETUP_MANIFEST_VERSION,
279
+ };
280
+ var hash = crypto.createHash("sha256");
281
+ hash.update(JSON.stringify(normalizedManifest));
282
+ return hash.digest("hex");
283
+ };
284
+ this.createSetupManifest = function (abilities, roles) {
285
+ var e_1, _a, e_2, _b;
286
+ var _c, _d;
287
+ var manifestAbilities = [];
298
288
  try {
299
- for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
300
- var item = items_1_1.value;
301
- if (isPlainObject(item)) {
302
- constraints.push(item);
289
+ for (var _e = __values(Object.keys(abilities).sort()), _f = _e.next(); !_f.done; _f = _e.next()) {
290
+ var model = _f.value;
291
+ var modelAbilities = abilities[model];
292
+ if (!modelAbilities)
293
+ continue;
294
+ try {
295
+ for (var _g = (e_2 = void 0, __values(Object.keys(modelAbilities).sort())), _h = _g.next(); !_h.done; _h = _g.next()) {
296
+ var slug = _h.value;
297
+ var ability = modelAbilities[slug];
298
+ if (!ability)
299
+ continue;
300
+ manifestAbilities.push({
301
+ expression: (_d = (_c = ability.expression) === null || _c === void 0 ? void 0 : _c.toString()) !== null && _d !== void 0 ? _d : null,
302
+ model: model,
303
+ operation: ability.operation,
304
+ policyName: _this.createAbilityName(model, slug),
305
+ slug: slug,
306
+ });
307
+ }
308
+ }
309
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
310
+ finally {
311
+ try {
312
+ if (_h && !_h.done && (_b = _g.return)) _b.call(_g);
313
+ }
314
+ finally { if (e_2) throw e_2.error; }
303
315
  }
304
316
  }
305
317
  }
306
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
318
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
307
319
  finally {
308
320
  try {
309
- if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
321
+ if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
310
322
  }
311
- finally { if (e_3) throw e_3.error; }
323
+ finally { if (e_1) throw e_1.error; }
312
324
  }
313
- }
314
- }
315
- var fromFields = (_b = fieldData.relationFromFields) !== null && _b !== void 0 ? _b : [];
316
- var toFields = (_c = fieldData.relationToFields) !== null && _c !== void 0 ? _c : [];
317
- if (fromFields.length > 0) {
318
- var hasAll = fromFields.every(function (field) { return data[field] !== undefined && data[field] !== null; });
319
- if (hasAll) {
320
- var where_1 = {};
321
- fromFields.forEach(function (fromField, index) {
322
- var _a;
323
- var toField = (_a = toFields[index]) !== null && _a !== void 0 ? _a : fromField;
324
- where_1[toField] = data[fromField];
325
- });
326
- constraints.push(where_1);
327
- }
328
- }
329
- return constraints.length > 0 ? constraints : null;
330
- };
331
- var matchesRelationFilter = function (prisma, runtimeDataModel, fieldData, data, condition) { return __awaiter(void 0, void 0, void 0, function () {
332
- var relatedModel, constraints, relationInput, hasIs, hasIsNot, relationWhere_1, isNegated, constraintWhere_1, combinedWhere_1, delegate_1, record, hasSome, hasEvery, hasNone, operator, relationWhere, constraintWhere, combinedWhere, delegate, record, record, results;
333
- var _a, _b, _c, _d;
334
- var _e, _f, _g, _h, _j, _k, _l, _m;
335
- return __generator(this, function (_o) {
336
- switch (_o.label) {
337
- case 0:
338
- relatedModel = fieldData.type;
339
- constraints = (_e = getRelationConstraints(data, fieldData)) !== null && _e !== void 0 ? _e : [];
340
- relationInput = isPlainObject(condition) ? condition : {};
341
- if (!!fieldData.isList) return [3 /*break*/, 2];
342
- hasIs = isPlainObject(condition) && "is" in condition;
343
- hasIsNot = isPlainObject(condition) && "isNot" in condition;
344
- relationWhere_1 = hasIs
345
- ? relationInput.is
346
- : hasIsNot
347
- ? relationInput.isNot
348
- : condition;
349
- isNegated = hasIsNot;
350
- if (relationWhere_1 === null) {
351
- return [2 /*return*/, isNegated ? constraints.length > 0 : constraints.length === 0];
352
- }
353
- if (constraints.length === 0)
354
- return [2 /*return*/, false];
355
- constraintWhere_1 = constraints.length === 1 ? constraints[0] : { OR: constraints };
356
- combinedWhere_1 = (_f = mergeWhere(relationWhere_1 !== null && relationWhere_1 !== void 0 ? relationWhere_1 : {}, constraintWhere_1)) !== null && _f !== void 0 ? _f : constraintWhere_1;
357
- delegate_1 = prisma[lowerModelName(relatedModel)];
358
- return [4 /*yield*/, delegate_1.findFirst({
359
- where: combinedWhere_1,
360
- select: (_a = {}, _a[(_g = getIdField(runtimeDataModel, relatedModel)) !== null && _g !== void 0 ? _g : "id"] = true, _a),
361
- })];
362
- case 1:
363
- record = _o.sent();
364
- return [2 /*return*/, isNegated ? !record : !!record];
365
- case 2:
366
- hasSome = isPlainObject(condition) && "some" in condition;
367
- hasEvery = isPlainObject(condition) && "every" in condition;
368
- hasNone = isPlainObject(condition) && "none" in condition;
369
- operator = hasEvery ? "every" : hasNone ? "none" : "some";
370
- relationWhere = (_h = relationInput[operator]) !== null && _h !== void 0 ? _h : condition;
371
- if (constraints.length === 0) {
372
- if (operator === "none")
373
- return [2 /*return*/, true];
374
- if (operator === "every")
375
- return [2 /*return*/, true];
376
- return [2 /*return*/, false];
377
- }
378
- constraintWhere = constraints.length === 1 ? constraints[0] : { OR: constraints };
379
- combinedWhere = (_j = mergeWhere(relationWhere !== null && relationWhere !== void 0 ? relationWhere : {}, constraintWhere)) !== null && _j !== void 0 ? _j : constraintWhere;
380
- delegate = prisma[lowerModelName(relatedModel)];
381
- if (!(operator === "some")) return [3 /*break*/, 4];
382
- return [4 /*yield*/, delegate.findFirst({
383
- where: combinedWhere,
384
- select: (_b = {}, _b[(_k = getIdField(runtimeDataModel, relatedModel)) !== null && _k !== void 0 ? _k : "id"] = true, _b),
385
- })];
386
- case 3:
387
- record = _o.sent();
388
- return [2 /*return*/, !!record];
389
- case 4:
390
- if (!(operator === "none")) return [3 /*break*/, 6];
391
- return [4 /*yield*/, delegate.findFirst({
392
- where: combinedWhere,
393
- select: (_c = {}, _c[(_l = getIdField(runtimeDataModel, relatedModel)) !== null && _l !== void 0 ? _l : "id"] = true, _c),
394
- })];
395
- case 5:
396
- record = _o.sent();
397
- return [2 /*return*/, !record];
398
- case 6: return [4 /*yield*/, delegate.findMany({
399
- where: combinedWhere,
400
- select: (_d = {}, _d[(_m = getIdField(runtimeDataModel, relatedModel)) !== null && _m !== void 0 ? _m : "id"] = true, _d),
401
- })];
402
- case 7:
403
- results = _o.sent();
404
- return [2 /*return*/, results.length === constraints.length];
405
- }
406
- });
407
- }); };
408
- var matchesCreateWhere = function (prisma, runtimeDataModel, model, data, where) { return __awaiter(void 0, void 0, void 0, function () {
409
- var clauses, checks, clauses, checks, clauses, checks, _loop_1, _a, _b, _c, field, condition, state_1, e_4_1;
410
- var e_4, _d;
411
- return __generator(this, function (_e) {
412
- switch (_e.label) {
413
- case 0:
414
- if (!where.AND) return [3 /*break*/, 2];
415
- clauses = Array.isArray(where.AND) ? where.AND : [where.AND];
416
- return [4 /*yield*/, Promise.all(clauses.map(function (clause) {
417
- return matchesCreateWhere(prisma, runtimeDataModel, model, data, clause);
418
- }))];
419
- case 1:
420
- checks = _e.sent();
421
- if (!checks.every(Boolean))
422
- return [2 /*return*/, false];
423
- _e.label = 2;
424
- case 2:
425
- if (!where.OR) return [3 /*break*/, 4];
426
- clauses = Array.isArray(where.OR) ? where.OR : [where.OR];
427
- return [4 /*yield*/, Promise.all(clauses.map(function (clause) {
428
- return matchesCreateWhere(prisma, runtimeDataModel, model, data, clause);
429
- }))];
430
- case 3:
431
- checks = _e.sent();
432
- if (!checks.some(Boolean))
433
- return [2 /*return*/, false];
434
- _e.label = 4;
435
- case 4:
436
- if (!where.NOT) return [3 /*break*/, 6];
437
- clauses = Array.isArray(where.NOT) ? where.NOT : [where.NOT];
438
- return [4 /*yield*/, Promise.all(clauses.map(function (clause) {
439
- return matchesCreateWhere(prisma, runtimeDataModel, model, data, clause);
440
- }))];
441
- case 5:
442
- checks = _e.sent();
443
- if (checks.some(Boolean))
444
- return [2 /*return*/, false];
445
- _e.label = 6;
446
- case 6:
447
- _loop_1 = function (field, condition) {
448
- var modelData, fieldData, ok, value;
449
- return __generator(this, function (_f) {
450
- switch (_f.label) {
451
- case 0:
452
- if (field === "AND" || field === "OR" || field === "NOT")
453
- return [2 /*return*/, "continue"];
454
- modelData = runtimeDataModel.models[model];
455
- fieldData = modelData === null || modelData === void 0 ? void 0 : modelData.fields.find(function (f) { return f.name === field; });
456
- if (!fieldData)
457
- return [2 /*return*/, "continue"];
458
- if (!(fieldData.kind === "object")) return [3 /*break*/, 2];
459
- return [4 /*yield*/, matchesRelationFilter(prisma, runtimeDataModel, fieldData, data, condition)];
460
- case 1:
461
- ok = _f.sent();
462
- if (!ok)
463
- return [2 /*return*/, { value: false }];
464
- return [2 /*return*/, "continue"];
465
- case 2:
466
- value = data[field];
467
- if (!matchesScalarFilter(value, condition, data))
468
- return [2 /*return*/, { value: false }];
469
- return [2 /*return*/];
470
- }
471
- });
472
- };
473
- _e.label = 7;
474
- case 7:
475
- _e.trys.push([7, 12, 13, 14]);
476
- _a = __values(Object.entries(where)), _b = _a.next();
477
- _e.label = 8;
478
- case 8:
479
- if (!!_b.done) return [3 /*break*/, 11];
480
- _c = __read(_b.value, 2), field = _c[0], condition = _c[1];
481
- return [5 /*yield**/, _loop_1(field, condition)];
482
- case 9:
483
- state_1 = _e.sent();
484
- if (typeof state_1 === "object")
485
- return [2 /*return*/, state_1.value];
486
- _e.label = 10;
487
- case 10:
488
- _b = _a.next();
489
- return [3 /*break*/, 8];
490
- case 11: return [3 /*break*/, 14];
491
- case 12:
492
- e_4_1 = _e.sent();
493
- e_4 = { error: e_4_1 };
494
- return [3 /*break*/, 14];
495
- case 13:
496
- try {
497
- if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
498
- }
499
- finally { if (e_4) throw e_4.error; }
500
- return [7 /*endfinally*/];
501
- case 14: return [2 /*return*/, true];
502
- }
503
- });
504
- }); };
505
- var extractModelFields = function (runtimeDataModel, model) {
506
- var _a;
507
- var modelData = runtimeDataModel.models[model];
508
- return (_a = modelData === null || modelData === void 0 ? void 0 : modelData.fields) !== null && _a !== void 0 ? _a : [];
509
- };
510
- var buildRowHelper = function (prisma, runtimeDataModel, model) {
511
- return (function (col) {
512
- var _a;
513
- var modelData = runtimeDataModel.models[model];
514
- if (!modelData) {
515
- throw new Error("Could not retrieve model data for '".concat(model, "'"));
516
- }
517
- var fieldData = modelData.fields.find(function (field) { return field.name === col; });
518
- if (!fieldData) {
519
- throw new Error("Could not retrieve field data from Prisma Client for field '".concat(model, ".").concat(col, "'"));
520
- }
521
- var delegate = prisma[lowerModelName(model)];
522
- var fieldRef = (_a = delegate === null || delegate === void 0 ? void 0 : delegate.fields) === null || _a === void 0 ? void 0 : _a[col];
523
- if (!fieldRef) {
524
- throw new Error("Could not resolve field reference for '".concat(model, ".").concat(col, "'"));
525
- }
526
- return fieldRef;
527
- });
528
- };
529
- var buildContextHelper = function (context) {
530
- return (function (key) {
531
- return context ? context[key] : undefined;
532
- });
533
- };
534
- var resolveExpression = function (prisma, runtimeDataModel, model, expression, context) { return __awaiter(void 0, void 0, void 0, function () {
535
- var row, ctx;
536
- return __generator(this, function (_a) {
537
- switch (_a.label) {
538
- case 0:
539
- if (!expression)
540
- return [2 /*return*/, {}];
541
- if (typeof expression !== "function")
542
- return [2 /*return*/, expression];
543
- row = buildRowHelper(prisma, runtimeDataModel, model);
544
- ctx = buildContextHelper(context);
545
- return [4 /*yield*/, expression(prisma, row, ctx)];
546
- case 1: return [2 /*return*/, (_a.sent())];
547
- }
548
- });
549
- }); };
550
- var dedupeAbilityList = function (abilityList) {
551
- var seen = new Set();
552
- return abilityList.filter(function (ability) {
553
- if (seen.has(ability)) {
554
- return false;
555
- }
556
- seen.add(ability);
557
- return true;
558
- });
559
- };
560
- var buildRoleAbilities = function (roles, allAbilities) {
561
- var e_5, _a;
562
- var roleAbilities = {};
563
- try {
564
- for (var _b = __values(Object.entries(roles)), _c = _b.next(); !_c.done; _c = _b.next()) {
565
- var _d = __read(_c.value, 2), role = _d[0], abilities = _d[1];
566
- var abilityList = abilities === "*"
567
- ? allAbilities
568
- : abilities;
569
- roleAbilities[role] = dedupeAbilityList(abilityList);
570
- }
571
- }
572
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
573
- finally {
574
- try {
575
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
576
- }
577
- finally { if (e_5) throw e_5.error; }
578
- }
579
- return roleAbilities;
580
- };
581
- var getAbilityFilters = function (prisma, runtimeDataModel, roleAbilities, role, model, operation, context) { return __awaiter(void 0, void 0, void 0, function () {
582
- var abilities, relevant;
583
- return __generator(this, function (_a) {
584
- abilities = roleAbilities[role] || [];
585
- relevant = abilities.filter(function (ability) { return ability.model === model && ability.operation === operation; });
586
- if (relevant.length === 0) {
587
- return [2 /*return*/, []];
588
- }
589
- return [2 /*return*/, Promise.all(relevant.map(function (ability) {
590
- return resolveExpression(prisma, runtimeDataModel, model, ability.expression, context);
591
- }))];
592
- });
593
- }); };
594
- var applyReadSelections = function (prisma, runtimeDataModel, roleAbilities, role, model, args, context) { return __awaiter(void 0, void 0, void 0, function () {
595
- var _a, _b, key, selection, _loop_2, _c, _d, _e, field, value, e_6_1, e_7_1;
596
- var e_7, _f, e_6, _g;
597
- var _h;
598
- return __generator(this, function (_j) {
599
- switch (_j.label) {
600
- case 0:
601
- _j.trys.push([0, 11, 12, 13]);
602
- _a = __values(["include", "select"]), _b = _a.next();
603
- _j.label = 1;
604
- case 1:
605
- if (!!_b.done) return [3 /*break*/, 10];
606
- key = _b.value;
607
- selection = args[key];
608
- if (!selection || !isPlainObject(selection))
609
- return [3 /*break*/, 9];
610
- _loop_2 = function (field, value) {
611
- var fields, fieldMeta, relatedModel, abilityFilters, abilityWhere, nextArgs;
612
- return __generator(this, function (_k) {
613
- switch (_k.label) {
614
- case 0:
615
- fields = extractModelFields(runtimeDataModel, model);
616
- fieldMeta = fields.find(function (f) { return f.name === field; });
617
- if (!fieldMeta || fieldMeta.kind !== "object")
618
- return [2 /*return*/, "continue"];
619
- relatedModel = fieldMeta.type;
620
- return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, relatedModel, "SELECT", context)];
621
- case 1:
622
- abilityFilters = _k.sent();
623
- if (!abilityFilters || abilityFilters.length === 0) {
624
- selection[field] = false;
625
- return [2 /*return*/, "continue"];
626
- }
627
- abilityWhere = combineAbilityFilters(abilityFilters);
628
- nextArgs = value === true ? {} : __assign({}, value);
629
- if (fieldMeta.isList) {
630
- nextArgs.where =
631
- (_h = mergeWhere(nextArgs.where, abilityWhere)) !== null && _h !== void 0 ? _h : nextArgs.where;
632
- }
633
- return [4 /*yield*/, applyReadSelections(prisma, runtimeDataModel, roleAbilities, role, relatedModel, nextArgs, context)];
634
- case 2:
635
- _k.sent();
636
- selection[field] = nextArgs;
637
- return [2 /*return*/];
325
+ var manifestRoles = Object.keys(roles)
326
+ .sort()
327
+ .map(function (roleName) {
328
+ var roleAbilities = roles[roleName];
329
+ var grants = Array.isArray(roleAbilities)
330
+ ? roleAbilities.map(function (ability) {
331
+ if (!ability.model || !ability.slug) {
332
+ throw new Error("Ability for role ".concat(roleName, " is missing model or slug"));
638
333
  }
639
- });
640
- };
641
- _j.label = 2;
642
- case 2:
643
- _j.trys.push([2, 7, 8, 9]);
644
- _c = (e_6 = void 0, __values(Object.entries(selection))), _d = _c.next();
645
- _j.label = 3;
646
- case 3:
647
- if (!!_d.done) return [3 /*break*/, 6];
648
- _e = __read(_d.value, 2), field = _e[0], value = _e[1];
649
- return [5 /*yield**/, _loop_2(field, value)];
650
- case 4:
651
- _j.sent();
652
- _j.label = 5;
653
- case 5:
654
- _d = _c.next();
655
- return [3 /*break*/, 3];
656
- case 6: return [3 /*break*/, 9];
657
- case 7:
658
- e_6_1 = _j.sent();
659
- e_6 = { error: e_6_1 };
660
- return [3 /*break*/, 9];
661
- case 8:
662
- try {
663
- if (_d && !_d.done && (_g = _c.return)) _g.call(_c);
664
- }
665
- finally { if (e_6) throw e_6.error; }
666
- return [7 /*endfinally*/];
667
- case 9:
668
- _b = _a.next();
669
- return [3 /*break*/, 1];
670
- case 10: return [3 /*break*/, 13];
671
- case 11:
672
- e_7_1 = _j.sent();
673
- e_7 = { error: e_7_1 };
674
- return [3 /*break*/, 13];
675
- case 12:
676
- try {
677
- if (_b && !_b.done && (_f = _a.return)) _f.call(_a);
678
- }
679
- finally { if (e_7) throw e_7.error; }
680
- return [7 /*endfinally*/];
681
- case 13: return [2 /*return*/];
682
- }
683
- });
684
- }); };
685
- var assertCreateAllowed = function (prisma, runtimeDataModel, roleAbilities, role, model, data, context) { return __awaiter(void 0, void 0, void 0, function () {
686
- var abilityFilters, abilityWhere;
687
- var _a;
688
- return __generator(this, function (_b) {
689
- switch (_b.label) {
690
- case 0: return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, model, "INSERT", context)];
691
- case 1:
692
- abilityFilters = (_a = (_b.sent())) !== null && _a !== void 0 ? _a : [];
693
- abilityWhere = combineAbilityFilters(abilityFilters);
694
- if (!abilityWhere) {
695
- throw permissionError(model, "create");
696
- }
697
- if (isEmptyWhere(abilityWhere))
698
- return [2 /*return*/];
699
- return [4 /*yield*/, matchesCreateWhere(prisma, runtimeDataModel, model, data, abilityWhere)];
700
- case 2:
701
- if (!(_b.sent())) {
702
- throw permissionError(model, "create");
703
- }
704
- return [2 /*return*/];
705
- }
706
- });
707
- }); };
708
- var assertRecordAllowed = function (prisma, runtimeDataModel, roleAbilities, role, model, operation, where, context) { return __awaiter(void 0, void 0, void 0, function () {
709
- var abilityFilters, abilityWhere, combinedWhere, delegate, record;
710
- var _a;
711
- var _b, _c, _d;
712
- return __generator(this, function (_e) {
713
- switch (_e.label) {
714
- case 0: return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, model, operation, context)];
715
- case 1:
716
- abilityFilters = (_b = (_e.sent())) !== null && _b !== void 0 ? _b : [];
717
- abilityWhere = combineAbilityFilters(abilityFilters);
718
- if (!abilityWhere) {
719
- return [2 /*return*/, false];
720
- }
721
- combinedWhere = (_c = mergeWhere(where, abilityWhere)) !== null && _c !== void 0 ? _c : where;
722
- delegate = prisma[lowerModelName(model)];
723
- return [4 /*yield*/, delegate.findFirst({
724
- where: combinedWhere,
725
- select: (_a = {}, _a[(_d = getIdField(runtimeDataModel, model)) !== null && _d !== void 0 ? _d : "id"] = true, _a),
726
- })];
727
- case 2:
728
- record = _e.sent();
729
- return [2 /*return*/, !!record];
730
- }
731
- });
732
- }); };
733
- var assertConnectStyleTargetsAllowed = function (prisma, runtimeDataModel, roleAbilities, role, model, targetInput, context) { return __awaiter(void 0, void 0, void 0, function () {
734
- var items, abilityFilters, abilityWhere, uniqueItems, _loop_3, items_2, items_2_1, item, delegate, combinedWhere, matchedCount;
735
- var e_8, _a;
736
- var _b, _c;
737
- return __generator(this, function (_d) {
738
- switch (_d.label) {
739
- case 0:
740
- items = (Array.isArray(targetInput) ? targetInput : [targetInput]).filter(function (item) {
741
- return isPlainObject(item) && !isEmptyWhere(item);
742
- });
743
- if (items.length === 0)
744
- return [2 /*return*/];
745
- return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, model, "UPDATE", context)];
746
- case 1:
747
- abilityFilters = (_b = (_d.sent())) !== null && _b !== void 0 ? _b : [];
748
- abilityWhere = combineAbilityFilters(abilityFilters);
749
- if (!abilityWhere) {
750
- throw updateNotFoundError();
751
- }
752
- if (isEmptyWhere(abilityWhere))
753
- return [2 /*return*/];
754
- uniqueItems = [];
755
- _loop_3 = function (item) {
756
- if (!uniqueItems.some(function (candidate) { return (0, isEqual_1.default)(candidate, item); })) {
757
- uniqueItems.push(item);
758
- }
759
- };
760
- try {
761
- for (items_2 = __values(items), items_2_1 = items_2.next(); !items_2_1.done; items_2_1 = items_2.next()) {
762
- item = items_2_1.value;
763
- _loop_3(item);
764
- }
765
- }
766
- catch (e_8_1) { e_8 = { error: e_8_1 }; }
767
- finally {
768
- try {
769
- if (items_2_1 && !items_2_1.done && (_a = items_2.return)) _a.call(items_2);
770
- }
771
- finally { if (e_8) throw e_8.error; }
772
- }
773
- delegate = prisma[lowerModelName(model)];
774
- combinedWhere = (_c = mergeWhere({ OR: uniqueItems }, abilityWhere)) !== null && _c !== void 0 ? _c : {
775
- OR: uniqueItems,
776
- };
777
- return [4 /*yield*/, delegate.count({ where: combinedWhere })];
778
- case 2:
779
- matchedCount = _d.sent();
780
- if (matchedCount < uniqueItems.length) {
781
- throw updateNotFoundError();
782
- }
783
- return [2 /*return*/];
784
- }
785
- });
786
- }); };
787
- var assertCurrentRelationTargetsAllowed = function (prisma, runtimeDataModel, roleAbilities, role, model, fieldMeta, currentWhere, context) { return __awaiter(void 0, void 0, void 0, function () {
788
- var relatedModel, relatedIdField, delegate, currentRecord, currentRelationValue, currentTargets;
789
- var _a, _b;
790
- return __generator(this, function (_c) {
791
- switch (_c.label) {
792
- case 0:
793
- if (!currentWhere || isEmptyWhere(currentWhere))
794
- return [2 /*return*/];
795
- relatedModel = fieldMeta.type;
796
- relatedIdField = getIdField(runtimeDataModel, relatedModel);
797
- if (!relatedIdField)
798
- return [2 /*return*/];
799
- delegate = prisma[lowerModelName(model)];
800
- return [4 /*yield*/, delegate.findFirst({
801
- where: currentWhere,
802
- select: (_a = {},
803
- _a[fieldMeta.name] = {
804
- select: (_b = {},
805
- _b[relatedIdField] = true,
806
- _b),
807
- },
808
- _a),
809
- })];
810
- case 1:
811
- currentRecord = _c.sent();
812
- if (!currentRecord)
813
- return [2 /*return*/];
814
- currentRelationValue = currentRecord[fieldMeta.name];
815
- currentTargets = fieldMeta.isList
816
- ? Array.isArray(currentRelationValue)
817
- ? currentRelationValue
818
- : []
819
- : currentRelationValue
820
- ? [currentRelationValue]
821
- : [];
822
- if (currentTargets.length === 0)
823
- return [2 /*return*/];
824
- return [4 /*yield*/, assertConnectStyleTargetsAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, currentTargets, context)];
825
- case 2:
826
- _c.sent();
827
- return [2 /*return*/];
828
- }
829
- });
830
- }); };
831
- var applyNestedWrites = function (prisma_1, runtimeDataModel_1, roleAbilities_1, role_1, model_1, data_1, context_1) {
832
- var args_1 = [];
833
- for (var _i = 7; _i < arguments.length; _i++) {
834
- args_1[_i - 7] = arguments[_i];
835
- }
836
- return __awaiter(void 0, __spreadArray([prisma_1, runtimeDataModel_1, roleAbilities_1, role_1, model_1, data_1, context_1], __read(args_1), false), void 0, function (prisma, runtimeDataModel, roleAbilities, role, model, data, context, options) {
837
- var mode, currentWhere, shouldCheckRelationMutations, fields, _loop_4, _a, _b, _c, field, value, e_9_1;
838
- var e_9, _d;
839
- var _e, _f, _g, _h, _j, _k, _l, _m;
840
- if (options === void 0) { options = {}; }
841
- return __generator(this, function (_o) {
842
- switch (_o.label) {
843
- case 0:
844
- mode = (_e = options.mode) !== null && _e !== void 0 ? _e : "create";
845
- currentWhere = options.currentWhere;
846
- shouldCheckRelationMutations = mode === "update";
847
- if (!isPlainObject(data))
848
- return [2 /*return*/];
849
- fields = extractModelFields(runtimeDataModel, model);
850
- _loop_4 = function (field, value) {
851
- var fieldMeta, relatedModel, handleCreate, handleUpdate, handleDelete, items, items_3, items_3_1, item, filters, abilityWhere, e_10_1, items, items_4, items_4_1, item, where, canUpdate, e_11_1, items, items_5, items_5_1, item, filters, abilityWhere, _p, _q, key, merged, _r, _s, key, e_12_1;
852
- var e_10, _t, e_11, _u, e_12, _v, e_13, _w, e_14, _x;
853
- return __generator(this, function (_y) {
854
- switch (_y.label) {
855
- case 0:
856
- fieldMeta = fields.find(function (f) { return f.name === field; });
857
- if (!fieldMeta || fieldMeta.kind !== "object")
858
- return [2 /*return*/, "continue"];
859
- relatedModel = fieldMeta.type;
860
- if (!isPlainObject(value))
861
- return [2 /*return*/, "continue"];
862
- handleCreate = function (createValue) { return __awaiter(void 0, void 0, void 0, function () {
863
- var items, items_6, items_6_1, item, e_15_1;
864
- var e_15, _a;
865
- return __generator(this, function (_b) {
866
- switch (_b.label) {
867
- case 0:
868
- items = Array.isArray(createValue) ? createValue : [createValue];
869
- _b.label = 1;
870
- case 1:
871
- _b.trys.push([1, 7, 8, 9]);
872
- items_6 = __values(items), items_6_1 = items_6.next();
873
- _b.label = 2;
874
- case 2:
875
- if (!!items_6_1.done) return [3 /*break*/, 6];
876
- item = items_6_1.value;
877
- if (!isPlainObject(item)) return [3 /*break*/, 5];
878
- return [4 /*yield*/, assertCreateAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, item, context)];
879
- case 3:
880
- _b.sent();
881
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, relatedModel, item, context, options)];
882
- case 4:
883
- _b.sent();
884
- _b.label = 5;
885
- case 5:
886
- items_6_1 = items_6.next();
887
- return [3 /*break*/, 2];
888
- case 6: return [3 /*break*/, 9];
889
- case 7:
890
- e_15_1 = _b.sent();
891
- e_15 = { error: e_15_1 };
892
- return [3 /*break*/, 9];
893
- case 8:
894
- try {
895
- if (items_6_1 && !items_6_1.done && (_a = items_6.return)) _a.call(items_6);
896
- }
897
- finally { if (e_15) throw e_15.error; }
898
- return [7 /*endfinally*/];
899
- case 9: return [2 /*return*/];
900
- }
901
- });
902
- }); };
903
- handleUpdate = function (updateValue) { return __awaiter(void 0, void 0, void 0, function () {
904
- var items, items_7, items_7_1, item, where, allowed, e_16_1;
905
- var e_16, _a;
906
- var _b;
907
- return __generator(this, function (_c) {
908
- switch (_c.label) {
909
- case 0:
910
- items = Array.isArray(updateValue) ? updateValue : [updateValue];
911
- _c.label = 1;
912
- case 1:
913
- _c.trys.push([1, 7, 8, 9]);
914
- items_7 = __values(items), items_7_1 = items_7.next();
915
- _c.label = 2;
916
- case 2:
917
- if (!!items_7_1.done) return [3 /*break*/, 6];
918
- item = items_7_1.value;
919
- if (!isPlainObject(item))
920
- return [3 /*break*/, 5];
921
- where = (_b = item.where) !== null && _b !== void 0 ? _b : {};
922
- return [4 /*yield*/, assertRecordAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, "UPDATE", where, context)];
923
- case 3:
924
- allowed = _c.sent();
925
- if (!allowed) {
926
- throw updateNotFoundError();
927
- }
928
- if (!item.data) return [3 /*break*/, 5];
929
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, relatedModel, item.data, context, __assign(__assign({}, options), { currentWhere: where }))];
930
- case 4:
931
- _c.sent();
932
- _c.label = 5;
933
- case 5:
934
- items_7_1 = items_7.next();
935
- return [3 /*break*/, 2];
936
- case 6: return [3 /*break*/, 9];
937
- case 7:
938
- e_16_1 = _c.sent();
939
- e_16 = { error: e_16_1 };
940
- return [3 /*break*/, 9];
941
- case 8:
942
- try {
943
- if (items_7_1 && !items_7_1.done && (_a = items_7.return)) _a.call(items_7);
944
- }
945
- finally { if (e_16) throw e_16.error; }
946
- return [7 /*endfinally*/];
947
- case 9: return [2 /*return*/];
948
- }
949
- });
950
- }); };
951
- handleDelete = function (deleteValue) { return __awaiter(void 0, void 0, void 0, function () {
952
- var items, items_8, items_8_1, item, where, allowed, e_17_1;
953
- var e_17, _a;
954
- return __generator(this, function (_b) {
955
- switch (_b.label) {
956
- case 0:
957
- items = Array.isArray(deleteValue) ? deleteValue : [deleteValue];
958
- _b.label = 1;
959
- case 1:
960
- _b.trys.push([1, 6, 7, 8]);
961
- items_8 = __values(items), items_8_1 = items_8.next();
962
- _b.label = 2;
963
- case 2:
964
- if (!!items_8_1.done) return [3 /*break*/, 5];
965
- item = items_8_1.value;
966
- where = isPlainObject(item) ? item : {};
967
- return [4 /*yield*/, assertRecordAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, "DELETE", where, context)];
968
- case 3:
969
- allowed = _b.sent();
970
- if (!allowed) {
971
- throw deleteNotFoundError();
972
- }
973
- _b.label = 4;
974
- case 4:
975
- items_8_1 = items_8.next();
976
- return [3 /*break*/, 2];
977
- case 5: return [3 /*break*/, 8];
978
- case 6:
979
- e_17_1 = _b.sent();
980
- e_17 = { error: e_17_1 };
981
- return [3 /*break*/, 8];
982
- case 7:
983
- try {
984
- if (items_8_1 && !items_8_1.done && (_a = items_8.return)) _a.call(items_8);
985
- }
986
- finally { if (e_17) throw e_17.error; }
987
- return [7 /*endfinally*/];
988
- case 8: return [2 /*return*/];
989
- }
990
- });
991
- }); };
992
- if (!value.create) return [3 /*break*/, 2];
993
- return [4 /*yield*/, handleCreate(value.create)];
994
- case 1:
995
- _y.sent();
996
- _y.label = 2;
997
- case 2:
998
- if (!((_f = value.createMany) === null || _f === void 0 ? void 0 : _f.data)) return [3 /*break*/, 4];
999
- return [4 /*yield*/, handleCreate(value.createMany.data)];
1000
- case 3:
1001
- _y.sent();
1002
- _y.label = 4;
1003
- case 4:
1004
- if (!value.update) return [3 /*break*/, 6];
1005
- return [4 /*yield*/, handleUpdate(value.update)];
1006
- case 5:
1007
- _y.sent();
1008
- _y.label = 6;
1009
- case 6:
1010
- if (!value.updateMany) return [3 /*break*/, 15];
1011
- items = Array.isArray(value.updateMany)
1012
- ? value.updateMany
1013
- : [value.updateMany];
1014
- _y.label = 7;
1015
- case 7:
1016
- _y.trys.push([7, 13, 14, 15]);
1017
- items_3 = (e_10 = void 0, __values(items)), items_3_1 = items_3.next();
1018
- _y.label = 8;
1019
- case 8:
1020
- if (!!items_3_1.done) return [3 /*break*/, 12];
1021
- item = items_3_1.value;
1022
- if (!isPlainObject(item))
1023
- return [3 /*break*/, 11];
1024
- return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, relatedModel, "UPDATE", context)];
1025
- case 9:
1026
- filters = (_g = (_y.sent())) !== null && _g !== void 0 ? _g : [];
1027
- abilityWhere = combineAbilityFilters(filters);
1028
- if (!abilityWhere) {
1029
- item.where = denyWhere(runtimeDataModel, relatedModel);
1030
- }
1031
- else {
1032
- item.where = (_j = mergeWhere((_h = item.where) !== null && _h !== void 0 ? _h : {}, abilityWhere)) !== null && _j !== void 0 ? _j : item.where;
1033
- }
1034
- if (!item.data) return [3 /*break*/, 11];
1035
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, relatedModel, item.data, context, __assign(__assign({}, options), { currentWhere: (_k = item.where) !== null && _k !== void 0 ? _k : {} }))];
1036
- case 10:
1037
- _y.sent();
1038
- _y.label = 11;
1039
- case 11:
1040
- items_3_1 = items_3.next();
1041
- return [3 /*break*/, 8];
1042
- case 12: return [3 /*break*/, 15];
1043
- case 13:
1044
- e_10_1 = _y.sent();
1045
- e_10 = { error: e_10_1 };
1046
- return [3 /*break*/, 15];
1047
- case 14:
1048
- try {
1049
- if (items_3_1 && !items_3_1.done && (_t = items_3.return)) _t.call(items_3);
1050
- }
1051
- finally { if (e_10) throw e_10.error; }
1052
- return [7 /*endfinally*/];
1053
- case 15:
1054
- if (!value.upsert) return [3 /*break*/, 29];
1055
- items = Array.isArray(value.upsert) ? value.upsert : [value.upsert];
1056
- _y.label = 16;
1057
- case 16:
1058
- _y.trys.push([16, 27, 28, 29]);
1059
- items_4 = (e_11 = void 0, __values(items)), items_4_1 = items_4.next();
1060
- _y.label = 17;
1061
- case 17:
1062
- if (!!items_4_1.done) return [3 /*break*/, 26];
1063
- item = items_4_1.value;
1064
- if (!isPlainObject(item))
1065
- return [3 /*break*/, 25];
1066
- where = (_l = item.where) !== null && _l !== void 0 ? _l : {};
1067
- return [4 /*yield*/, assertRecordAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, "UPDATE", where, context)];
1068
- case 18:
1069
- canUpdate = _y.sent();
1070
- if (!canUpdate) return [3 /*break*/, 21];
1071
- if (!item.update) return [3 /*break*/, 20];
1072
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, relatedModel, item.update, context, __assign(__assign({}, options), { currentWhere: where }))];
1073
- case 19:
1074
- _y.sent();
1075
- _y.label = 20;
1076
- case 20: return [3 /*break*/, 25];
1077
- case 21:
1078
- if (!item.create) return [3 /*break*/, 24];
1079
- return [4 /*yield*/, assertCreateAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, item.create, context)];
1080
- case 22:
1081
- _y.sent();
1082
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, relatedModel, item.create, context, options)];
1083
- case 23:
1084
- _y.sent();
1085
- return [3 /*break*/, 25];
1086
- case 24: throw updateNotFoundError();
1087
- case 25:
1088
- items_4_1 = items_4.next();
1089
- return [3 /*break*/, 17];
1090
- case 26: return [3 /*break*/, 29];
1091
- case 27:
1092
- e_11_1 = _y.sent();
1093
- e_11 = { error: e_11_1 };
1094
- return [3 /*break*/, 29];
1095
- case 28:
1096
- try {
1097
- if (items_4_1 && !items_4_1.done && (_u = items_4.return)) _u.call(items_4);
1098
- }
1099
- finally { if (e_11) throw e_11.error; }
1100
- return [7 /*endfinally*/];
1101
- case 29:
1102
- if (!value.delete) return [3 /*break*/, 31];
1103
- return [4 /*yield*/, handleDelete(value.delete)];
1104
- case 30:
1105
- _y.sent();
1106
- _y.label = 31;
1107
- case 31:
1108
- if (!value.deleteMany) return [3 /*break*/, 39];
1109
- items = Array.isArray(value.deleteMany)
1110
- ? value.deleteMany
1111
- : [value.deleteMany];
1112
- _y.label = 32;
1113
- case 32:
1114
- _y.trys.push([32, 37, 38, 39]);
1115
- items_5 = (e_12 = void 0, __values(items)), items_5_1 = items_5.next();
1116
- _y.label = 33;
1117
- case 33:
1118
- if (!!items_5_1.done) return [3 /*break*/, 36];
1119
- item = items_5_1.value;
1120
- if (!isPlainObject(item))
1121
- return [3 /*break*/, 35];
1122
- return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, relatedModel, "DELETE", context)];
1123
- case 34:
1124
- filters = (_m = (_y.sent())) !== null && _m !== void 0 ? _m : [];
1125
- abilityWhere = combineAbilityFilters(filters);
1126
- if (!abilityWhere) {
1127
- try {
1128
- for (_p = (e_13 = void 0, __values(Object.keys(item))), _q = _p.next(); !_q.done; _q = _p.next()) {
1129
- key = _q.value;
1130
- delete item[key];
1131
- }
1132
- }
1133
- catch (e_13_1) { e_13 = { error: e_13_1 }; }
1134
- finally {
1135
- try {
1136
- if (_q && !_q.done && (_w = _p.return)) _w.call(_p);
1137
- }
1138
- finally { if (e_13) throw e_13.error; }
1139
- }
1140
- Object.assign(item, denyWhere(runtimeDataModel, relatedModel));
1141
- }
1142
- else {
1143
- merged = mergeWhere((0, cloneDeep_1.default)(item), abilityWhere);
1144
- if (merged && merged !== item) {
1145
- try {
1146
- for (_r = (e_14 = void 0, __values(Object.keys(item))), _s = _r.next(); !_s.done; _s = _r.next()) {
1147
- key = _s.value;
1148
- delete item[key];
1149
- }
1150
- }
1151
- catch (e_14_1) { e_14 = { error: e_14_1 }; }
1152
- finally {
1153
- try {
1154
- if (_s && !_s.done && (_x = _r.return)) _x.call(_r);
1155
- }
1156
- finally { if (e_14) throw e_14.error; }
1157
- }
1158
- Object.assign(item, merged);
1159
- }
1160
- }
1161
- _y.label = 35;
1162
- case 35:
1163
- items_5_1 = items_5.next();
1164
- return [3 /*break*/, 33];
1165
- case 36: return [3 /*break*/, 39];
1166
- case 37:
1167
- e_12_1 = _y.sent();
1168
- e_12 = { error: e_12_1 };
1169
- return [3 /*break*/, 39];
1170
- case 38:
1171
- try {
1172
- if (items_5_1 && !items_5_1.done && (_v = items_5.return)) _v.call(items_5);
1173
- }
1174
- finally { if (e_12) throw e_12.error; }
1175
- return [7 /*endfinally*/];
1176
- case 39:
1177
- if (!shouldCheckRelationMutations) return [3 /*break*/, 48];
1178
- if (!value.connect) return [3 /*break*/, 41];
1179
- return [4 /*yield*/, assertConnectStyleTargetsAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, value.connect, context)];
1180
- case 40:
1181
- _y.sent();
1182
- _y.label = 41;
1183
- case 41:
1184
- if (!value.set) return [3 /*break*/, 44];
1185
- return [4 /*yield*/, assertConnectStyleTargetsAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, value.set, context)];
1186
- case 42:
1187
- _y.sent();
1188
- if (!fieldMeta.isList) return [3 /*break*/, 44];
1189
- return [4 /*yield*/, assertCurrentRelationTargetsAllowed(prisma, runtimeDataModel, roleAbilities, role, model, fieldMeta, currentWhere, context)];
1190
- case 43:
1191
- _y.sent();
1192
- _y.label = 44;
1193
- case 44:
1194
- if (!(value.disconnect &&
1195
- value.disconnect !== true &&
1196
- value.disconnect !== false)) return [3 /*break*/, 46];
1197
- return [4 /*yield*/, assertConnectStyleTargetsAllowed(prisma, runtimeDataModel, roleAbilities, role, relatedModel, value.disconnect, context)];
1198
- case 45:
1199
- _y.sent();
1200
- _y.label = 46;
1201
- case 46:
1202
- if (!(value.disconnect === true && !fieldMeta.isList)) return [3 /*break*/, 48];
1203
- return [4 /*yield*/, assertCurrentRelationTargetsAllowed(prisma, runtimeDataModel, roleAbilities, role, model, fieldMeta, currentWhere, context)];
1204
- case 47:
1205
- _y.sent();
1206
- _y.label = 48;
1207
- case 48: return [2 /*return*/];
1208
- }
1209
- });
1210
- };
1211
- _o.label = 1;
1212
- case 1:
1213
- _o.trys.push([1, 6, 7, 8]);
1214
- _a = __values(Object.entries(data)), _b = _a.next();
1215
- _o.label = 2;
1216
- case 2:
1217
- if (!!_b.done) return [3 /*break*/, 5];
1218
- _c = __read(_b.value, 2), field = _c[0], value = _c[1];
1219
- return [5 /*yield**/, _loop_4(field, value)];
1220
- case 3:
1221
- _o.sent();
1222
- _o.label = 4;
1223
- case 4:
1224
- _b = _a.next();
1225
- return [3 /*break*/, 2];
1226
- case 5: return [3 /*break*/, 8];
1227
- case 6:
1228
- e_9_1 = _o.sent();
1229
- e_9 = { error: e_9_1 };
1230
- return [3 /*break*/, 8];
1231
- case 7:
1232
- try {
1233
- if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
1234
- }
1235
- finally { if (e_9) throw e_9.error; }
1236
- return [7 /*endfinally*/];
1237
- case 8: return [2 /*return*/];
334
+ return _this.createAbilityName(ability.model, ability.slug);
335
+ })
336
+ : "*";
337
+ return { grants: grants, roleName: roleName };
338
+ });
339
+ return {
340
+ abilities: manifestAbilities,
341
+ databaseScope: _this.getDatabaseScope(),
342
+ roles: manifestRoles,
343
+ };
344
+ };
345
+ this.getSetupManifestId = function () { return "".concat(_this.getDatabaseScope(), ":public"); };
346
+ this.getStoredSetupManifestHash = function (manifestId_1) {
347
+ var args_1 = [];
348
+ for (var _i = 1; _i < arguments.length; _i++) {
349
+ args_1[_i - 1] = arguments[_i];
1238
350
  }
1239
- });
1240
- });
1241
- };
1242
- var Yates = /** @class */ (function () {
1243
- function Yates(prisma) {
1244
- var _this = this;
1245
- this.prisma = prisma;
1246
- this.inspectRunTimeDataModel = function () {
1247
- var runtimeDataModel = _this.prisma
1248
- ._runtimeDataModel;
1249
- return runtimeDataModel;
351
+ return __awaiter(_this, __spreadArray([manifestId_1], __read(args_1), false), void 0, function (manifestId, prisma) {
352
+ var rows;
353
+ var _a, _b;
354
+ if (prisma === void 0) { prisma = this.prisma; }
355
+ return __generator(this, function (_c) {
356
+ switch (_c.label) {
357
+ case 0: return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\tSELECT manifest_hash\n\t\t\t\tFROM _yates._yates_schema_syncs\n\t\t\t\tWHERE id = $1\n\t\t\t\tLIMIT 1;\n\t\t\t", manifestId)];
358
+ case 1:
359
+ rows = _c.sent();
360
+ return [2 /*return*/, (_b = (_a = rows[0]) === null || _a === void 0 ? void 0 : _a.manifest_hash) !== null && _b !== void 0 ? _b : null];
361
+ }
362
+ });
363
+ });
364
+ };
365
+ this.upsertSetupManifestHash = function (manifestId, manifestHash, prisma) {
366
+ if (prisma === void 0) { prisma = _this.prisma; }
367
+ return prisma.$executeRawUnsafe("\n\t\t\t\tINSERT INTO _yates._yates_schema_syncs (id, manifest_hash, manifest_version, yates_version, app_name, applied_at)\n\t\t\t\tVALUES ($1, $2, $3, $4, $5, now())\n\t\t\t\tON CONFLICT (id) DO UPDATE\n\t\t\t\tSET manifest_hash = EXCLUDED.manifest_hash,\n\t\t\t\t\tmanifest_version = EXCLUDED.manifest_version,\n\t\t\t\t\tyates_version = EXCLUDED.yates_version,\n\t\t\t\t\tapp_name = EXCLUDED.app_name,\n\t\t\t\t\tapplied_at = now();\n\t\t\t", manifestId, manifestHash, SETUP_MANIFEST_VERSION, YATES_VERSION, "yates");
1250
368
  };
1251
369
  this.getDefaultAbilities = function (models) {
1252
- var e_18, _a;
370
+ var e_3, _a;
1253
371
  var abilities = {};
1254
372
  try {
1255
373
  for (var models_1 = __values(models), models_1_1 = models_1.next(); !models_1_1.done; models_1_1 = models_1.next()) {
@@ -1257,28 +375,28 @@ var Yates = /** @class */ (function () {
1257
375
  abilities[model] = {
1258
376
  create: {
1259
377
  description: "Create ".concat(model),
1260
- expression: {},
378
+ expression: "true",
1261
379
  operation: "INSERT",
1262
380
  model: model,
1263
381
  slug: "create",
1264
382
  },
1265
383
  read: {
1266
384
  description: "Read ".concat(model),
1267
- expression: {},
385
+ expression: "true",
1268
386
  operation: "SELECT",
1269
387
  model: model,
1270
388
  slug: "read",
1271
389
  },
1272
390
  update: {
1273
391
  description: "Update ".concat(model),
1274
- expression: {},
392
+ expression: "true",
1275
393
  operation: "UPDATE",
1276
394
  model: model,
1277
395
  slug: "update",
1278
396
  },
1279
397
  delete: {
1280
398
  description: "Delete ".concat(model),
1281
- expression: {},
399
+ expression: "true",
1282
400
  operation: "DELETE",
1283
401
  model: model,
1284
402
  slug: "delete",
@@ -1286,312 +404,801 @@ var Yates = /** @class */ (function () {
1286
404
  };
1287
405
  }
1288
406
  }
1289
- catch (e_18_1) { e_18 = { error: e_18_1 }; }
407
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
1290
408
  finally {
1291
409
  try {
1292
410
  if (models_1_1 && !models_1_1.done && (_a = models_1.return)) _a.call(models_1);
1293
411
  }
1294
- finally { if (e_18) throw e_18.error; }
412
+ finally { if (e_3) throw e_3.error; }
1295
413
  }
1296
414
  return abilities;
1297
415
  };
1298
- }
1299
- return Yates;
1300
- }());
1301
- exports.Yates = Yates;
1302
- /**
1303
- * Creates an extended client that applies role abilities to Prisma queries.
1304
- **/
1305
- exports.__private = {
1306
- denyWhere: denyWhere,
1307
- getIdField: getIdField,
1308
- matchesScalarFilter: matchesScalarFilter,
1309
- validateContext: validateContext,
1310
- };
1311
- var setup = function (params) { return __awaiter(void 0, void 0, void 0, function () {
1312
- var start, prisma, customAbilities, getRoles, getContext, yates, runtimeDataModel, models, diff, defaultAbilities, abilities, models_2, models_2_1, model, modelCustomAbilities, modelAbilities, ability, operation, roles, allAbilities, roleAbilities, client;
1313
- var e_19, _a;
1314
- var _b;
1315
- return __generator(this, function (_c) {
1316
- start = performance.now();
1317
- prisma = params.prisma, customAbilities = params.customAbilities, getRoles = params.getRoles, getContext = params.getContext;
1318
- yates = new Yates(prisma);
1319
- runtimeDataModel = yates.inspectRunTimeDataModel();
1320
- models = Object.keys(runtimeDataModel.models).map(function (m) { return runtimeDataModel.models[m].dbName || m; });
1321
- if (customAbilities) {
1322
- diff = (0, difference_1.default)(Object.keys(customAbilities), models);
1323
- if (diff.length) {
1324
- throw new Error("Invalid models in custom abilities: ".concat(diff.join(", ")));
1325
- }
1326
- }
1327
- defaultAbilities = yates.getDefaultAbilities(models);
1328
- abilities = (0, cloneDeep_1.default)(defaultAbilities);
1329
- try {
1330
- for (models_2 = __values(models), models_2_1 = models_2.next(); !models_2_1.done; models_2_1 = models_2.next()) {
1331
- model = models_2_1.value;
1332
- modelCustomAbilities = customAbilities === null || customAbilities === void 0 ? void 0 : customAbilities[model];
1333
- if (modelCustomAbilities) {
1334
- if (!abilities[model]) {
1335
- abilities[model] = {};
1336
- }
1337
- modelAbilities = abilities[model];
1338
- for (ability in modelCustomAbilities) {
1339
- operation = (_b = modelCustomAbilities === null || modelCustomAbilities === void 0 ? void 0 : modelCustomAbilities[ability]) === null || _b === void 0 ? void 0 : _b.operation;
1340
- if (!operation)
1341
- continue;
1342
- if (!VALID_OPERATIONS.includes(operation)) {
1343
- throw new Error("Invalid operation: ".concat(operation));
416
+ // This uses client extensions to set the role and context for the current user so that RLS can be applied
417
+ this.createClient = function (getContext, options) {
418
+ if (options === void 0) { options = {}; }
419
+ var prisma = _this.prisma;
420
+ // Set default options
421
+ var _a = options.txMaxWait, txMaxWait = _a === void 0 ? 30000 : _a, _b = options.txTimeout, txTimeout = _b === void 0 ? 30000 : _b;
422
+ // By default, Prisma will batch requests by the transaction ID if it is present.
423
+ // This behaviour prevents automatic batching from working when using Yates, since all queries are executed inside an interactive transaction.
424
+ // To get around this we by monkey patching the batching function to use the Yates ID as the batch ID.
425
+ // To get the batching to work we also need to ensure that all the requests we might want to batch together are generated inside the same tick.
426
+ // This means that all the requests per-tick that have the same role and context values will be batched together,
427
+ // allowing the in-built prisma batch optimizations to work for us.
428
+ // This is why we use process.nextTick and the tickActive flag to ensure we only tick once at a time.
429
+ // See:
430
+ // - https://github.com/prisma/prisma/blob/5.21.1/packages/client/src/runtime/RequestHandler.ts#L122
431
+ // - https://www.prisma.io/docs/orm/prisma-client/queries/query-optimization-performance
432
+ prisma._requestHandler.dataloader.options.batchBy = function (request) {
433
+ var _a;
434
+ var batchIdPQ = _this.getBatchId(request.protocolQuery);
435
+ if ((_a = request.transaction) === null || _a === void 0 ? void 0 : _a.id) {
436
+ return "transaction-".concat(request.transaction.id).concat(batchIdPQ ? "-".concat(batchIdPQ) : "");
437
+ }
438
+ return _this.getBatchId(request.protocolQuery);
439
+ };
440
+ var tickActive = false;
441
+ var batches = {};
442
+ // This function is called once per tick, and processes all the batches that have been created during that tick.
443
+ // Each batch represents a unique role + context combination, and contains all the requests that need to be executed with that role + context.
444
+ var dispatchBatches = function () {
445
+ var e_4, _a;
446
+ var _loop_1 = function (key, batch) {
447
+ delete batches[key];
448
+ // Because batch transactions inside a prisma client query extension can run out of order if used with async middleware,
449
+ // we need to run the logic inside an interactive transaction, however this brings a different set of problems in that the
450
+ // main query will no longer automatically run inside the transaction. We resolve this issue by manually executing the prisma request.
451
+ // See https://github.com/prisma/prisma/issues/18276
452
+ prisma
453
+ .$transaction(function (tx) { return __awaiter(_this, void 0, void 0, function () {
454
+ var _a, _b, _c, key_1, value, e_5_1, txId, results;
455
+ var e_5, _d;
456
+ return __generator(this, function (_e) {
457
+ switch (_e.label) {
458
+ case 0:
459
+ // Switch to the user role, We can't use a prepared statement here, due to limitations in PG not allowing prepared statements to be used in SET LOCAL ROLE
460
+ return [4 /*yield*/, tx.$queryRawUnsafe("SET LOCAL ROLE ".concat(batch.pgRole))];
461
+ case 1:
462
+ // Switch to the user role, We can't use a prepared statement here, due to limitations in PG not allowing prepared statements to be used in SET LOCAL ROLE
463
+ _e.sent();
464
+ _e.label = 2;
465
+ case 2:
466
+ _e.trys.push([2, 7, 8, 9]);
467
+ _a = __values((0, toPairs_1.default)(batch.context)), _b = _a.next();
468
+ _e.label = 3;
469
+ case 3:
470
+ if (!!_b.done) return [3 /*break*/, 6];
471
+ _c = __read(_b.value, 2), key_1 = _c[0], value = _c[1];
472
+ return [4 /*yield*/, tx.$queryRaw(templateObject_2 || (templateObject_2 = __makeTemplateObject(["SELECT set_config(", ", ", ", true);"], ["SELECT set_config(", ", ", ", true);"])), key_1, value.toString())];
473
+ case 4:
474
+ _e.sent();
475
+ _e.label = 5;
476
+ case 5:
477
+ _b = _a.next();
478
+ return [3 /*break*/, 3];
479
+ case 6: return [3 /*break*/, 9];
480
+ case 7:
481
+ e_5_1 = _e.sent();
482
+ e_5 = { error: e_5_1 };
483
+ return [3 /*break*/, 9];
484
+ case 8:
485
+ try {
486
+ if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
487
+ }
488
+ finally { if (e_5) throw e_5.error; }
489
+ return [7 /*endfinally*/];
490
+ case 9:
491
+ txId = tx[Symbol.for("prisma.client.transaction.id")];
492
+ return [4 /*yield*/, Promise.all(batch.requests.map(function (request) {
493
+ return prisma._executeRequest(__assign(__assign({}, request.params), { transaction: {
494
+ kind: "itx",
495
+ id: txId,
496
+ } }));
497
+ }))];
498
+ case 10:
499
+ results = _e.sent();
500
+ return [2 /*return*/, results];
501
+ }
502
+ });
503
+ }); }, {
504
+ maxWait: txMaxWait,
505
+ timeout: txTimeout,
506
+ })
507
+ .then(function (results) {
508
+ results.forEach(function (result, index) {
509
+ batch.requests[index].resolve(result);
510
+ });
511
+ })
512
+ .catch(function (e) {
513
+ var e_6, _a;
514
+ try {
515
+ for (var _b = (e_6 = void 0, __values(batch.requests)), _c = _b.next(); !_c.done; _c = _b.next()) {
516
+ var request = _c.value;
517
+ request.reject(e);
518
+ }
519
+ }
520
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
521
+ finally {
522
+ try {
523
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
524
+ }
525
+ finally { if (e_6) throw e_6.error; }
1344
526
  }
1345
- modelAbilities[ability] = __assign(__assign({}, modelCustomAbilities[ability]), { operation: operation, model: model, slug: ability });
527
+ delete batches[key];
528
+ });
529
+ };
530
+ try {
531
+ for (var _b = __values(Object.entries(batches)), _c = _b.next(); !_c.done; _c = _b.next()) {
532
+ var _d = __read(_c.value, 2), key = _d[0], batch = _d[1];
533
+ _loop_1(key, batch);
1346
534
  }
1347
535
  }
1348
- }
1349
- }
1350
- catch (e_19_1) { e_19 = { error: e_19_1 }; }
1351
- finally {
1352
- try {
1353
- if (models_2_1 && !models_2_1.done && (_a = models_2.return)) _a.call(models_2);
1354
- }
1355
- finally { if (e_19) throw e_19.error; }
1356
- }
1357
- roles = getRoles(abilities);
1358
- allAbilities = Object.values(abilities).flatMap(function (modelAbilities) {
1359
- return modelAbilities ? Object.values(modelAbilities) : [];
1360
- });
1361
- roleAbilities = buildRoleAbilities(roles, allAbilities);
1362
- client = prisma.$extends({
1363
- name: "Yates client",
1364
- query: {
1365
- $allModels: {
1366
- $allOperations: function (params) {
1367
- return __awaiter(this, void 0, void 0, function () {
1368
- var model, args, query, operation, queryArgs, ctx, op, context, role, filters, abilityWhere, combinedWhere, deniedWhere, fluentField, delegate, result, _a, fluentField, delegate, result, _b, items, items_9, items_9_1, item, e_20_1, allowed, filters, abilityWhere, canUpdate, allowed, filters, abilityWhere;
1369
- var e_20, _c;
1370
- var _d, _e, _f, _g, _h, _j, _k, _l, _m;
1371
- return __generator(this, function (_o) {
1372
- switch (_o.label) {
536
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
537
+ finally {
538
+ try {
539
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
540
+ }
541
+ finally { if (e_4) throw e_4.error; }
542
+ }
543
+ };
544
+ var createRoleName = _this.createRoleName.bind(_this);
545
+ var client = prisma.$extends({
546
+ name: "Yates client",
547
+ query: {
548
+ $allModels: {
549
+ $allOperations: function (params) {
550
+ return __awaiter(this, void 0, void 0, function () {
551
+ var model, args, query, operation, ctx, role, context, pgRole, _a, _b, k, _c, _d, v, txId, hash, __internalParams;
552
+ var e_7, _e, e_8, _f;
553
+ return __generator(this, function (_g) {
554
+ model = params.model, args = params.args, query = params.query, operation = params.operation;
555
+ if (!model) {
556
+ // If the model is not defined, we can't apply RLS
557
+ // This can occur when you are making a call with Prisma's $queryRaw method
558
+ return [2 /*return*/, query(args)];
559
+ }
560
+ ctx = getContext();
561
+ // If ctx is null, the middleware is explicitly skipped
562
+ if (ctx === null) {
563
+ return [2 /*return*/, query(args)];
564
+ }
565
+ role = ctx.role, context = ctx.context;
566
+ pgRole = createRoleName(role);
567
+ if (context) {
568
+ try {
569
+ for (_a = __values(Object.keys(context)), _b = _a.next(); !_b.done; _b = _a.next()) {
570
+ k = _b.value;
571
+ if (!k.match(/^[a-z_\.]+$/)) {
572
+ throw new Error("Context variable \"".concat(k, "\" contains invalid characters. Context variables must only contain lowercase letters, numbers, periods and underscores."));
573
+ }
574
+ if (typeof context[k] !== "number" &&
575
+ typeof context[k] !== "string" &&
576
+ !Array.isArray(context[k])) {
577
+ throw new Error("Context variable \"".concat(k, "\" must be a string, number or array. Got ").concat(typeof context[k]));
578
+ }
579
+ if (Array.isArray(context[k])) {
580
+ try {
581
+ for (_c = (e_8 = void 0, __values(context[k])), _d = _c.next(); !_d.done; _d = _c.next()) {
582
+ v = _d.value;
583
+ if (typeof v !== "string") {
584
+ throw new Error("Context variable \"".concat(k, "\" must be an array of strings. Got ").concat(typeof v));
585
+ }
586
+ }
587
+ }
588
+ catch (e_8_1) { e_8 = { error: e_8_1 }; }
589
+ finally {
590
+ try {
591
+ if (_d && !_d.done && (_f = _c.return)) _f.call(_c);
592
+ }
593
+ finally { if (e_8) throw e_8.error; }
594
+ }
595
+ // Cast to a JSON string so that it can be used in RLS expressions
596
+ context[k] = JSON.stringify(context[k]);
597
+ }
598
+ }
599
+ }
600
+ catch (e_7_1) { e_7 = { error: e_7_1 }; }
601
+ finally {
602
+ try {
603
+ if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
604
+ }
605
+ finally { if (e_7) throw e_7.error; }
606
+ }
607
+ }
608
+ txId = hashWithPrefix("yates_tx_", JSON.stringify(ctx));
609
+ hash = txId;
610
+ if (!batches[hash]) {
611
+ // Create a new batch for this role + context combination
612
+ batches[hash] = {
613
+ pgRole: pgRole,
614
+ context: context,
615
+ requests: [],
616
+ };
617
+ // make sure, that we only tick once at a time
618
+ if (!tickActive) {
619
+ tickActive = true;
620
+ process.nextTick(function () {
621
+ dispatchBatches();
622
+ tickActive = false;
623
+ });
624
+ }
625
+ }
626
+ __internalParams = params.__internalParams;
627
+ // Add the request to the batch, and return a promise that will be resolved or rejected in dispatchBatches
628
+ return [2 /*return*/, new Promise(function (resolve, reject) {
629
+ batches[hash].requests.push({
630
+ params: __internalParams,
631
+ query: query,
632
+ args: args,
633
+ resolve: resolve,
634
+ reject: reject,
635
+ });
636
+ }).catch(function (e) {
637
+ var _a;
638
+ // Normalize RLS errors to make them a bit more readable.
639
+ if ((_a = e.message) === null || _a === void 0 ? void 0 : _a.includes("new row violates row-level security policy for table")) {
640
+ throw new Error("You do not have permission to perform this action: ".concat(model, ".").concat(operation, "(...)"));
641
+ }
642
+ throw e;
643
+ })];
644
+ });
645
+ });
646
+ },
647
+ },
648
+ },
649
+ });
650
+ return client;
651
+ };
652
+ this.setRLS = function (prisma, table, roleName, slug, ability, resolvedExpression) { return __awaiter(_this, void 0, void 0, function () {
653
+ var operation, rawExpression, description, abilityExpression, policyExpression, policyName, quotedPolicyName, quotedRoleName, quotedTableName, existingAbilities, existingAbility, shouldUpdateAbilityTable;
654
+ return __generator(this, function (_a) {
655
+ switch (_a.label) {
656
+ case 0:
657
+ operation = ability.operation, rawExpression = ability.expression, description = ability.description;
658
+ if (!rawExpression) {
659
+ throw new Error("Expression must be defined for RLS abilities");
660
+ }
661
+ abilityExpression = resolvedExpression.abilityExpression, policyExpression = resolvedExpression.policyExpression;
662
+ policyName = roleName;
663
+ quotedPolicyName = this.quoteIdentifier(policyName);
664
+ quotedRoleName = this.quoteIdentifier(roleName);
665
+ quotedTableName = "".concat(this.quoteIdentifier("public"), ".").concat(this.quoteIdentifier(table));
666
+ return [4 /*yield*/, prisma.$queryRaw(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n\t\t\t\tselect * from _yates._yates_abilities where ability_model = ", " and ability_policy_name = ", "\n\t\t\t"], ["\n\t\t\t\tselect * from _yates._yates_abilities where ability_model = ", " and ability_policy_name = ", "\n\t\t\t"])), table, policyName)];
667
+ case 1:
668
+ existingAbilities = _a.sent();
669
+ existingAbility = existingAbilities[0];
670
+ shouldUpdateAbilityTable = false;
671
+ if (!!existingAbility) return [3 /*break*/, 6];
672
+ debug("Creating RLS policy for", roleName, "on", table, "for", operation);
673
+ if (!(operation === "INSERT")) return [3 /*break*/, 3];
674
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\t\tCREATE POLICY ".concat(quotedPolicyName, " ON ").concat(quotedTableName, " FOR ").concat(operation, " TO ").concat(quotedRoleName, " WITH CHECK (").concat(policyExpression, ");\n\t\t\t\t"))];
675
+ case 2:
676
+ _a.sent();
677
+ return [3 /*break*/, 5];
678
+ case 3: return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\t\tCREATE POLICY ".concat(quotedPolicyName, " ON ").concat(quotedTableName, " FOR ").concat(operation, " TO ").concat(quotedRoleName, " USING (").concat(policyExpression, ");\n\t\t\t\t"))];
679
+ case 4:
680
+ _a.sent();
681
+ _a.label = 5;
682
+ case 5:
683
+ shouldUpdateAbilityTable = true;
684
+ return [3 /*break*/, 11];
685
+ case 6:
686
+ if (!(existingAbility.ability_expression !== abilityExpression)) return [3 /*break*/, 11];
687
+ debug("Updating RLS policy for", roleName, "on", table, "for", operation);
688
+ if (!(operation === "INSERT")) return [3 /*break*/, 8];
689
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\t\tALTER POLICY ".concat(quotedPolicyName, " ON ").concat(quotedTableName, " TO ").concat(quotedRoleName, " WITH CHECK (").concat(policyExpression, ");\n\t\t\t\t"))];
690
+ case 7:
691
+ _a.sent();
692
+ return [3 /*break*/, 10];
693
+ case 8: return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\t\tALTER POLICY ".concat(quotedPolicyName, " ON ").concat(quotedTableName, " TO ").concat(quotedRoleName, " USING (").concat(policyExpression, ");\n\t\t\t\t"))];
694
+ case 9:
695
+ _a.sent();
696
+ _a.label = 10;
697
+ case 10:
698
+ shouldUpdateAbilityTable = true;
699
+ _a.label = 11;
700
+ case 11:
701
+ if (!shouldUpdateAbilityTable) return [3 /*break*/, 13];
702
+ return [4 /*yield*/, upsertAbility(prisma, {
703
+ ability_model: table,
704
+ ability_name: slug,
705
+ ability_policy_name: policyName,
706
+ ability_description: description !== null && description !== void 0 ? description : "",
707
+ ability_operation: operation,
708
+ // We store the string representation of the expression so that
709
+ // we can compare it later without having to recompute the SQL
710
+ ability_expression: abilityExpression,
711
+ })];
712
+ case 12:
713
+ _a.sent();
714
+ _a.label = 13;
715
+ case 13: return [2 /*return*/];
716
+ }
717
+ });
718
+ }); };
719
+ this.createRoles = function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
720
+ var _c, txMaxWait, _d, txTimeout, runtimeDataModel, models, diff, defaultAbilities, abilities, models_2, models_2_1, model, ability, operation, roles, setupManifest, setupManifestHash, setupManifestId, resolvedSetupAbilityExpressions, _e, _f, _g, _i, model, _h, _j, _k, _l, slug, ability, roleName, _m, _o;
721
+ var e_9, _p, _q;
722
+ var _this = this;
723
+ var _r;
724
+ var customAbilities = _b.customAbilities, getRoles = _b.getRoles, _s = _b.options, options = _s === void 0 ? {} : _s;
725
+ return __generator(this, function (_t) {
726
+ switch (_t.label) {
727
+ case 0: return [4 /*yield*/, this.ensureDatabaseScope()];
728
+ case 1:
729
+ _t.sent();
730
+ _c = options.txMaxWait, txMaxWait = _c === void 0 ? 30000 : _c, _d = options.txTimeout, txTimeout = _d === void 0 ? 30000 : _d;
731
+ runtimeDataModel = this.inspectRunTimeDataModel();
732
+ models = Object.keys(runtimeDataModel.models).map(function (m) { return runtimeDataModel.models[m].dbName || m; });
733
+ if (customAbilities) {
734
+ diff = (0, difference_1.default)(Object.keys(customAbilities), models);
735
+ if (diff.length) {
736
+ throw new Error("Invalid models in custom abilities: ".concat(diff.join(", ")));
737
+ }
738
+ }
739
+ defaultAbilities = this.getDefaultAbilities(models);
740
+ abilities = (0, cloneDeep_1.default)(defaultAbilities);
741
+ try {
742
+ for (models_2 = __values(models), models_2_1 = models_2.next(); !models_2_1.done; models_2_1 = models_2.next()) {
743
+ model = models_2_1.value;
744
+ if (customAbilities === null || customAbilities === void 0 ? void 0 : customAbilities[model]) {
745
+ for (ability in customAbilities[model]) {
746
+ operation =
747
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
748
+ (_r = customAbilities[model][ability]) === null || _r === void 0 ? void 0 : _r.operation;
749
+ if (!operation)
750
+ continue;
751
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
752
+ abilities[model][ability] = __assign(__assign({}, customAbilities[model][ability]), { operation: operation, model: model, slug: ability });
753
+ }
754
+ }
755
+ }
756
+ }
757
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
758
+ finally {
759
+ try {
760
+ if (models_2_1 && !models_2_1.done && (_p = models_2.return)) _p.call(models_2);
761
+ }
762
+ finally { if (e_9) throw e_9.error; }
763
+ }
764
+ roles = getRoles(abilities);
765
+ setupManifest = this.createSetupManifest(abilities, roles);
766
+ setupManifestHash = this.createSetupManifestHash(setupManifest);
767
+ setupManifestId = this.getSetupManifestId();
768
+ return [4 /*yield*/, this.getStoredSetupManifestHash(setupManifestId)];
769
+ case 2:
770
+ if ((_t.sent()) ===
771
+ setupManifestHash) {
772
+ debug("Yates setup manifest unchanged; skipping role reconciliation");
773
+ return [2 /*return*/];
774
+ }
775
+ resolvedSetupAbilityExpressions = {};
776
+ _e = abilities;
777
+ _f = [];
778
+ for (_g in _e)
779
+ _f.push(_g);
780
+ _i = 0;
781
+ _t.label = 3;
782
+ case 3:
783
+ if (!(_i < _f.length)) return [3 /*break*/, 8];
784
+ _g = _f[_i];
785
+ if (!(_g in _e)) return [3 /*break*/, 7];
786
+ model = _g;
787
+ _h = abilities[model];
788
+ _j = [];
789
+ for (_k in _h)
790
+ _j.push(_k);
791
+ _l = 0;
792
+ _t.label = 4;
793
+ case 4:
794
+ if (!(_l < _j.length)) return [3 /*break*/, 7];
795
+ _k = _j[_l];
796
+ if (!(_k in _h)) return [3 /*break*/, 6];
797
+ slug = _k;
798
+ ability =
799
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
800
+ abilities[model][slug];
801
+ if (!ability.expression) {
802
+ return [3 /*break*/, 6];
803
+ }
804
+ roleName = this.createAbilityName(model, slug);
805
+ _m = resolvedSetupAbilityExpressions;
806
+ _o = roleName;
807
+ _q = {
808
+ abilityExpression: ability.expression.toString()
809
+ };
810
+ return [4 /*yield*/, (0, expressions_1.expressionToSQL)(ability.expression, model)];
811
+ case 5:
812
+ _m[_o] = (_q.policyExpression = _t.sent(),
813
+ _q);
814
+ _t.label = 6;
815
+ case 6:
816
+ _l++;
817
+ return [3 /*break*/, 4];
818
+ case 7:
819
+ _i++;
820
+ return [3 /*break*/, 3];
821
+ case 8: return [4 /*yield*/, this.prisma.$transaction(function (tx) { return __awaiter(_this, void 0, void 0, function () {
822
+ var prisma;
823
+ return __generator(this, function (_a) {
824
+ switch (_a.label) {
1373
825
  case 0:
1374
- model = params.model, args = params.args, query = params.query, operation = params.operation;
1375
- queryArgs = args;
1376
- if (!model) {
1377
- return [2 /*return*/, query(args)];
826
+ prisma = tx;
827
+ return [4 /*yield*/, takeLock(prisma)];
828
+ case 1:
829
+ _a.sent();
830
+ return [4 /*yield*/, this.getStoredSetupManifestHash(setupManifestId, prisma)];
831
+ case 2:
832
+ if ((_a.sent()) ===
833
+ setupManifestHash) {
834
+ debug("Yates setup manifest unchanged after acquiring lock; skipping role reconciliation");
835
+ return [2 /*return*/];
1378
836
  }
1379
- ctx = getContext();
1380
- if (ctx === null) {
1381
- return [2 /*return*/, query(args)];
837
+ return [4 /*yield*/, this.reconcileRoles({
838
+ abilities: abilities,
839
+ defaultAbilities: defaultAbilities,
840
+ prisma: prisma,
841
+ resolvedSetupAbilityExpressions: resolvedSetupAbilityExpressions,
842
+ roles: roles,
843
+ })];
844
+ case 3:
845
+ _a.sent();
846
+ return [4 /*yield*/, this.upsertSetupManifestHash(setupManifestId, setupManifestHash, prisma)];
847
+ case 4:
848
+ _a.sent();
849
+ return [2 /*return*/];
850
+ }
851
+ });
852
+ }); }, { maxWait: txMaxWait, timeout: txTimeout })];
853
+ case 9:
854
+ _t.sent();
855
+ return [2 /*return*/];
856
+ }
857
+ });
858
+ }); };
859
+ this.reconcileRoles = function (_a) { return __awaiter(_this, [_a], void 0, function (_b) {
860
+ var pgRoles, existingAbilities, pgPolicies, migratedAbilities, migratedAbilities_1, migratedAbilities_1_1, migratedAbility, e_10_1, _c, _d, _e, _i, model, table, _loop_2, this_1, _f, _g, _h, _j, slug, _loop_3, this_2, _k, _l, _m, _o, key;
861
+ var e_10, _p;
862
+ var _this = this;
863
+ var abilities = _b.abilities, defaultAbilities = _b.defaultAbilities, prisma = _b.prisma, resolvedSetupAbilityExpressions = _b.resolvedSetupAbilityExpressions, roles = _b.roles;
864
+ return __generator(this, function (_q) {
865
+ switch (_q.label) {
866
+ case 0: return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\tselect * from pg_catalog.pg_roles where rolname like 'yates%'\n\t\t")];
867
+ case 1:
868
+ pgRoles = _q.sent();
869
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\tselect * from _yates._yates_abilities;\n\t\t")];
870
+ case 2:
871
+ existingAbilities = _q.sent();
872
+ if (!(existingAbilities.length === 0)) return [3 /*break*/, 12];
873
+ debug('No existing abilities found, importing from "pg_policies" table');
874
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\tselect * from pg_catalog.pg_policies where policyname like 'yates%'\n\t\t\t")];
875
+ case 3:
876
+ pgPolicies = _q.sent();
877
+ if (!pgPolicies.length) return [3 /*break*/, 12];
878
+ migratedAbilities = pgPolicies.map(function (policy) {
879
+ var _a, _b;
880
+ return ({
881
+ ability_model: policy.tablename,
882
+ ability_name: policy.policyname,
883
+ ability_policy_name: policy.policyname,
884
+ ability_description: "",
885
+ ability_operation: policy.cmd,
886
+ ability_expression: (_b = (_a = policy.qual) !== null && _a !== void 0 ? _a : policy.with_check) !== null && _b !== void 0 ? _b : "",
887
+ });
888
+ });
889
+ _q.label = 4;
890
+ case 4:
891
+ _q.trys.push([4, 9, 10, 11]);
892
+ migratedAbilities_1 = __values(migratedAbilities), migratedAbilities_1_1 = migratedAbilities_1.next();
893
+ _q.label = 5;
894
+ case 5:
895
+ if (!!migratedAbilities_1_1.done) return [3 /*break*/, 8];
896
+ migratedAbility = migratedAbilities_1_1.value;
897
+ return [4 /*yield*/, upsertAbility(prisma, migratedAbility)];
898
+ case 6:
899
+ _q.sent();
900
+ _q.label = 7;
901
+ case 7:
902
+ migratedAbilities_1_1 = migratedAbilities_1.next();
903
+ return [3 /*break*/, 5];
904
+ case 8: return [3 /*break*/, 11];
905
+ case 9:
906
+ e_10_1 = _q.sent();
907
+ e_10 = { error: e_10_1 };
908
+ return [3 /*break*/, 11];
909
+ case 10:
910
+ try {
911
+ if (migratedAbilities_1_1 && !migratedAbilities_1_1.done && (_p = migratedAbilities_1.return)) _p.call(migratedAbilities_1);
912
+ }
913
+ finally { if (e_10) throw e_10.error; }
914
+ return [7 /*endfinally*/];
915
+ case 11:
916
+ existingAbilities.push.apply(existingAbilities, __spreadArray([], __read(migratedAbilities), false));
917
+ _q.label = 12;
918
+ case 12:
919
+ _c = abilities;
920
+ _d = [];
921
+ for (_e in _c)
922
+ _d.push(_e);
923
+ _i = 0;
924
+ _q.label = 13;
925
+ case 13:
926
+ if (!(_i < _d.length)) return [3 /*break*/, 19];
927
+ _e = _d[_i];
928
+ if (!(_e in _c)) return [3 /*break*/, 18];
929
+ model = _e;
930
+ table = model;
931
+ return [4 /*yield*/, this.enableRowLevelSecurityIfNeeded(prisma, table)];
932
+ case 14:
933
+ _q.sent();
934
+ _loop_2 = function (slug) {
935
+ var ability, roleName, resolvedExpression;
936
+ return __generator(this, function (_r) {
937
+ switch (_r.label) {
938
+ case 0:
939
+ ability =
940
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
941
+ abilities[model][slug];
942
+ if (!VALID_OPERATIONS.includes(ability.operation)) {
943
+ throw new Error("Invalid operation: ".concat(ability.operation));
1382
944
  }
1383
- validateContext(ctx === null || ctx === void 0 ? void 0 : ctx.context);
1384
- op = OPERATION_MAP[operation];
1385
- if (!op) {
1386
- return [2 /*return*/, query(args)];
945
+ roleName = this_1.createAbilityName(model, slug);
946
+ if (!pgRoles.find(function (role) { return role.rolname === roleName; })) return [3 /*break*/, 1];
947
+ debug("Role already exists", roleName, model, slug);
948
+ return [3 /*break*/, 4];
949
+ case 1: return [4 /*yield*/, prisma.$executeRawUnsafe("\n\t\t\t\t\t\tdo\n\t\t\t\t\t\t$$\n\t\t\t\t\t\tbegin\n\t\t\t\t\t\tif not exists (select * from pg_catalog.pg_roles where rolname = '".concat(roleName, "') then \n\t\t\t\t\t\t\tcreate role ").concat(roleName, ";\n\t\t\t\t\t\tend if;\n\t\t\t\t\t\tend\n\t\t\t\t\t\t$$\n\t\t\t\t\t\t;\n\t\t\t\t\t"))];
950
+ case 2:
951
+ _r.sent();
952
+ return [4 /*yield*/, prisma.$executeRawUnsafe("\n\t\t\t\t\t\tGRANT ".concat(ability.operation, " ON ").concat(this_1.quoteIdentifier("public"), ".").concat(this_1.quoteIdentifier(table), " TO ").concat(this_1.quoteIdentifier(roleName), ";\n\t\t\t\t\t"))];
953
+ case 3:
954
+ _r.sent();
955
+ _r.label = 4;
956
+ case 4:
957
+ if (!ability.expression) return [3 /*break*/, 6];
958
+ resolvedExpression = resolvedSetupAbilityExpressions[roleName];
959
+ if (!resolvedExpression) {
960
+ throw new Error("Missing resolved expression for ".concat(model, ".").concat(slug, " (").concat(roleName, ")"));
1387
961
  }
1388
- context = ctx === null || ctx === void 0 ? void 0 : ctx.context;
1389
- role = ctx === null || ctx === void 0 ? void 0 : ctx.role;
1390
- if (!SELECT_OPERATIONS.has(operation)) return [3 /*break*/, 17];
1391
- return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, model, "SELECT", context)];
962
+ return [4 /*yield*/, this_1.setRLS(prisma, table, roleName, slug, ability, resolvedExpression)];
963
+ case 5:
964
+ _r.sent();
965
+ _r.label = 6;
966
+ case 6: return [2 /*return*/];
967
+ }
968
+ });
969
+ };
970
+ this_1 = this;
971
+ _f = abilities[model];
972
+ _g = [];
973
+ for (_h in _f)
974
+ _g.push(_h);
975
+ _j = 0;
976
+ _q.label = 15;
977
+ case 15:
978
+ if (!(_j < _g.length)) return [3 /*break*/, 18];
979
+ _h = _g[_j];
980
+ if (!(_h in _f)) return [3 /*break*/, 17];
981
+ slug = _h;
982
+ return [5 /*yield**/, _loop_2(slug)];
983
+ case 16:
984
+ _q.sent();
985
+ _q.label = 17;
986
+ case 17:
987
+ _j++;
988
+ return [3 /*break*/, 15];
989
+ case 18:
990
+ _i++;
991
+ return [3 /*break*/, 13];
992
+ case 19:
993
+ _loop_3 = function (key) {
994
+ var role, wildCardAbilities, roleAbilities, rlsRoles, userRoles, oldRoles, policies, policies_1, policies_1_1, oldPolicy, e_11_1;
995
+ var e_11, _s;
996
+ return __generator(this, function (_t) {
997
+ switch (_t.label) {
998
+ case 0:
999
+ role = this_2.createRoleName(key);
1000
+ return [4 /*yield*/, prisma.$executeRawUnsafe("\n\t\t\t\tdo\n\t\t\t\t$$\n\t\t\t\tbegin\n\t\t\t\tif not exists (select * from pg_catalog.pg_roles where rolname = '".concat(role, "') then \n\t\t\t\t\tcreate role ").concat(role, ";\n\t\t\t\tend if;\n\t\t\t\tend\n\t\t\t\t$$\n\t\t\t\t;\n\t\t\t"))];
1392
1001
  case 1:
1393
- filters = (_d = (_o.sent())) !== null && _d !== void 0 ? _d : [];
1394
- abilityWhere = combineAbilityFilters(filters);
1395
- combinedWhere = mergeWhere(queryArgs.where, abilityWhere);
1396
- if (!!abilityWhere) return [3 /*break*/, 9];
1397
- deniedWhere = denyWhere(runtimeDataModel, model);
1398
- if (!(operation === "findUnique" ||
1399
- operation === "findUniqueOrThrow")) return [3 /*break*/, 7];
1400
- return [4 /*yield*/, applyReadSelections(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs, context)];
1002
+ _t.sent();
1003
+ wildCardAbilities = (0, flatMap_1.default)(defaultAbilities, function (model, modelName) {
1004
+ return (0, map_1.default)(model, function (_params, slug) {
1005
+ return _this.createAbilityName(modelName, slug);
1006
+ });
1007
+ });
1008
+ roleAbilities = roles[key];
1009
+ rlsRoles = roleAbilities === "*"
1010
+ ? wildCardAbilities
1011
+ : roleAbilities.map(function (ability) {
1012
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
1013
+ return _this.createAbilityName(ability.model, ability.slug);
1014
+ });
1015
+ debug("Setting up role", key, role, "with abilities", rlsRoles.join(", "));
1016
+ // Note: We need to GRANT all on schema public so that we can resolve relation queries with prisma, as they will sometimes use a join table.
1017
+ // This is not ideal, but because we are using RLS, it's not a security risk. Any table with RLS also needs a corresponding policy for the role to have access.
1018
+ return [4 /*yield*/, prisma.$executeRawUnsafe("GRANT ALL ON ALL TABLES IN SCHEMA public TO ".concat(role, ";"))];
1401
1019
  case 2:
1402
- _o.sent();
1403
- fluentField = getFluentSelectionField(runtimeDataModel, model, queryArgs);
1404
- delegate = prisma[lowerModelName(model)];
1405
- if (!(operation === "findUnique")) return [3 /*break*/, 4];
1406
- return [4 /*yield*/, delegate.findFirst(__assign(__assign({}, queryArgs), { where: deniedWhere }))];
1020
+ // Note: We need to GRANT all on schema public so that we can resolve relation queries with prisma, as they will sometimes use a join table.
1021
+ // This is not ideal, but because we are using RLS, it's not a security risk. Any table with RLS also needs a corresponding policy for the role to have access.
1022
+ _t.sent();
1023
+ return [4 /*yield*/, prisma.$executeRawUnsafe("\n\t\t\t\t\tGRANT ALL ON ALL SEQUENCES IN SCHEMA public TO ".concat(role, ";\n\t\t\t\t"))];
1407
1024
  case 3:
1408
- _a = _o.sent();
1409
- return [3 /*break*/, 6];
1410
- case 4: return [4 /*yield*/, delegate.findFirstOrThrow(__assign(__assign({}, queryArgs), { where: deniedWhere }))];
1025
+ _t.sent();
1026
+ return [4 /*yield*/, prisma.$executeRawUnsafe("\n\t\t\t\t\tGRANT ALL ON SCHEMA public TO ".concat(role, ";\n\t\t\t\t"))];
1027
+ case 4:
1028
+ _t.sent();
1029
+ return [4 /*yield*/, prisma.$queryRawUnsafe("GRANT ".concat(rlsRoles.join(", "), " TO ").concat(role))];
1411
1030
  case 5:
1412
- _a = _o.sent();
1413
- _o.label = 6;
1031
+ _t.sent();
1032
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\t\tWITH RECURSIVE cte AS (\n\t\t\t\t\tSELECT oid FROM pg_roles where rolname = '".concat(role, "'\n\t\t\t\t\tUNION ALL\n\t\t\t\t\tSELECT m.roleid\n\t\t\t\t\tFROM cte\n\t\t\t\t\tJOIN pg_auth_members m ON m.member = cte.oid\n\t\t\t\t\t)\n\t\t\t\tSELECT oid, oid::regrole::text AS rolename FROM cte where oid::regrole::text != '").concat(role, "'; \n\t\t"))];
1414
1033
  case 6:
1415
- result = _a;
1416
- if (fluentField && result) {
1417
- return [2 /*return*/, result[fluentField]];
1418
- }
1419
- return [2 /*return*/, result];
1034
+ userRoles = _t.sent();
1035
+ oldRoles = userRoles
1036
+ .filter(function (_a) {
1037
+ var rolename = _a.rolename;
1038
+ return !rlsRoles.includes(rolename);
1039
+ })
1040
+ .map(function (_a) {
1041
+ var rolename = _a.rolename;
1042
+ return rolename;
1043
+ });
1044
+ if (!oldRoles.length) return [3 /*break*/, 18];
1045
+ // Now revoke old roles from the user role
1046
+ debug("Revoking old roles", key, role, oldRoles.join(", "));
1047
+ return [4 /*yield*/, prisma.$executeRawUnsafe("REVOKE ".concat(oldRoles.join(", "), " FROM ").concat(role))];
1420
1048
  case 7:
1421
- queryArgs.where =
1422
- (_f = mergeWhere((_e = queryArgs.where) !== null && _e !== void 0 ? _e : {}, deniedWhere)) !== null && _f !== void 0 ? _f : queryArgs.where;
1423
- return [4 /*yield*/, applyReadSelections(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs, context)];
1049
+ _t.sent();
1050
+ return [4 /*yield*/, prisma.$queryRawUnsafe("SELECT * FROM pg_catalog.pg_policies WHERE policyname IN (".concat(oldRoles
1051
+ .map(function (or) { return "'".concat(or, "'"); })
1052
+ .join(", "), ")"))];
1424
1053
  case 8:
1425
- _o.sent();
1426
- return [2 /*return*/, query(args)];
1054
+ policies = _t.sent();
1055
+ _t.label = 9;
1427
1056
  case 9:
1428
- if (!(operation === "findUnique" ||
1429
- operation === "findUniqueOrThrow")) return [3 /*break*/, 15];
1430
- return [4 /*yield*/, applyReadSelections(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs, context)];
1057
+ _t.trys.push([9, 14, 15, 16]);
1058
+ policies_1 = (e_11 = void 0, __values(policies)), policies_1_1 = policies_1.next();
1059
+ _t.label = 10;
1431
1060
  case 10:
1432
- _o.sent();
1433
- fluentField = getFluentSelectionField(runtimeDataModel, model, queryArgs);
1434
- delegate = prisma[lowerModelName(model)];
1435
- if (!(operation === "findUnique")) return [3 /*break*/, 12];
1436
- return [4 /*yield*/, delegate.findFirst(__assign(__assign({}, queryArgs), { where: combinedWhere }))];
1061
+ if (!!policies_1_1.done) return [3 /*break*/, 13];
1062
+ oldPolicy = policies_1_1.value;
1063
+ return [4 /*yield*/, prisma.$executeRawUnsafe("DROP POLICY ".concat(oldPolicy.policyname, " ON \"").concat(oldPolicy.tablename, "\""))];
1437
1064
  case 11:
1438
- _b = _o.sent();
1439
- return [3 /*break*/, 14];
1440
- case 12: return [4 /*yield*/, delegate.findFirstOrThrow(__assign(__assign({}, queryArgs), { where: combinedWhere }))];
1441
- case 13:
1442
- _b = _o.sent();
1443
- _o.label = 14;
1065
+ _t.sent();
1066
+ _t.label = 12;
1067
+ case 12:
1068
+ policies_1_1 = policies_1.next();
1069
+ return [3 /*break*/, 10];
1070
+ case 13: return [3 /*break*/, 16];
1444
1071
  case 14:
1445
- result = _b;
1446
- if (fluentField && result) {
1447
- return [2 /*return*/, result[fluentField]];
1448
- }
1449
- return [2 /*return*/, result];
1072
+ e_11_1 = _t.sent();
1073
+ e_11 = { error: e_11_1 };
1074
+ return [3 /*break*/, 16];
1450
1075
  case 15:
1451
- queryArgs.where = combinedWhere !== null && combinedWhere !== void 0 ? combinedWhere : queryArgs.where;
1452
- return [4 /*yield*/, applyReadSelections(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs, context)];
1453
- case 16:
1454
- _o.sent();
1455
- return [2 /*return*/, query(args)];
1456
- case 17:
1457
- if (!(op === "INSERT")) return [3 /*break*/, 30];
1458
- if (!(operation === "create")) return [3 /*break*/, 20];
1459
- return [4 /*yield*/, assertCreateAllowed(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs.data, context)];
1460
- case 18:
1461
- _o.sent();
1462
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs.data, context)];
1463
- case 19:
1464
- _o.sent();
1465
- return [2 /*return*/, query(args)];
1466
- case 20:
1467
- if (!(operation === "createMany")) return [3 /*break*/, 30];
1468
- items = Array.isArray(queryArgs.data)
1469
- ? queryArgs.data
1470
- : [queryArgs.data];
1471
- _o.label = 21;
1472
- case 21:
1473
- _o.trys.push([21, 27, 28, 29]);
1474
- items_9 = __values(items), items_9_1 = items_9.next();
1475
- _o.label = 22;
1476
- case 22:
1477
- if (!!items_9_1.done) return [3 /*break*/, 26];
1478
- item = items_9_1.value;
1479
- return [4 /*yield*/, assertCreateAllowed(prisma, runtimeDataModel, roleAbilities, role, model, item, context)];
1480
- case 23:
1481
- _o.sent();
1482
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, model, item, context)];
1483
- case 24:
1484
- _o.sent();
1485
- _o.label = 25;
1486
- case 25:
1487
- items_9_1 = items_9.next();
1488
- return [3 /*break*/, 22];
1489
- case 26: return [3 /*break*/, 29];
1490
- case 27:
1491
- e_20_1 = _o.sent();
1492
- e_20 = { error: e_20_1 };
1493
- return [3 /*break*/, 29];
1494
- case 28:
1495
1076
  try {
1496
- if (items_9_1 && !items_9_1.done && (_c = items_9.return)) _c.call(items_9);
1077
+ if (policies_1_1 && !policies_1_1.done && (_s = policies_1.return)) _s.call(policies_1);
1497
1078
  }
1498
- finally { if (e_20) throw e_20.error; }
1079
+ finally { if (e_11) throw e_11.error; }
1499
1080
  return [7 /*endfinally*/];
1500
- case 29: return [2 /*return*/, query(args)];
1501
- case 30:
1502
- if (!(op === "UPDATE")) return [3 /*break*/, 47];
1503
- if (!(operation === "update")) return [3 /*break*/, 34];
1504
- return [4 /*yield*/, assertRecordAllowed(prisma, runtimeDataModel, roleAbilities, role, model, "UPDATE", queryArgs.where, context)];
1505
- case 31:
1506
- allowed = _o.sent();
1507
- if (!allowed)
1508
- throw updateNotFoundError();
1509
- if (!queryArgs.data) return [3 /*break*/, 33];
1510
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs.data, context, { mode: "update", currentWhere: queryArgs.where })];
1511
- case 32:
1512
- _o.sent();
1513
- _o.label = 33;
1514
- case 33: return [2 /*return*/, query(args)];
1515
- case 34:
1516
- if (!(operation === "updateMany")) return [3 /*break*/, 38];
1517
- return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, model, "UPDATE", context)];
1518
- case 35:
1519
- filters = (_g = (_o.sent())) !== null && _g !== void 0 ? _g : [];
1520
- abilityWhere = combineAbilityFilters(filters);
1521
- if (!abilityWhere) {
1522
- queryArgs.where = denyWhere(runtimeDataModel, model);
1523
- }
1524
- else {
1525
- queryArgs.where =
1526
- (_j = mergeWhere((_h = queryArgs.where) !== null && _h !== void 0 ? _h : {}, abilityWhere)) !== null && _j !== void 0 ? _j : queryArgs.where;
1527
- }
1528
- if (!queryArgs.data) return [3 /*break*/, 37];
1529
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, model, queryArgs.data, context, { mode: "update", currentWhere: queryArgs.where })];
1530
- case 36:
1531
- _o.sent();
1532
- _o.label = 37;
1533
- case 37: return [2 /*return*/, query(args)];
1534
- case 38:
1535
- if (!(operation === "upsert")) return [3 /*break*/, 47];
1536
- return [4 /*yield*/, assertRecordAllowed(prisma, runtimeDataModel, roleAbilities, role, model, "UPDATE", queryArgs.where, context)];
1537
- case 39:
1538
- canUpdate = _o.sent();
1539
- if (!canUpdate) return [3 /*break*/, 42];
1540
- if (!args.update) return [3 /*break*/, 41];
1541
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, model, args.update, context, { mode: "update", currentWhere: queryArgs.where })];
1542
- case 40:
1543
- _o.sent();
1544
- _o.label = 41;
1545
- case 41: return [3 /*break*/, 46];
1546
- case 42:
1547
- if (!args.create) return [3 /*break*/, 45];
1548
- return [4 /*yield*/, assertCreateAllowed(prisma, runtimeDataModel, roleAbilities, role, model, args.create, context)];
1549
- case 43:
1550
- _o.sent();
1551
- return [4 /*yield*/, applyNestedWrites(prisma, runtimeDataModel, roleAbilities, role, model, args.create, context)];
1552
- case 44:
1553
- _o.sent();
1554
- return [3 /*break*/, 46];
1555
- case 45: throw updateNotFoundError();
1556
- case 46: return [2 /*return*/, query(args)];
1557
- case 47:
1558
- if (!(op === "DELETE")) return [3 /*break*/, 51];
1559
- if (!(operation === "delete")) return [3 /*break*/, 49];
1560
- return [4 /*yield*/, assertRecordAllowed(prisma, runtimeDataModel, roleAbilities, role, model, "DELETE", queryArgs.where, context)];
1561
- case 48:
1562
- allowed = _o.sent();
1563
- if (!allowed)
1564
- throw deleteNotFoundError();
1565
- return [2 /*return*/, query(args)];
1566
- case 49:
1567
- if (!(operation === "deleteMany")) return [3 /*break*/, 51];
1568
- return [4 /*yield*/, getAbilityFilters(prisma, runtimeDataModel, roleAbilities, role, model, "DELETE", context)];
1569
- case 50:
1570
- filters = (_k = (_o.sent())) !== null && _k !== void 0 ? _k : [];
1571
- abilityWhere = combineAbilityFilters(filters);
1572
- if (!abilityWhere) {
1573
- queryArgs.where = denyWhere(runtimeDataModel, model);
1574
- }
1575
- else {
1576
- queryArgs.where =
1577
- (_m = mergeWhere((_l = queryArgs.where) !== null && _l !== void 0 ? _l : {}, abilityWhere)) !== null && _m !== void 0 ? _m : queryArgs.where;
1578
- }
1579
- return [2 /*return*/, query(args)];
1580
- case 51:
1581
- if (!UNIQUE_OPERATIONS.has(operation)) {
1582
- return [2 /*return*/, query(args)];
1583
- }
1584
- return [2 /*return*/, query(args)];
1081
+ case 16:
1082
+ debug("Revoked old rows from ability table", oldRoles.join(", "));
1083
+ return [4 /*yield*/, prisma.$executeRawUnsafe("DELETE FROM _yates._yates_abilities WHERE ability_policy_name IN (".concat(oldRoles
1084
+ .map(function (or) { return "'".concat(or, "'"); })
1085
+ .join(", "), ")"))];
1086
+ case 17:
1087
+ _t.sent();
1088
+ _t.label = 18;
1089
+ case 18: return [2 /*return*/];
1585
1090
  }
1586
1091
  });
1587
- });
1588
- },
1589
- },
1590
- },
1092
+ };
1093
+ this_2 = this;
1094
+ _k = roles;
1095
+ _l = [];
1096
+ for (_m in _k)
1097
+ _l.push(_m);
1098
+ _o = 0;
1099
+ _q.label = 20;
1100
+ case 20:
1101
+ if (!(_o < _l.length)) return [3 /*break*/, 23];
1102
+ _m = _l[_o];
1103
+ if (!(_m in _k)) return [3 /*break*/, 22];
1104
+ key = _m;
1105
+ return [5 /*yield**/, _loop_3(key)];
1106
+ case 21:
1107
+ _q.sent();
1108
+ _q.label = 22;
1109
+ case 22:
1110
+ _o++;
1111
+ return [3 /*break*/, 20];
1112
+ case 23: return [2 /*return*/];
1113
+ }
1114
+ });
1115
+ }); };
1116
+ this.inspectDBRoles = function (role) { return __awaiter(_this, void 0, void 0, function () {
1117
+ var hashedRoleName, roles;
1118
+ return __generator(this, function (_a) {
1119
+ switch (_a.label) {
1120
+ case 0: return [4 /*yield*/, this.ensureDatabaseScope()];
1121
+ case 1:
1122
+ _a.sent();
1123
+ hashedRoleName = this.createRoleName(role);
1124
+ return [4 /*yield*/, this.prisma.$queryRawUnsafe("\n WITH RECURSIVE role_tree AS(\n --Start from your role\n SELECT \n r.oid,\n r.rolname\n FROM pg_roles r\n WHERE r.rolname = '".concat(hashedRoleName, "'\n\n UNION\n\n --Walk \"upwards\": all parent roles granted to it\n SELECT \n parent.oid,\n parent.rolname\n FROM pg_auth_members m\n JOIN role_tree rt\n ON m.member = rt.oid\n JOIN pg_roles parent\n ON parent.oid = m.roleid\n )\n SELECT\n p.tablename,\n p.policyname,\n p.cmd,\n p.roles:: text[] AS policy_roles,\n rt.rolname AS matched_role\n FROM pg_policies p\n JOIN role_tree rt\n ON(\n p.roles IS NULL\n OR array_length(p.roles, 1) = 0\n OR rt.rolname = ANY(p.roles:: text[])\n )\n WHERE p.schemaname = 'public'\n ORDER BY p.policyname, matched_role;\n "))];
1125
+ case 2:
1126
+ roles = _a.sent();
1127
+ return [2 /*return*/, roles];
1128
+ }
1129
+ });
1130
+ }); };
1131
+ this.inspectRunTimeDataModel = function () {
1132
+ // See https://github.com/prisma/prisma/discussions/14777
1133
+ // We are reaching into the prisma internals to get the data model.
1134
+ // This is a bit sketchy, but we can get the internal type definition from the runtime library
1135
+ // and there is even a test case in prisma that checks that this value is exported
1136
+ // See https://github.com/prisma/prisma/blob/5.1.0/packages/client/tests/functional/extensions/pdp.ts#L51
1137
+ // This is a private API, so not much we can do about the cast
1138
+ var runtimeDataModel = _this.prisma
1139
+ ._runtimeDataModel;
1140
+ return runtimeDataModel;
1141
+ };
1142
+ }
1143
+ // @ts-ignore
1144
+ Yates.prototype.getBatchId = function (query) {
1145
+ if (query.action !== "findUnique" && query.action !== "findUniqueOrThrow") {
1146
+ return undefined;
1147
+ }
1148
+ var parts = [];
1149
+ if (query.modelName) {
1150
+ parts.push(query.modelName);
1151
+ }
1152
+ if (query.query.arguments) {
1153
+ parts.push(this.buildKeysString(query.query.arguments));
1154
+ }
1155
+ parts.push(this.buildKeysString(query.query.selection));
1156
+ return parts.join("");
1157
+ };
1158
+ Yates.prototype.buildKeysString = function (obj) {
1159
+ var _this = this;
1160
+ var keysArray = Object.keys(obj)
1161
+ .sort()
1162
+ .map(function (key) {
1163
+ // @ts-ignore
1164
+ var value = obj[key];
1165
+ if (typeof value === "object" && value !== null) {
1166
+ return "(".concat(key, " ").concat(_this.buildKeysString(value), ")");
1167
+ }
1168
+ return key;
1591
1169
  });
1592
- debug("Setup completed in", performance.now() - start, "ms");
1593
- return [2 /*return*/, client];
1170
+ return "(".concat(keysArray.join(" "), ")");
1171
+ };
1172
+ return Yates;
1173
+ }());
1174
+ exports.Yates = Yates;
1175
+ /**
1176
+ * Creates an extended client that sets contextual parameters and user role on every query
1177
+ **/
1178
+ var setup = function (params) { return __awaiter(void 0, void 0, void 0, function () {
1179
+ var start, prisma, customAbilities, getRoles, getContext, yates, client;
1180
+ return __generator(this, function (_a) {
1181
+ switch (_a.label) {
1182
+ case 0:
1183
+ start = performance.now();
1184
+ prisma = params.prisma, customAbilities = params.customAbilities, getRoles = params.getRoles, getContext = params.getContext;
1185
+ yates = new Yates(prisma);
1186
+ return [4 /*yield*/, yates.init()];
1187
+ case 1:
1188
+ _a.sent();
1189
+ return [4 /*yield*/, yates.createRoles({
1190
+ customAbilities: customAbilities,
1191
+ getRoles: getRoles,
1192
+ options: params.options,
1193
+ })];
1194
+ case 2:
1195
+ _a.sent();
1196
+ client = yates.createClient(getContext, params.options);
1197
+ debug("Setup completed in", performance.now() - start, "ms");
1198
+ return [2 /*return*/, client];
1199
+ }
1594
1200
  });
1595
1201
  }); };
1596
1202
  exports.setup = setup;
1203
+ var templateObject_1, templateObject_2, templateObject_3;
1597
1204
  //# sourceMappingURL=index.js.map