@rhino-dev/rhino-nestjs 4.2.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `npx rhino permissions-migrate [--apply]`
3
+ *
4
+ * Lifts per-user `userRoles.permissions` into the shared `orgRolePermission`
5
+ * role layer, reducing each user row to its delta. Dry-run unless `--apply`.
6
+ *
7
+ * Loads the consumer app's PrismaClient at runtime (the lib has no DB of its
8
+ * own). A custom client can be injected for testing.
9
+ */
10
+ export declare function runPermissionsMigrate(flags: Record<string, string | true>, deps?: {
11
+ loadPrisma?: () => any;
12
+ log?: (msg: string) => void;
13
+ }): Promise<void>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runPermissionsMigrate = runPermissionsMigrate;
4
+ const permissions_migrator_1 = require("../permissions-migrator");
5
+ /**
6
+ * `npx rhino permissions-migrate [--apply]`
7
+ *
8
+ * Lifts per-user `userRoles.permissions` into the shared `orgRolePermission`
9
+ * role layer, reducing each user row to its delta. Dry-run unless `--apply`.
10
+ *
11
+ * Loads the consumer app's PrismaClient at runtime (the lib has no DB of its
12
+ * own). A custom client can be injected for testing.
13
+ */
14
+ async function runPermissionsMigrate(flags, deps = {}) {
15
+ const apply = flags.apply === true || flags.apply === 'true';
16
+ const log = deps.log ?? ((m) => console.log(m));
17
+ let prisma;
18
+ try {
19
+ const load = deps.loadPrisma ??
20
+ (() => {
21
+ // Resolved from the consumer app's installed @prisma/client.
22
+ const { PrismaClient } = require('@prisma/client');
23
+ return new PrismaClient();
24
+ });
25
+ prisma = load();
26
+ }
27
+ catch {
28
+ log('Could not load @prisma/client. Run this from your application root where Prisma is installed.');
29
+ return;
30
+ }
31
+ try {
32
+ const result = await (0, permissions_migrator_1.migratePermissions)(prisma, { apply });
33
+ for (const line of result.lines)
34
+ log(line);
35
+ const verb = apply ? 'Migrated' : 'Would migrate';
36
+ let summary = `${verb} ${result.groupsMigrated} (org, role) group(s); ${result.rowsReduced} user row(s) reduced to deltas.`;
37
+ if (result.skippedExisting > 0) {
38
+ summary += ` Skipped ${result.skippedExisting} group(s) with an existing role layer.`;
39
+ }
40
+ log(summary);
41
+ if (!apply && result.groupsMigrated > 0) {
42
+ log('Dry-run only. Re-run with --apply to write these changes.');
43
+ }
44
+ }
45
+ finally {
46
+ if (typeof prisma.$disconnect === 'function') {
47
+ await prisma.$disconnect().catch(() => undefined);
48
+ }
49
+ }
50
+ }
51
+ //# sourceMappingURL=permissions-migrate.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions-migrate.command.js","sourceRoot":"","sources":["../../../src/cli/commands/permissions-migrate.command.ts"],"names":[],"mappings":";;AAWA,sDAyCC;AApDD,kEAA6D;AAE7D;;;;;;;;GAQG;AACI,KAAK,UAAU,qBAAqB,CACzC,KAAoC,EACpC,OAAgE,EAAE;IAElE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAExD,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,IAAI,GACR,IAAI,CAAC,UAAU;YACf,CAAC,GAAG,EAAE;gBACJ,6DAA6D;gBAC7D,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;gBACnD,OAAO,IAAI,YAAY,EAAE,CAAC;YAC5B,CAAC,CAAC,CAAC;QACL,MAAM,GAAG,IAAI,EAAE,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,GAAG,CAAC,+FAA+F,CAAC,CAAC;QACrG,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAA,yCAAkB,EAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3D,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAE3C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC;QAClD,IAAI,OAAO,GAAG,GAAG,IAAI,IAAI,MAAM,CAAC,cAAc,0BAA0B,MAAM,CAAC,WAAW,iCAAiC,CAAC;QAC5H,IAAI,MAAM,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,YAAY,MAAM,CAAC,eAAe,wCAAwC,CAAC;QACxF,CAAC;QACD,GAAG,CAAC,OAAO,CAAC,CAAC;QAEb,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;YACxC,GAAG,CAAC,2DAA2D,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;YAC7C,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;AACH,CAAC"}
package/dist/cli/index.js CHANGED
@@ -20,6 +20,7 @@ const generate_command_1 = require("./commands/generate.command");
20
20
  const blueprint_command_1 = require("./commands/blueprint.command");
