@cerebruminc/yates 3.3.2-beta.dangerous.6e79492 → 3.3.2-beta.dangerous.8bebbaf

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
@@ -177,11 +177,11 @@ var createClient = function (prisma, getContext, options) {
177
177
  query: {
178
178
  $allModels: {
179
179
  $allOperations: function (params) {
180
+ var _a;
180
181
  return __awaiter(this, void 0, void 0, function () {
181
- var model, args, query, operation, ctx, role, context, pgRole, _a, _b, k, _c, _d, v, queryResults, e_1;
182
- var e_2, _e, e_3, _f;
182
+ var model, args, query, operation, ctx, role, context, pgRole, _b, _c, k, _d, _e, v, queryResults, e_1;
183
+ var e_2, _f, e_3, _g;
183
184
  var _this = this;
184
- var _g;
185
185
  return __generator(this, function (_h) {
186
186
  switch (_h.label) {
187
187
  case 0:
@@ -201,8 +201,8 @@ var createClient = function (prisma, getContext, options) {
201
201
  pgRole = (0, exports.createRoleName)(role);
202
202
  if (context) {
203
203
  try {
204
- for (_a = __values(Object.keys(context)), _b = _a.next(); !_b.done; _b = _a.next()) {
205
- k = _b.value;
204
+ for (_b = __values(Object.keys(context)), _c = _b.next(); !_c.done; _c = _b.next()) {
205
+ k = _c.value;
206
206
  if (!k.match(/^[a-z_\.]+$/)) {
207
207
  throw new Error("Context variable \"".concat(k, "\" contains invalid characters. Context variables must only contain lowercase letters, numbers, periods and underscores."));
208
208
  }
@@ -213,8 +213,8 @@ var createClient = function (prisma, getContext, options) {
213
213
  }
214
214
  if (Array.isArray(context[k])) {
215
215
  try {
216
- for (_c = (e_3 = void 0, __values(context[k])), _d = _c.next(); !_d.done; _d = _c.next()) {
217
- v = _d.value;
216
+ for (_d = (e_3 = void 0, __values(context[k])), _e = _d.next(); !_e.done; _e = _d.next()) {
217
+ v = _e.value;
218
218
  if (typeof v !== "string") {
219
219
  throw new Error("Context variable \"".concat(k, "\" must be an array of strings. Got ").concat(typeof v));
220
220
  }
@@ -223,7 +223,7 @@ var createClient = function (prisma, getContext, options) {
223
223
  catch (e_3_1) { e_3 = { error: e_3_1 }; }
224
224
  finally {
225
225
  try {
226
- if (_d && !_d.done && (_f = _c.return)) _f.call(_c);
226
+ if (_e && !_e.done && (_g = _d.return)) _g.call(_d);
227
227
  }
228
228
  finally { if (e_3) throw e_3.error; }
229
229
  }
@@ -235,7 +235,7 @@ var createClient = function (prisma, getContext, options) {
235
235
  catch (e_2_1) { e_2 = { error: e_2_1 }; }
236
236
  finally {
237
237
  try {
238
- if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
238
+ if (_c && !_c.done && (_f = _b.return)) _f.call(_b);
239
239
  }
240
240
  finally { if (e_2) throw e_2.error; }
241
241
  }
@@ -307,7 +307,7 @@ var createClient = function (prisma, getContext, options) {
307
307
  case 3:
308
308
  e_1 = _h.sent();
309
309
  // Normalize RLS errors to make them a bit more readable.
310
- if ((_g = e_1.message) === null || _g === void 0 ? void 0 : _g.includes("new row violates row-level security policy for table")) {
310
+ if ((_a = e_1.message) === null || _a === void 0 ? void 0 : _a.includes("new row violates row-level security policy for table")) {
311
311
  throw new Error("You do not have permission to perform this action: ".concat(model, ".").concat(operation, "(...)"));
312
312
  }
313
313
  throw e_1;
@@ -322,266 +322,315 @@ var createClient = function (prisma, getContext, options) {
322
322
  return client;
323
323
  };
324
324
  exports.createClient = createClient;
325
- var setRLS = function (prisma, table, roleName, operation, rawExpression) { return __awaiter(void 0, void 0, void 0, function () {
326
- var expression, policyName, rows;
327
- return __generator(this, function (_a) {
328
- switch (_a.label) {
325
+ var setRLS = function (prisma,
326
+ // biome-ignore lint/suspicious/noExplicitAny: TODO fix this, by providing the correct type for the catalog
327
+ policies, table, roleName, operation, rawExpression) { return __awaiter(void 0, void 0, void 0, function () {
328
+ var expression, policyName, rows, normalizedExpression, normalizedQual;
329
+ var _a, _b, _c, _d;
330
+ return __generator(this, function (_e) {
331
+ switch (_e.label) {
329
332
  case 0:
330
333
  debug("Calculating RLS expression from", rawExpression);
331
334
  return [4 /*yield*/, (0, expressions_1.expressionToSQL)(rawExpression, table)];
332
335
  case 1:
333
- expression = _a.sent();
336
+ expression = _e.sent();
334
337
  policyName = roleName;
335
- return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\tselect * from pg_catalog.pg_policies where tablename = '".concat(table, "' AND policyname = '").concat(policyName, "';\n\t"))];
336
- case 2:
337
- rows = _a.sent();
338
+ rows = policies.filter(function (row) { return row.tablename === table && row.policyname === policyName; });
338
339
  debug("Creating RLS policy", policyName);
339
340
  debug("On table", table);
340
341
  debug("For operation", operation);
341
342
  debug("To role", roleName);
342
343
  debug("With expression", expression);
343
- if (!(rows.length === 0)) return [3 /*break*/, 7];
344
- if (!(operation === "INSERT")) return [3 /*break*/, 4];
344
+ console.log(expression);
345
+ normalizedExpression = expression === "true"
346
+ ? expression
347
+ : "(".concat(expression.replace(/(\r\n|\n|\r)/gm, ""), ")");
348
+ normalizedQual = operation === "INSERT"
349
+ ? (_b = (_a = rows === null || rows === void 0 ? void 0 : rows[0]) === null || _a === void 0 ? void 0 : _a.with_check) === null || _b === void 0 ? void 0 : _b.replace(/(\r\n|\n|\r)/gm, "")
350
+ : (_d = (_c = rows === null || rows === void 0 ? void 0 : rows[0]) === null || _c === void 0 ? void 0 : _c.qual) === null || _d === void 0 ? void 0 : _d.replace(/(\r\n|\n|\r)/gm, "");
351
+ if (!(rows.length === 0)) return [3 /*break*/, 6];
352
+ if (!(operation === "INSERT")) return [3 /*break*/, 3];
345
353
  return [4 /*yield*/, prisma.$queryRawUnsafe("\n CREATE POLICY ".concat(policyName, " ON \"public\".\"").concat(table, "\" FOR ").concat(operation, " TO ").concat(roleName, " WITH CHECK (").concat(expression, ");\n "))];
346
- case 3:
347
- _a.sent();
348
- return [3 /*break*/, 6];
349
- case 4: return [4 /*yield*/, prisma.$queryRawUnsafe("\n CREATE POLICY ".concat(policyName, " ON \"public\".\"").concat(table, "\" FOR ").concat(operation, " TO ").concat(roleName, " USING (").concat(expression, ");\n "))];
350
- case 5:
351
- _a.sent();
352
- _a.label = 6;
353
- case 6: return [3 /*break*/, 11];
354
- case 7:
355
- if (!(rows[0].qual !== expression)) return [3 /*break*/, 11];
356
- if (!(operation === "INSERT")) return [3 /*break*/, 9];
354
+ case 2:
355
+ _e.sent();
356
+ return [3 /*break*/, 5];
357
+ case 3: return [4 /*yield*/, prisma.$queryRawUnsafe("\n CREATE POLICY ".concat(policyName, " ON \"public\".\"").concat(table, "\" FOR ").concat(operation, " TO ").concat(roleName, " USING (").concat(expression, ");\n "))];
358
+ case 4:
359
+ _e.sent();
360
+ _e.label = 5;
361
+ case 5: return [3 /*break*/, 10];
362
+ case 6:
363
+ if (!(normalizedQual !== normalizedExpression)) return [3 /*break*/, 10];
364
+ console.count("ALTERING RLS POLICY");
365
+ console.log({ operation: operation });
366
+ console.log("ROW QUAL", normalizedQual);
367
+ console.log("NORMALIZED", normalizedExpression);
368
+ console.log("\n\n");
369
+ if (!(operation === "INSERT")) return [3 /*break*/, 8];
357
370
  return [4 /*yield*/, prisma.$queryRawUnsafe("\n ALTER POLICY ".concat(policyName, " ON \"public\".\"").concat(table, "\" TO ").concat(roleName, " WITH CHECK (").concat(expression, ");\n "))];
358
- case 8:
359
- _a.sent();
360
- return [3 /*break*/, 11];
361
- case 9: return [4 /*yield*/, prisma.$queryRawUnsafe("\n ALTER POLICY ".concat(policyName, " ON \"public\".\"").concat(table, "\" TO ").concat(roleName, " USING (").concat(expression, ");\n "))];
362
- case 10:
363
- _a.sent();
364
- _a.label = 11;
365
- case 11: return [2 /*return*/];
371
+ case 7:
372
+ _e.sent();
373
+ return [3 /*break*/, 10];
374
+ case 8: return [4 /*yield*/, prisma.$queryRawUnsafe("\n ALTER POLICY ".concat(policyName, " ON \"public\".\"").concat(table, "\" TO ").concat(roleName, " USING (").concat(expression, ");\n "))];
375
+ case 9:
376
+ _e.sent();
377
+ _e.label = 10;
378
+ case 10: return [2 /*return*/];
366
379
  }
367
380
  });
368
381
  }); };
369
- var createRoles = function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
370
- var abilities, runtimeDataModel, models, diff, models_1, models_1_1, model, ability, operation, roles, _c, _d, _e, _i, model, table, _f, _g, _h, _j, slug, ability, roleName, _loop_1, _k, _l, _m, _o, key;
371
- var e_5, _p;
372
- var _q;
373
- var prisma = _b.prisma, customAbilities = _b.customAbilities, getRoles = _b.getRoles;
374
- return __generator(this, function (_r) {
375
- switch (_r.label) {
376
- case 0:
377
- abilities = {};
378
- runtimeDataModel = prisma
379
- ._runtimeDataModel;
380
- models = Object.keys(runtimeDataModel.models).map(function (m) { return runtimeDataModel.models[m].dbName || m; });
381
- if (customAbilities) {
382
- diff = (0, difference_1.default)(Object.keys(customAbilities), models);
383
- if (diff.length) {
384
- throw new Error("Invalid models in custom abilities: ".concat(diff.join(", ")));
382
+ var createRoles = function (_a) {
383
+ var prisma = _a.prisma, customAbilities = _a.customAbilities, getRoles = _a.getRoles;
384
+ return __awaiter(void 0, void 0, void 0, function () {
385
+ var abilities, runtimeDataModel, models, diff, models_1, models_1_1, model, ability, operation, roles, pgRoles, pgPolicies, _b, _c, _d, _i, model, table, _loop_1, _e, _f, _g, _h, slug, _loop_2, _j, _k, _l, _m, key;
386
+ var e_5, _o;
387
+ var _p;
388
+ return __generator(this, function (_q) {
389
+ switch (_q.label) {
390
+ case 0:
391
+ abilities = {};
392
+ runtimeDataModel = prisma
393
+ ._runtimeDataModel;
394
+ models = Object.keys(runtimeDataModel.models).map(function (m) { return runtimeDataModel.models[m].dbName || m; });
395
+ if (customAbilities) {
396
+ diff = (0, difference_1.default)(Object.keys(customAbilities), models);
397
+ if (diff.length) {
398
+ throw new Error("Invalid models in custom abilities: ".concat(diff.join(", ")));
399
+ }
385
400
  }
386
- }
387
- try {
388
- for (models_1 = __values(models), models_1_1 = models_1.next(); !models_1_1.done; models_1_1 = models_1.next()) {
389
- model = models_1_1.value;
390
- abilities[model] = {
391
- create: {
392
- description: "Create ".concat(model),
393
- expression: "true",
394
- operation: "INSERT",
395
- // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
396
- model: model,
397
- slug: "create",
398
- },
399
- read: {
400
- description: "Read ".concat(model),
401
- expression: "true",
402
- operation: "SELECT",
403
- // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
404
- model: model,
405
- slug: "read",
406
- },
407
- update: {
408
- description: "Update ".concat(model),
409
- expression: "true",
410
- operation: "UPDATE",
411
- // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
412
- model: model,
413
- slug: "update",
414
- },
415
- delete: {
416
- description: "Delete ".concat(model),
417
- expression: "true",
418
- operation: "DELETE",
419
- // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
420
- model: model,
421
- slug: "delete",
422
- },
423
- };
424
- if (customAbilities === null || customAbilities === void 0 ? void 0 : customAbilities[model]) {
425
- for (ability in customAbilities[model]) {
426
- operation =
427
- // biome-ignore lint/style/noNonNullAssertion: TODO fix this
428
- (_q = customAbilities[model][ability]) === null || _q === void 0 ? void 0 : _q.operation;
429
- if (!operation)
430
- continue;
431
- // biome-ignore lint/style/noNonNullAssertion: TODO fix this
432
- abilities[model][ability] = __assign(__assign({}, customAbilities[model][ability]), { operation: operation,
401
+ try {
402
+ for (models_1 = __values(models), models_1_1 = models_1.next(); !models_1_1.done; models_1_1 = models_1.next()) {
403
+ model = models_1_1.value;
404
+ abilities[model] = {
405
+ // @ts-ignore
406
+ create: {
407
+ description: "Create ".concat(model),
408
+ expression: "true",
409
+ operation: "INSERT",
410
+ // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
411
+ model: model,
412
+ slug: "create",
413
+ },
414
+ read: {
415
+ description: "Read ".concat(model),
416
+ expression: "true",
417
+ operation: "SELECT",
418
+ // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
419
+ model: model,
420
+ slug: "read",
421
+ },
422
+ update: {
423
+ description: "Update ".concat(model),
424
+ expression: "true",
425
+ operation: "UPDATE",
433
426
  // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
434
- model: model, slug: ability });
427
+ model: model,
428
+ slug: "update",
429
+ },
430
+ delete: {
431
+ description: "Delete ".concat(model),
432
+ expression: "true",
433
+ operation: "DELETE",
434
+ // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
435
+ model: model,
436
+ slug: "delete",
437
+ },
438
+ };
439
+ if (customAbilities === null || customAbilities === void 0 ? void 0 : customAbilities[model]) {
440
+ for (ability in customAbilities[model]) {
441
+ operation =
442
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
443
+ (_p = customAbilities[model][ability]) === null || _p === void 0 ? void 0 : _p.operation;
444
+ if (!operation)
445
+ continue;
446
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
447
+ abilities[model][ability] = __assign(__assign({}, customAbilities[model][ability]), { operation: operation,
448
+ // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
449
+ model: model, slug: ability });
450
+ }
435
451
  }
436
452
  }
437
453
  }
438
- }
439
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
440
- finally {
441
- try {
442
- if (models_1_1 && !models_1_1.done && (_p = models_1.return)) _p.call(models_1);
454
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
455
+ finally {
456
+ try {
457
+ if (models_1_1 && !models_1_1.done && (_o = models_1.return)) _o.call(models_1);
458
+ }
459
+ finally { if (e_5) throw e_5.error; }
443
460
  }
444
- finally { if (e_5) throw e_5.error; }
445
- }
446
- roles = getRoles(abilities);
447
- _c = abilities;
448
- _d = [];
449
- for (_e in _c)
450
- _d.push(_e);
451
- _i = 0;
452
- _r.label = 1;
453
- case 1:
454
- if (!(_i < _d.length)) return [3 /*break*/, 8];
455
- _e = _d[_i];
456
- if (!(_e in _c)) return [3 /*break*/, 7];
457
- model = _e;
458
- table = model;
459
- return [4 /*yield*/, prisma.$transaction([
460
- takeLock(prisma),
461
- prisma.$queryRawUnsafe("ALTER table \"".concat(table, "\" enable row level security;")),
462
- ])];
463
- case 2:
464
- _r.sent();
465
- _f = abilities[model];
466
- _g = [];
467
- for (_h in _f)
468
- _g.push(_h);
469
- _j = 0;
470
- _r.label = 3;
471
- case 3:
472
- if (!(_j < _g.length)) return [3 /*break*/, 7];
473
- _h = _g[_j];
474
- if (!(_h in _f)) return [3 /*break*/, 6];
475
- slug = _h;
476
- ability =
477
- // biome-ignore lint/style/noNonNullAssertion: TODO fix this
478
- abilities[model][slug];
479
- if (!VALID_OPERATIONS.includes(ability.operation)) {
480
- throw new Error("Invalid operation: ".concat(ability.operation));
481
- }
482
- roleName = (0, exports.createAbilityName)(model, slug);
483
- // Check if role already exists
484
- return [4 /*yield*/, prisma.$transaction([
485
- takeLock(prisma),
486
- prisma.$queryRawUnsafe("\n\t\t\t\t\tdo\n\t\t\t\t\t$$\n\t\t\t\t\tbegin\n\t\t\t\t\tif not exists (select * from pg_catalog.pg_roles where rolname = '".concat(roleName, "') then \n\t\t\t\t\t\tcreate role ").concat(roleName, ";\n\t\t\t\t\tend if;\n\t\t\t\t\tend\n\t\t\t\t\t$$\n\t\t\t\t\t;\n\t\t\t\t")),
487
- prisma.$queryRawUnsafe("\n\t\t\t\t\tGRANT ".concat(ability.operation, " ON \"").concat(table, "\" TO ").concat(roleName, ";\n\t\t\t\t")),
488
- ])];
489
- case 4:
490
- // Check if role already exists
491
- _r.sent();
492
- if (!ability.expression) return [3 /*break*/, 6];
493
- return [4 /*yield*/, setRLS(prisma, table, roleName, ability.operation,
494
- // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
495
- ability.expression)];
496
- case 5:
497
- _r.sent();
498
- _r.label = 6;
499
- case 6:
500
- _j++;
501
- return [3 /*break*/, 3];
502
- case 7:
503
- _i++;
504
- return [3 /*break*/, 1];
505
- case 8:
506
- _loop_1 = function (key) {
507
- var role, wildCardAbilities, roleAbilities, rlsRoles, userRoles, oldRoles;
508
- return __generator(this, function (_s) {
509
- switch (_s.label) {
510
- case 0:
511
- role = (0, exports.createRoleName)(key);
512
- return [4 /*yield*/, prisma.$executeRawUnsafe("\n\t\t\tdo\n\t\t\t$$\n\t\t\tbegin\n\t\t\tif not exists (select * from pg_catalog.pg_roles where rolname = '".concat(role, "') then \n\t\t\t\tcreate role ").concat(role, ";\n\t\t\tend if;\n\t\t\tend\n\t\t\t$$\n\t\t\t;\n\t\t"))];
513
- case 1:
514
- _s.sent();
515
- wildCardAbilities = (0, flatMap_1.default)(abilities, function (model, modelName) {
516
- return (0, map_1.default)(model, function (_params, slug) {
517
- return (0, exports.createAbilityName)(modelName, slug);
518
- });
519
- });
520
- roleAbilities = roles[key];
521
- rlsRoles = roleAbilities === "*"
522
- ? wildCardAbilities
523
- : roleAbilities.map(function (ability) {
524
- // biome-ignore lint/style/noNonNullAssertion: TODO fix this
525
- return (0, exports.createAbilityName)(ability.model, ability.slug);
461
+ roles = getRoles(abilities);
462
+ debug("Setting row level security on tables");
463
+ return [4 /*yield*/, prisma.$transaction(__spreadArray([
464
+ takeLock(prisma)
465
+ ], __read(Object.keys(abilities).map(function (table) {
466
+ return prisma.$queryRawUnsafe("ALTER table \"".concat(table, "\" enable row level security;"));
467
+ })), false))];
468
+ case 1:
469
+ _q.sent();
470
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\tselect * from pg_catalog.pg_roles\n\t\t")];
471
+ case 2:
472
+ pgRoles = _q.sent();
473
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\tselect * from pg_catalog.pg_policies;\n\t")];
474
+ case 3:
475
+ pgPolicies = _q.sent();
476
+ _b = abilities;
477
+ _c = [];
478
+ for (_d in _b)
479
+ _c.push(_d);
480
+ _i = 0;
481
+ _q.label = 4;
482
+ case 4:
483
+ if (!(_i < _c.length)) return [3 /*break*/, 9];
484
+ _d = _c[_i];
485
+ if (!(_d in _b)) return [3 /*break*/, 8];
486
+ model = _d;
487
+ table = model;
488
+ _loop_1 = function (slug) {
489
+ var ability, roleName;
490
+ return __generator(this, function (_r) {
491
+ switch (_r.label) {
492
+ case 0:
493
+ ability =
494
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
495
+ abilities[model][slug];
496
+ if (!VALID_OPERATIONS.includes(ability.operation)) {
497
+ throw new Error("Invalid operation: ".concat(ability.operation));
498
+ }
499
+ roleName = (0, exports.createAbilityName)(model, slug);
500
+ // Check if role already exists
501
+ debug("Checking if role exists", roleName);
502
+ if (!pgRoles.find(function (role) { return role.rolname === roleName; })) return [3 /*break*/, 1];
503
+ debug("Role already exists", roleName);
504
+ return [3 /*break*/, 3];
505
+ case 1: return [4 /*yield*/, prisma.$transaction([
506
+ takeLock(prisma),
507
+ prisma.$queryRawUnsafe("\n\t\t\t\t\tdo\n\t\t\t\t\t$$\n\t\t\t\t\tbegin\n\t\t\t\t\tif not exists (select * from pg_catalog.pg_roles where rolname = '".concat(roleName, "') then \n\t\t\t\t\t\tcreate role ").concat(roleName, ";\n\t\t\t\t\tend if;\n\t\t\t\t\tGRANT ").concat(ability.operation, " ON \"").concat(table, "\" TO ").concat(roleName, ";\n\t\t\t\t\tend\n\t\t\t\t\t$$\n\t\t\t\t\t;\n\t\t\t\t")),
508
+ ])];
509
+ case 2:
510
+ _r.sent();
511
+ _r.label = 3;
512
+ case 3:
513
+ if (!ability.expression) return [3 /*break*/, 5];
514
+ return [4 /*yield*/, setRLS(prisma, pgPolicies, table, roleName, ability.operation,
515
+ // biome-ignore lint/suspicious/noExplicitAny: TODO fix this
516
+ ability.expression)];
517
+ case 4:
518
+ _r.sent();
519
+ _r.label = 5;
520
+ case 5:
521
+ debug("Finished setting RLS for model", model);
522
+ return [2 /*return*/];
523
+ }
524
+ });
525
+ };
526
+ _e = abilities[model];
527
+ _f = [];
528
+ for (_g in _e)
529
+ _f.push(_g);
530
+ _h = 0;
531
+ _q.label = 5;
532
+ case 5:
533
+ if (!(_h < _f.length)) return [3 /*break*/, 8];
534
+ _g = _f[_h];
535
+ if (!(_g in _e)) return [3 /*break*/, 7];
536
+ slug = _g;
537
+ return [5 /*yield**/, _loop_1(slug)];
538
+ case 6:
539
+ _q.sent();
540
+ _q.label = 7;
541
+ case 7:
542
+ _h++;
543
+ return [3 /*break*/, 5];
544
+ case 8:
545
+ _i++;
546
+ return [3 /*break*/, 4];
547
+ case 9:
548
+ _loop_2 = function (key) {
549
+ var role, wildCardAbilities, roleAbilities, rlsRoles, userRoles, oldRoles;
550
+ return __generator(this, function (_s) {
551
+ switch (_s.label) {
552
+ case 0:
553
+ role = (0, exports.createRoleName)(key);
554
+ debug("Creating role", role);
555
+ wildCardAbilities = (0, flatMap_1.default)(abilities, function (model, modelName) {
556
+ return (0, map_1.default)(model, function (_params, slug) {
557
+ return (0, exports.createAbilityName)(modelName, slug);
558
+ });
526
559
  });
527
- // 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.
528
- // 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.
529
- return [4 /*yield*/, prisma.$transaction([
560
+ roleAbilities = roles[key];
561
+ rlsRoles = roleAbilities === "*"
562
+ ? wildCardAbilities
563
+ : roleAbilities.map(function (ability) {
564
+ // biome-ignore lint/style/noNonNullAssertion: TODO fix this
565
+ return (0, exports.createAbilityName)(ability.model, ability.slug);
566
+ });
567
+ // 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.
568
+ // 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.
569
+ debug("Granting role access");
570
+ // Check if role already exists
571
+ debug("Checking if role exists", role);
572
+ if (!pgRoles.find(function (row) { return row.rolname === role; })) return [3 /*break*/, 1];
573
+ debug("Role already exists", role);
574
+ return [3 /*break*/, 3];
575
+ case 1: return [4 /*yield*/, prisma.$transaction([
530
576
  takeLock(prisma),
531
- prisma.$executeRawUnsafe("GRANT ALL ON ALL TABLES IN SCHEMA public TO ".concat(role, ";")),
532
- prisma.$executeRawUnsafe("\n\t\t\t\tGRANT ALL ON ALL SEQUENCES IN SCHEMA public TO ".concat(role, ";\n\t\t\t")),
533
- prisma.$executeRawUnsafe("\n\t\t\t\tGRANT ALL ON SCHEMA public TO ".concat(role, ";\n\t\t\t")),
534
- prisma.$queryRawUnsafe("GRANT ".concat(rlsRoles.join(", "), " TO ").concat(role)),
577
+ 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\tGRANT ALL ON ALL TABLES IN SCHEMA public TO ").concat(role, ";\n\t\t\t\tGRANT ALL ON ALL SEQUENCES IN SCHEMA public TO ").concat(role, ";\n\t\t\t\tGRANT ALL ON SCHEMA public TO ").concat(role, ";\n\t\t\t\tend\n\t\t\t\t$$\n\t\t\t\t;\n\t\t\t")),
535
578
  ])];
536
- case 2:
537
- // 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.
538
- // 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.
539
- _s.sent();
540
- return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\tWITH RECURSIVE cte AS (\n\t\t\t\tSELECT oid FROM pg_roles where rolname = '".concat(role, "'\n\t\t\t\tUNION ALL\n\t\t\t\tSELECT m.roleid\n\t\t\t\tFROM cte\n\t\t\t\tJOIN pg_auth_members m ON m.member = cte.oid\n\t\t\t\t)\n\t\t\tSELECT oid, oid::regrole::text AS rolename FROM cte where oid::regrole::text != '").concat(role, "'; \n\t "))];
541
- case 3:
542
- userRoles = _s.sent();
543
- oldRoles = userRoles
544
- .filter(function (_a) {
545
- var rolename = _a.rolename;
546
- return !rlsRoles.includes(rolename);
547
- })
548
- .map(function (_a) {
549
- var rolename = _a.rolename;
550
- return rolename;
551
- });
552
- if (!oldRoles.length) return [3 /*break*/, 5];
553
- // Now revoke old roles from the user role
554
- return [4 /*yield*/, prisma.$executeRawUnsafe("REVOKE ".concat(oldRoles.join(", "), " FROM ").concat(role))];
555
- case 4:
556
- // Now revoke old roles from the user role
557
- _s.sent();
558
- _s.label = 5;
559
- case 5: return [2 /*return*/];
560
- }
561
- });
562
- };
563
- _k = roles;
564
- _l = [];
565
- for (_m in _k)
566
- _l.push(_m);
567
- _o = 0;
568
- _r.label = 9;
569
- case 9:
570
- if (!(_o < _l.length)) return [3 /*break*/, 12];
571
- _m = _l[_o];
572
- if (!(_m in _k)) return [3 /*break*/, 11];
573
- key = _m;
574
- return [5 /*yield**/, _loop_1(key)];
575
- case 10:
576
- _r.sent();
577
- _r.label = 11;
578
- case 11:
579
- _o++;
580
- return [3 /*break*/, 9];
581
- case 12: return [2 /*return*/];
582
- }
579
+ case 2:
580
+ _s.sent();
581
+ _s.label = 3;
582
+ case 3: return [4 /*yield*/, prisma.$executeRawUnsafe("GRANT ".concat(rlsRoles.join(", "), " TO ").concat(role, ";"))];
583
+ case 4:
584
+ _s.sent();
585
+ // Cleanup any old roles that aren't included in the new roles
586
+ debug("Cleaning up old roles");
587
+ return [4 /*yield*/, prisma.$queryRawUnsafe("\n\t\t\tWITH RECURSIVE cte AS (\n\t\t\t\tSELECT oid FROM pg_roles where rolname = '".concat(role, "'\n\t\t\t\tUNION ALL\n\t\t\t\tSELECT m.roleid\n\t\t\t\tFROM cte\n\t\t\t\tJOIN pg_auth_members m ON m.member = cte.oid\n\t\t\t\t)\n\t\t\tSELECT oid, oid::regrole::text AS rolename FROM cte where oid::regrole::text != '").concat(role, "'; \n\t "))];
588
+ case 5:
589
+ userRoles = _s.sent();
590
+ oldRoles = userRoles
591
+ .filter(function (_a) {
592
+ var rolename = _a.rolename;
593
+ return !rlsRoles.includes(rolename);
594
+ })
595
+ .map(function (_a) {
596
+ var rolename = _a.rolename;
597
+ return rolename;
598
+ });
599
+ if (!oldRoles.length) return [3 /*break*/, 7];
600
+ debug("Revoking ".concat(oldRoles.length, " old roles from ").concat(role));
601
+ // Now revoke old roles from the user role
602
+ return [4 /*yield*/, prisma.$executeRawUnsafe("REVOKE ".concat(oldRoles.join(", "), " FROM ").concat(role))];
603
+ case 6:
604
+ // Now revoke old roles from the user role
605
+ _s.sent();
606
+ _s.label = 7;
607
+ case 7: return [2 /*return*/];
608
+ }
609
+ });
610
+ };
611
+ _j = roles;
612
+ _k = [];
613
+ for (_l in _j)
614
+ _k.push(_l);
615
+ _m = 0;
616
+ _q.label = 10;
617
+ case 10:
618
+ if (!(_m < _k.length)) return [3 /*break*/, 13];
619
+ _l = _k[_m];
620
+ if (!(_l in _j)) return [3 /*break*/, 12];
621
+ key = _l;
622
+ return [5 /*yield**/, _loop_2(key)];
623
+ case 11:
624
+ _q.sent();
625
+ _q.label = 12;
626
+ case 12:
627
+ _m++;
628
+ return [3 /*break*/, 10];
629
+ case 13: return [2 /*return*/];
630
+ }
631
+ });
583
632
  });
584
- }); };
633
+ };
585
634
  exports.createRoles = createRoles;
586
635
  /**
587
636
  * Creates an extended client that sets contextual parameters and user role on every query
@@ -592,6 +641,7 @@ var setup = function (params) { return __awaiter(void 0, void 0, void 0, functio
592
641
  switch (_a.label) {
593
642
  case 0:
594
643
  prisma = params.prisma, customAbilities = params.customAbilities, getRoles = params.getRoles, getContext = params.getContext;
644
+ debug("Creating roles");
595
645
  return [4 /*yield*/, (0, exports.createRoles)({
596
646
  prisma: prisma,
597
647
  customAbilities: customAbilities,
@@ -599,7 +649,9 @@ var setup = function (params) { return __awaiter(void 0, void 0, void 0, functio
599
649
  })];
600
650
  case 1:
601
651
  _a.sent();
652
+ debug("Creating client");
602
653
  client = (0, exports.createClient)(prisma, getContext, params.options);
654
+ debug("Client ready");
603
655
  return [2 /*return*/, client];
604
656
  }
605
657
  });