21
21
  const export_postman_command_1 = require("./commands/export-postman.command");
22
22
  const export_types_command_1 = require("./commands/export-types.command");
23
+ const permissions_migrate_command_1 = require("./commands/permissions-migrate.command");
23
24
  // -----------------------------------------------------------------------
24
25
  // Flag parsing helpers
25
26
  // -----------------------------------------------------------------------
@@ -57,6 +58,7 @@ function printHelp() {
57
58
  blueprint Generate code from YAML blueprints
58
59
  export-postman Export a Postman collection
59
60
  export-types Export TypeScript type definitions
61
+ permissions-migrate Lift per-user permissions into the org role layer (--apply)
60
62
 
61
63
  Options (by command):
62
64
  blueprint
@@ -103,6 +105,9 @@ async function main(argv = process.argv.slice(2)) {
103
105
  output: typeof flags['output'] === 'string' ? flags['output'] : undefined,
104
106
  });
105
107
  break;
108
+ case 'permissions-migrate':
109
+ await (0, permissions_migrate_command_1.runPermissionsMigrate)(flags);
110
+ break;
106
111
  default:
107
112
  printHelp();
108
113
  if (command !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Lift per-user permissions into the shared org role layer.
3
+ *
4
+ * For each (organization, role) group, the literal intersection of every user's
5
+ * `userRoles.permissions` becomes the `orgRolePermission` row (the shared role
6
+ * layer). Each user's row is then reduced to only its delta
7
+ * (`grantedPermissions = permissions − roleLayer`) and its legacy `permissions`
8
+ * is cleared. Effective permissions are preserved exactly (the intersection is a
9
+ * subset of every user's set, so nothing is gained or lost).
10
+ *
11
+ * Safe & idempotent:
12
+ * - Dry-run by default; pass { apply: true } to write.
13
+ * - Groups that already have an orgRolePermission row are skipped.
14
+ * - After a run the legacy permissions are empty, so a second run is a no-op.
15
+ * - Non-tenant (null organization) rows are left untouched.
16
+ *
17
+ * The `prisma` argument is any object exposing the `userRole` and
18
+ * `orgRolePermission` delegates (a real PrismaClient, or a fake in tests).
19
+ */
20
+ export interface MigratePermissionsResult {
21
+ groupsMigrated: number;
22
+ rowsReduced: number;
23
+ skippedExisting: number;
24
+ lines: string[];
25
+ }
26
+ export declare function migratePermissions(prisma: any, { apply }?: {
27
+ apply?: boolean;
28
+ }): Promise<MigratePermissionsResult>;
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.migratePermissions = migratePermissions;
4
+ function decode(value) {
5
+ if (Array.isArray(value))
6
+ return value.filter((v) => typeof v === 'string');
7
+ if (typeof value === 'string' && value.trim() !== '') {
8
+ try {
9
+ const parsed = JSON.parse(value);
10
+ return Array.isArray(parsed) ? parsed.filter((v) => typeof v === 'string') : [];
11
+ }
12
+ catch {
13
+ return [];
14
+ }
15
+ }
16
+ return [];
17
+ }
18
+ function readOrgId(r) {
19
+ return r.organizationId ?? r.organization_id;
20
+ }
21
+ function readRoleId(r) {
22
+ return r.roleId ?? r.role_id;
23
+ }
24
+ async function migratePermissions(prisma, { apply = false } = {}) {
25
+ const userRoles = await prisma.userRole.findMany();
26
+ const relevant = userRoles.filter((r) => readOrgId(r) != null && readRoleId(r) != null);
27
+ const groups = new Map();
28
+ for (const r of relevant) {
29
+ const key = `${readOrgId(r)}::${readRoleId(r)}`;
30
+ const bucket = groups.get(key);
31
+ if (bucket)
32
+ bucket.push(r);
33
+ else
34
+ groups.set(key, [r]);
35
+ }
36
+ let groupsMigrated = 0;
37
+ let rowsReduced = 0;
38
+ let skippedExisting = 0;
39
+ const lines = [];
40
+ for (const rows of groups.values()) {
41
+ const withLegacy = rows.filter((r) => decode(r.permissions).length > 0);
42
+ if (withLegacy.length === 0)
43
+ continue;
44
+ const orgId = readOrgId(rows[0]);
45
+ const roleId = readRoleId(rows[0]);
46
+ const existing = await prisma.orgRolePermission.findFirst({
47
+ where: { organizationId: orgId, roleId: roleId },
48
+ });
49
+ if (existing) {
50
+ skippedExisting++;
51
+ continue;
52
+ }
53
+ const sets = withLegacy.map((r) => decode(r.permissions));
54
+ const roleLayer = sets.reduce((acc, set) => acc.filter((p) => set.includes(p)));
55
+ lines.push(`org=${orgId} role=${roleId} → role layer [${roleLayer.join(', ')}] (${withLegacy.length} user rows)`);
56
+ if (apply) {
57
+ await prisma.orgRolePermission.create({
58
+ data: { organizationId: orgId, roleId: roleId, permissions: roleLayer },
59
+ });
60
+ for (const r of withLegacy) {
61
+ const legacy = decode(r.permissions);
62
+ const grants = decode(r.grantedPermissions ?? r.granted_permissions);
63
+ const delta = Array.from(new Set([...legacy.filter((p) => !roleLayer.includes(p)), ...grants]));
64
+ await prisma.userRole.update({
65
+ where: { id: r.id },
66
+ data: { permissions: [], grantedPermissions: delta },
67
+ });
68
+ }
69
+ }
70
+ groupsMigrated++;
71
+ rowsReduced += withLegacy.length;
72
+ }
73
+ return { groupsMigrated, rowsReduced, skippedExisting, lines };
74
+ }
75
+ //# sourceMappingURL=permissions-migrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissions-migrator.js","sourceRoot":"","sources":["../../src/cli/permissions-migrator.ts"],"names":[],"mappings":"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"}
@@ -56,8 +56,11 @@ let GroupMembershipGuard = class GroupMembershipGuard {
56
56
  if (rows.length === 0) {
57
57
  throw rhino_exception_1.RhinoException.membershipDenied();
58
58
  }
59
- // Switch the permission source to the matched membership row(s).
59
+ // Switch the permission source to the matched membership row(s). Both the
60
+ // allow set (legacy ∪ granted ∪ role layer) and the deny set come from the
61
+ // matched rows only; deny wins downstream in `userHasPermission`.
60
62
  user.__membershipPermissions = this.membership.permissionsFromRows(rows);
63
+ user.__membershipDeniedPermissions = this.membership.deniedFromRows(rows);
61
64
  return true;
62
65
  }
63
66
  };
@@ -1 +1 @@
1
- {"version":3,"file":"group-membership.guard.js","sourceRoot":"","sources":["../../src/guards/group-membership.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAIwB;AACxB,kDAAqD;AACrD,uEAAmE;AACnE,+DAA2D;AAG3D;;;;;;;;;;;;;;;GAeG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAEZ;IACA;IAFnB,YACmB,MAA0B,EAC1B,UAA6B;QAD7B,WAAM,GAAN,MAAM,CAAoB;QAC1B,eAAU,GAAV,UAAU,CAAmB;IAC7C,CAAC;IAEJ,WAAW,CAAC,OAAyB;QACnC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE;YAAE,OAAO,IAAI,CAAC;QAE5C,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAgB,CAAC;QAC9D,IAAI,GAAG,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAChC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC,CAAC,iDAAiD;QAEzE,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC;QAC5C,0DAA0D;QAC1D,IAAI,UAAU,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAEzC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC3E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,MAAM,gCAAc,CAAC,gBAAgB,EAAE,CAAC;QAC1C,CAAC;QAED,iEAAiE;QAChE,IAAY,CAAC,uBAAuB,GAAG,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AA9BY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;qCAGgB,iCAAkB;QACd,sCAAiB;GAHrC,oBAAoB,CA8BhC"}
1
+ {"version":3,"file":"group-membership.guard.js","sourceRoot":"","sources":["../../src/guards/group-membership.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAIwB;AACxB,kDAAqD;AACrD,uEAAmE;AACnE,+DAA2D;AAG3D;;;;;;;;;;;;;;;GAeG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAEZ;IACA;IAFnB,YACmB,MAA0B,EAC1B,UAA6B;QAD7B,WAAM,GAAN,MAAM,CAAoB;QAC1B,eAAU,GAAV,UAAU,CAAmB;IAC7C,CAAC;IAEJ,WAAW,CAAC,OAAyB;QACnC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE;YAAE,OAAO,IAAI,CAAC;QAE5C,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAgB,CAAC;QAC9D,IAAI,GAAG,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAChC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC,CAAC,iDAAiD;QAEzE,MAAM,UAAU,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC;QAC5C,0DAA0D;QAC1D,IAAI,UAAU,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAEzC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,IAAI,IAAI,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC3E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,MAAM,gCAAc,CAAC,gBAAgB,EAAE,CAAC;QAC1C,CAAC;QAED,0EAA0E;QAC1E,2EAA2E;QAC3E,kEAAkE;QACjE,IAAY,CAAC,uBAAuB,GAAG,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACjF,IAAY,CAAC,6BAA6B,GAAG,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACnF,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAjCY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;qCAGgB,iCAAkB;QACd,sCAAiB;GAHrC,oBAAoB,CAiChC"}
@@ -52,12 +52,27 @@ let JwtAuthGuard = class JwtAuthGuard {
52
52
  // behavior is byte-for-byte unchanged.
53
53
  let user = null;
54
54
  if (this.config.multiTenantEnabled()) {
55
+ // Preferred: also eager-load the org role layer (org_role_permissions) so
56
+ // layered permission resolution has the role-level grants. Apps that have
57
+ // not added the OrgRolePermission relation will throw on this include —
58
+ // fall back to the role-only include (grant/deny columns are scalars and
59
+ // still load there), then to a plain lookup. Existing behavior is unchanged.
55
60
  user = await delegate
56
61
  .findUnique({
57
62
  where: { id: payload.sub },
58
- include: { userRoles: { include: { role: true } } },
63
+ include: {
64
+ userRoles: { include: { role: { include: { orgRolePermissions: true } } } },
65
+ },
59
66
  })
60
67
  .catch(() => null);
68
+ if (!user) {
69
+ user = await delegate
70
+ .findUnique({
71
+ where: { id: payload.sub },
72
+ include: { userRoles: { include: { role: true } } },
73
+ })
74
+ .catch(() => null);
75
+ }
61
76
  }
62
77
  if (!user) {
63
78
  user = await delegate
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../src/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAIwB;AACxB,2DAAuD;AACvD,6DAAyD;AACzD,kDAAqD;AACrD,+DAA2D;AAG3D;;;;GAIG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAY;IAEJ;IACA;IACA;IAHnB,YACmB,IAAiB,EACjB,MAAqB,EACrB,MAA0B;QAF1B,SAAI,GAAJ,IAAI,CAAa;QACjB,WAAM,GAAN,MAAM,CAAe;QACrB,WAAM,GAAN,MAAM,CAAoB;IAC1C,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAgB,CAAC;QAC9D,IAAI,GAAG,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YAClC,MAAM,gCAAc,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1C,MAAM,gCAAc,CAAC,YAAY,CAAC,wBAAwB,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,gEAAgE;QAChE,4EAA4E;QAC5E,yEAAyE;QACzE,wEAAwE;QACxE,6EAA6E;QAC7E,uCAAuC;QACvC,IAAI,IAAI,GAAQ,IAAI,CAAC;QACrB,IAAI,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,EAAE,CAAC;YACrC,IAAI,GAAG,MAAM,QAAQ;iBAClB,UAAU,CAAC;gBACV,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE;gBAC1B,OAAO,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;aACpD,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,MAAM,QAAQ;iBAClB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;iBAC1C,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,IAAI;YAAE,MAAM,gCAAc,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;QAC/D,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AA7CY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;qCAGc,0BAAW;QACT,8BAAa;QACb,iCAAkB;GAJlC,YAAY,CA6CxB"}
1
+ {"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../src/guards/jwt-auth.guard.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,8 @@ export interface MembershipRow {
8
8
  routeGroup: string | null;
9
9
  organizationId: number | string | null;
10
10
  permissions: unknown;
11
+ grantedPermissions?: unknown;
12
+ deniedPermissions?: unknown;
11
13
  role?: any;
12
14
  }
13
15
  /**
@@ -49,8 +51,14 @@ export declare class MembershipService {
49
51
  id: number | string;
50
52
  } | null | undefined, isTenant: boolean): boolean;
51
53
  /**
52
- * Permissions granted to the user from the matched membership rows only
54
+ * ALLOW permissions resolved from the matched membership rows only
53
55
  * (design §6: "permissions then resolve from that matching membership row").
56
+ * Layered: each row contributes legacy ∪ granted ∪ org role layer.
54
57
  */
55
58
  permissionsFromRows(rows: MembershipRow[]): string[];
59
+ /**
60
+ * DENY permissions resolved from the matched membership rows. Deny always
61
+ * wins over the allow set ({@link permissionsFromRows}).
62
+ */
63
+ deniedFromRows(rows: MembershipRow[]): string[];
56
64
  }
@@ -80,6 +80,8 @@ let MembershipService = class MembershipService {
80
80
  routeGroup: rowGroup,
81
81
  organizationId: rowOrg,
82
82
  permissions: ur.permissions,
83
+ grantedPermissions: ur.grantedPermissions ?? ur.granted_permissions,
84
+ deniedPermissions: ur.deniedPermissions ?? ur.denied_permissions,
83
85
  role: ur.role,
84
86
  });
85
87
  }
@@ -93,13 +95,26 @@ let MembershipService = class MembershipService {
93
95
  return this.matchingRows(user, routeGroup, organization, isTenant).length > 0;
94
96
  }
95
97
  /**
96
- * Permissions granted to the user from the matched membership rows only
98
+ * ALLOW permissions resolved from the matched membership rows only
97
99
  * (design §6: "permissions then resolve from that matching membership row").
100
+ * Layered: each row contributes legacy ∪ granted ∪ org role layer.
98
101
  */
99
102
  permissionsFromRows(rows) {
100
103
  const out = [];
101
104
  for (const r of rows) {
102
- for (const p of (0, permission_matcher_1.coercePermissions)(r.permissions))
105
+ for (const p of (0, permission_matcher_1.rowAllowPermissions)(r))
106
+ out.push(p);
107
+ }
108
+ return out;
109
+ }
110
+ /**
111
+ * DENY permissions resolved from the matched membership rows. Deny always
112
+ * wins over the allow set ({@link permissionsFromRows}).
113
+ */
114
+ deniedFromRows(rows) {
115
+ const out = [];
116
+ for (const r of rows) {
117
+ for (const p of (0, permission_matcher_1.rowDeniedPermissions)(r))
103
118
  out.push(p);
104
119
  }
105
120
  return out;
@@ -1 +1 @@
1
- {"version":3,"file":"membership.service.js","sourceRoot":"","sources":["../../src/services/membership.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"membership.service.js","sourceRoot":"","sources":["../../src/services/membership.service.ts"],"names":[],"mappings":"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"}