@carlonicora/nestjs-neo4jsonapi 1.63.0 → 1.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap/bootstrap.options.d.ts +7 -0
- package/dist/bootstrap/bootstrap.options.d.ts.map +1 -1
- package/dist/foundations/rbac/controllers/rbac-dev.controller.d.ts +50 -0
- package/dist/foundations/rbac/controllers/rbac-dev.controller.d.ts.map +1 -0
- package/dist/foundations/rbac/controllers/rbac-dev.controller.js +172 -0
- package/dist/foundations/rbac/controllers/rbac-dev.controller.js.map +1 -0
- package/dist/foundations/rbac/dsl/define-rbac.d.ts +15 -0
- package/dist/foundations/rbac/dsl/define-rbac.d.ts.map +1 -0
- package/dist/foundations/rbac/dsl/define-rbac.js +19 -0
- package/dist/foundations/rbac/dsl/define-rbac.js.map +1 -0
- package/dist/foundations/rbac/dsl/index.d.ts +6 -0
- package/dist/foundations/rbac/dsl/index.d.ts.map +1 -0
- package/dist/foundations/rbac/dsl/index.js +30 -0
- package/dist/foundations/rbac/dsl/index.js.map +1 -0
- package/dist/foundations/rbac/dsl/perm.d.ts +15 -0
- package/dist/foundations/rbac/dsl/perm.d.ts.map +1 -0
- package/dist/foundations/rbac/dsl/perm.js +24 -0
- package/dist/foundations/rbac/dsl/perm.js.map +1 -0
- package/dist/foundations/rbac/dsl/resolver.d.ts +24 -0
- package/dist/foundations/rbac/dsl/resolver.d.ts.map +1 -0
- package/dist/foundations/rbac/dsl/resolver.js +55 -0
- package/dist/foundations/rbac/dsl/resolver.js.map +1 -0
- package/dist/foundations/rbac/dsl/to-permissions-json.d.ts +13 -0
- package/dist/foundations/rbac/dsl/to-permissions-json.d.ts.map +1 -0
- package/dist/foundations/rbac/dsl/to-permissions-json.js +43 -0
- package/dist/foundations/rbac/dsl/to-permissions-json.js.map +1 -0
- package/dist/foundations/rbac/dsl/types.d.ts +55 -0
- package/dist/foundations/rbac/dsl/types.d.ts.map +1 -0
- package/dist/foundations/rbac/dsl/types.js +6 -0
- package/dist/foundations/rbac/dsl/types.js.map +1 -0
- package/dist/foundations/rbac/dump.d.ts +116 -0
- package/dist/foundations/rbac/dump.d.ts.map +1 -0
- package/dist/foundations/rbac/dump.js +154 -0
- package/dist/foundations/rbac/dump.js.map +1 -0
- package/dist/foundations/rbac/index.d.ts +6 -0
- package/dist/foundations/rbac/index.d.ts.map +1 -1
- package/dist/foundations/rbac/index.js +23 -1
- package/dist/foundations/rbac/index.js.map +1 -1
- package/dist/foundations/rbac/rbac.module.d.ts +4 -1
- package/dist/foundations/rbac/rbac.module.d.ts.map +1 -1
- package/dist/foundations/rbac/rbac.module.js +25 -11
- package/dist/foundations/rbac/rbac.module.js.map +1 -1
- package/dist/foundations/rbac/rbac.tokens.d.ts +11 -0
- package/dist/foundations/rbac/rbac.tokens.d.ts.map +1 -0
- package/dist/foundations/rbac/rbac.tokens.js +14 -0
- package/dist/foundations/rbac/rbac.tokens.js.map +1 -0
- package/dist/foundations/rbac/serializer/matrix-to-ts.d.ts +13 -0
- package/dist/foundations/rbac/serializer/matrix-to-ts.d.ts.map +1 -0
- package/dist/foundations/rbac/serializer/matrix-to-ts.js +74 -0
- package/dist/foundations/rbac/serializer/matrix-to-ts.js.map +1 -0
- package/dist/foundations/rbac/services/rbac-reconciler.service.d.ts +30 -0
- package/dist/foundations/rbac/services/rbac-reconciler.service.d.ts.map +1 -0
- package/dist/foundations/rbac/services/rbac-reconciler.service.js +192 -0
- package/dist/foundations/rbac/services/rbac-reconciler.service.js.map +1 -0
- package/dist/tools/generate-rbac-paths/index.js +24 -19
- package/package.json +1 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Driver } from "neo4j-driver";
|
|
2
|
+
/**
|
|
3
|
+
* Options for {@link dumpRbacMatrix}.
|
|
4
|
+
*/
|
|
5
|
+
export interface DumpRbacMatrixOptions {
|
|
6
|
+
/**
|
|
7
|
+
* A connected `neo4j-driver` Driver. The function opens a single session
|
|
8
|
+
* and closes it on exit, but does NOT close the driver — the caller owns
|
|
9
|
+
* the driver lifecycle.
|
|
10
|
+
*/
|
|
11
|
+
driver: Driver;
|
|
12
|
+
/**
|
|
13
|
+
* Optional database name. If omitted, the driver's default database is
|
|
14
|
+
* used. Pass this when your deployment uses a non-default database
|
|
15
|
+
* (e.g. `process.env.NEO4J_DATABASE`).
|
|
16
|
+
*/
|
|
17
|
+
database?: string;
|
|
18
|
+
/**
|
|
19
|
+
* UUID → PascalCase name map for roles. The serializer emits
|
|
20
|
+
* `RoleId.<Name>` references using these names; without them, the
|
|
21
|
+
* generated file contains raw UUIDs.
|
|
22
|
+
*
|
|
23
|
+
* Typical construction from a `RoleId` enum:
|
|
24
|
+
* ```ts
|
|
25
|
+
* Object.fromEntries(Object.entries(RoleId).map(([k, v]) => [v, k]))
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
roleNames: Record<string, string>;
|
|
29
|
+
/**
|
|
30
|
+
* UUID → PascalCase name map for modules. Same shape and purpose as
|
|
31
|
+
* `roleNames`, applied to `ModuleId.<Name>` references in the output.
|
|
32
|
+
*/
|
|
33
|
+
moduleNames: Record<string, string>;
|
|
34
|
+
/**
|
|
35
|
+
* UUID of the Administrator role. The dump writes
|
|
36
|
+
* `[RoleId.Administrator]: perm.full` for every declared module so the
|
|
37
|
+
* file matches the convention enforced by `RbacReconcilerService`
|
|
38
|
+
* (which deliberately skips Administrator edges — Admin is hardwired in
|
|
39
|
+
* code, not represented as `HAS_PERMISSIONS` edges in the DB).
|
|
40
|
+
*/
|
|
41
|
+
administratorRoleId: string;
|
|
42
|
+
/**
|
|
43
|
+
* Output path for the emitted TypeScript file. Absolute, or relative to
|
|
44
|
+
* `process.cwd()`. Parent directories are created if missing.
|
|
45
|
+
*
|
|
46
|
+
* Convention: place the file under your API app's `src/rbac/` directory
|
|
47
|
+
* (e.g. `"src/rbac/permissions.ts"` when running from the api package
|
|
48
|
+
* cwd, or `"apps/api/src/rbac/permissions.ts"` from the monorepo root).
|
|
49
|
+
*/
|
|
50
|
+
outputPath: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Result of {@link dumpRbacMatrix}.
|
|
54
|
+
*/
|
|
55
|
+
export interface DumpRbacMatrixResult {
|
|
56
|
+
/** Number of bytes written to the output file. */
|
|
57
|
+
bytesWritten: number;
|
|
58
|
+
/** Resolved absolute path that was written. */
|
|
59
|
+
path: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read the current RBAC state from Neo4j and emit a declarative-matrix
|
|
63
|
+
* `permissions.ts` source file for the consuming app to commit.
|
|
64
|
+
*
|
|
65
|
+
* **Developer-only.** This is meant to run as a one-shot CLI step when
|
|
66
|
+
* bootstrapping a new project (or re-dumping after manual DB edits during
|
|
67
|
+
* development). Do not expose this from a runtime endpoint — production
|
|
68
|
+
* servers should never write source files.
|
|
69
|
+
*
|
|
70
|
+
* The emitted file imports `RoleId` / `ModuleId` from `@neural-erp/shared`
|
|
71
|
+
* (or whichever package you've wired into `serializeMatrixToTs`), and
|
|
72
|
+
* `perm` / `defineRbac` from `@carlonicora/nestjs-neo4jsonapi`.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* // apps/api/scripts/rbac-dump.ts
|
|
77
|
+
* import * as dotenv from "dotenv";
|
|
78
|
+
* import * as path from "path";
|
|
79
|
+
* dotenv.config({ path: path.resolve(__dirname, "../../../.env") });
|
|
80
|
+
*
|
|
81
|
+
* import neo4j from "neo4j-driver";
|
|
82
|
+
* import { RoleId, ModuleId } from "@neural-erp/shared";
|
|
83
|
+
* import { dumpRbacMatrix } from "@carlonicora/nestjs-neo4jsonapi";
|
|
84
|
+
*
|
|
85
|
+
* async function main() {
|
|
86
|
+
* const driver = neo4j.driver(
|
|
87
|
+
* process.env.NEO4J_URI!,
|
|
88
|
+
* neo4j.auth.basic(process.env.NEO4J_USER!, process.env.NEO4J_PASSWORD!),
|
|
89
|
+
* );
|
|
90
|
+
* try {
|
|
91
|
+
* const result = await dumpRbacMatrix({
|
|
92
|
+
* driver,
|
|
93
|
+
* database: process.env.NEO4J_DATABASE,
|
|
94
|
+
* roleNames: Object.fromEntries(
|
|
95
|
+
* Object.entries(RoleId).map(([k, v]) => [v, k]),
|
|
96
|
+
* ),
|
|
97
|
+
* moduleNames: Object.fromEntries(
|
|
98
|
+
* Object.entries(ModuleId).map(([k, v]) => [v, k]),
|
|
99
|
+
* ),
|
|
100
|
+
* administratorRoleId: RoleId.Administrator,
|
|
101
|
+
* outputPath: path.resolve(__dirname, "../src/rbac/permissions.ts"),
|
|
102
|
+
* });
|
|
103
|
+
* console.log(`Wrote ${result.bytesWritten} bytes to ${result.path}`);
|
|
104
|
+
* } finally {
|
|
105
|
+
* await driver.close();
|
|
106
|
+
* }
|
|
107
|
+
* }
|
|
108
|
+
*
|
|
109
|
+
* main().catch((err) => {
|
|
110
|
+
* console.error(err);
|
|
111
|
+
* process.exit(1);
|
|
112
|
+
* });
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export declare function dumpRbacMatrix(opts: DumpRbacMatrixOptions): Promise<DumpRbacMatrixResult>;
|
|
116
|
+
//# sourceMappingURL=dump.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dump.d.ts","sourceRoot":"","sources":["../../../src/foundations/rbac/dump.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;;OASG;IACH,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAElC;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpC;;;;;;OAMG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAE5B;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAkD/F"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.dumpRbacMatrix = dumpRbacMatrix;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const matrix_to_ts_1 = require("./serializer/matrix-to-ts");
|
|
40
|
+
/**
|
|
41
|
+
* Read the current RBAC state from Neo4j and emit a declarative-matrix
|
|
42
|
+
* `permissions.ts` source file for the consuming app to commit.
|
|
43
|
+
*
|
|
44
|
+
* **Developer-only.** This is meant to run as a one-shot CLI step when
|
|
45
|
+
* bootstrapping a new project (or re-dumping after manual DB edits during
|
|
46
|
+
* development). Do not expose this from a runtime endpoint — production
|
|
47
|
+
* servers should never write source files.
|
|
48
|
+
*
|
|
49
|
+
* The emitted file imports `RoleId` / `ModuleId` from `@neural-erp/shared`
|
|
50
|
+
* (or whichever package you've wired into `serializeMatrixToTs`), and
|
|
51
|
+
* `perm` / `defineRbac` from `@carlonicora/nestjs-neo4jsonapi`.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // apps/api/scripts/rbac-dump.ts
|
|
56
|
+
* import * as dotenv from "dotenv";
|
|
57
|
+
* import * as path from "path";
|
|
58
|
+
* dotenv.config({ path: path.resolve(__dirname, "../../../.env") });
|
|
59
|
+
*
|
|
60
|
+
* import neo4j from "neo4j-driver";
|
|
61
|
+
* import { RoleId, ModuleId } from "@neural-erp/shared";
|
|
62
|
+
* import { dumpRbacMatrix } from "@carlonicora/nestjs-neo4jsonapi";
|
|
63
|
+
*
|
|
64
|
+
* async function main() {
|
|
65
|
+
* const driver = neo4j.driver(
|
|
66
|
+
* process.env.NEO4J_URI!,
|
|
67
|
+
* neo4j.auth.basic(process.env.NEO4J_USER!, process.env.NEO4J_PASSWORD!),
|
|
68
|
+
* );
|
|
69
|
+
* try {
|
|
70
|
+
* const result = await dumpRbacMatrix({
|
|
71
|
+
* driver,
|
|
72
|
+
* database: process.env.NEO4J_DATABASE,
|
|
73
|
+
* roleNames: Object.fromEntries(
|
|
74
|
+
* Object.entries(RoleId).map(([k, v]) => [v, k]),
|
|
75
|
+
* ),
|
|
76
|
+
* moduleNames: Object.fromEntries(
|
|
77
|
+
* Object.entries(ModuleId).map(([k, v]) => [v, k]),
|
|
78
|
+
* ),
|
|
79
|
+
* administratorRoleId: RoleId.Administrator,
|
|
80
|
+
* outputPath: path.resolve(__dirname, "../src/rbac/permissions.ts"),
|
|
81
|
+
* });
|
|
82
|
+
* console.log(`Wrote ${result.bytesWritten} bytes to ${result.path}`);
|
|
83
|
+
* } finally {
|
|
84
|
+
* await driver.close();
|
|
85
|
+
* }
|
|
86
|
+
* }
|
|
87
|
+
*
|
|
88
|
+
* main().catch((err) => {
|
|
89
|
+
* console.error(err);
|
|
90
|
+
* process.exit(1);
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
async function dumpRbacMatrix(opts) {
|
|
95
|
+
const session = opts.driver.session(opts.database ? { database: opts.database } : undefined);
|
|
96
|
+
try {
|
|
97
|
+
const modulesResult = await session.run(`MATCH (m:Module) RETURN m.id AS id, m.permissions AS permissions`);
|
|
98
|
+
const edgesResult = await session.run(`MATCH (r:Role)-[p:HAS_PERMISSIONS]->(m:Module) RETURN r.id AS roleId, m.id AS moduleId, p.permissions AS permissions`);
|
|
99
|
+
const matrix = {};
|
|
100
|
+
for (const rec of modulesResult.records) {
|
|
101
|
+
const moduleId = rec.get("id");
|
|
102
|
+
const permissions = rec.get("permissions");
|
|
103
|
+
if (!moduleId)
|
|
104
|
+
continue;
|
|
105
|
+
matrix[moduleId] = { default: deserialize(permissions), ...(matrix[moduleId] ?? {}) };
|
|
106
|
+
}
|
|
107
|
+
for (const rec of edgesResult.records) {
|
|
108
|
+
const roleId = rec.get("roleId");
|
|
109
|
+
const moduleId = rec.get("moduleId");
|
|
110
|
+
const permissions = rec.get("permissions");
|
|
111
|
+
if (!matrix[moduleId])
|
|
112
|
+
matrix[moduleId] = { default: [] };
|
|
113
|
+
matrix[moduleId][roleId] = deltaFromDefault(deserialize(permissions), matrix[moduleId].default);
|
|
114
|
+
}
|
|
115
|
+
// Administrator gets perm.full on every declared module — matches the
|
|
116
|
+
// reconciler's "Administrator edges are never managed" convention.
|
|
117
|
+
for (const moduleId of Object.keys(matrix)) {
|
|
118
|
+
matrix[moduleId][opts.administratorRoleId] = [
|
|
119
|
+
{ action: "read", scope: true },
|
|
120
|
+
{ action: "create", scope: true },
|
|
121
|
+
{ action: "update", scope: true },
|
|
122
|
+
{ action: "delete", scope: true },
|
|
123
|
+
];
|
|
124
|
+
}
|
|
125
|
+
const source = await (0, matrix_to_ts_1.serializeMatrixToTs)(matrix, {
|
|
126
|
+
roleNames: opts.roleNames,
|
|
127
|
+
moduleNames: opts.moduleNames,
|
|
128
|
+
});
|
|
129
|
+
const outPath = path.isAbsolute(opts.outputPath) ? opts.outputPath : path.resolve(process.cwd(), opts.outputPath);
|
|
130
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
131
|
+
fs.writeFileSync(outPath, source);
|
|
132
|
+
return { bytesWritten: Buffer.byteLength(source), path: outPath };
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
await session.close();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function deserialize(raw) {
|
|
139
|
+
if (!raw)
|
|
140
|
+
return [];
|
|
141
|
+
const arr = JSON.parse(raw);
|
|
142
|
+
return arr
|
|
143
|
+
.filter((e) => e.value !== false)
|
|
144
|
+
.map((e) => ({
|
|
145
|
+
action: e.type,
|
|
146
|
+
scope: e.value === true ? true : e.value,
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
function deltaFromDefault(effective, defaults) {
|
|
150
|
+
// Naive shallow comparison — sufficient because tokens are flat
|
|
151
|
+
// {action, scope} records.
|
|
152
|
+
return effective.filter((e) => !defaults.some((d) => d.action === e.action && d.scope === e.scope));
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=dump.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dump.js","sourceRoot":"","sources":["../../../src/foundations/rbac/dump.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,4 +4,10 @@ export { permissionMappingMeta } from "./entities/permission-mapping.meta";
|
|
|
4
4
|
export { modulePathsMeta } from "./entities/module-paths.meta";
|
|
5
5
|
export type { PermissionMapping } from "./entities/permission-mapping.entity";
|
|
6
6
|
export type { ModuleRelationshipPaths } from "./entities/module-paths.entity";
|
|
7
|
+
export { perm, defineRbac, toPermissionsJson } from "./dsl";
|
|
8
|
+
export { resolveForRole, resolveDefault, iterateDeclaredEdges, iterateDeclaredModules } from "./dsl";
|
|
9
|
+
export { ACTION_ORDER } from "./dsl";
|
|
10
|
+
export type { PermToken, ModuleBlock, RbacMatrix, ResolvedPermissions } from "./dsl";
|
|
11
|
+
export { dumpRbacMatrix } from "./dump";
|
|
12
|
+
export type { DumpRbacMatrixOptions, DumpRbacMatrixResult } from "./dump";
|
|
7
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/foundations/rbac/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/foundations/rbac/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAI9E,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAC;AACrG,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAKrF,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AACxC,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.modulePathsMeta = exports.permissionMappingMeta = exports.MODULE_USER_PATHS_TOKEN = exports.RbacModule = void 0;
|
|
3
|
+
exports.dumpRbacMatrix = exports.ACTION_ORDER = exports.iterateDeclaredModules = exports.iterateDeclaredEdges = exports.resolveDefault = exports.resolveForRole = exports.toPermissionsJson = exports.defineRbac = exports.perm = exports.modulePathsMeta = exports.permissionMappingMeta = exports.MODULE_USER_PATHS_TOKEN = exports.RbacModule = void 0;
|
|
4
4
|
var rbac_module_1 = require("./rbac.module");
|
|
5
5
|
Object.defineProperty(exports, "RbacModule", { enumerable: true, get: function () { return rbac_module_1.RbacModule; } });
|
|
6
6
|
var rbac_constants_1 = require("./rbac.constants");
|
|
@@ -9,4 +9,26 @@ var permission_mapping_meta_1 = require("./entities/permission-mapping.meta");
|
|
|
9
9
|
Object.defineProperty(exports, "permissionMappingMeta", { enumerable: true, get: function () { return permission_mapping_meta_1.permissionMappingMeta; } });
|
|
10
10
|
var module_paths_meta_1 = require("./entities/module-paths.meta");
|
|
11
11
|
Object.defineProperty(exports, "modulePathsMeta", { enumerable: true, get: function () { return module_paths_meta_1.modulePathsMeta; } });
|
|
12
|
+
// RBAC DSL — re-export explicitly to avoid `Action` collision with
|
|
13
|
+
// `common/enums/action.ts` at the library root.
|
|
14
|
+
var dsl_1 = require("./dsl");
|
|
15
|
+
Object.defineProperty(exports, "perm", { enumerable: true, get: function () { return dsl_1.perm; } });
|
|
16
|
+
Object.defineProperty(exports, "defineRbac", { enumerable: true, get: function () { return dsl_1.defineRbac; } });
|
|
17
|
+
Object.defineProperty(exports, "toPermissionsJson", { enumerable: true, get: function () { return dsl_1.toPermissionsJson; } });
|
|
18
|
+
var dsl_2 = require("./dsl");
|
|
19
|
+
Object.defineProperty(exports, "resolveForRole", { enumerable: true, get: function () { return dsl_2.resolveForRole; } });
|
|
20
|
+
Object.defineProperty(exports, "resolveDefault", { enumerable: true, get: function () { return dsl_2.resolveDefault; } });
|
|
21
|
+
Object.defineProperty(exports, "iterateDeclaredEdges", { enumerable: true, get: function () { return dsl_2.iterateDeclaredEdges; } });
|
|
22
|
+
Object.defineProperty(exports, "iterateDeclaredModules", { enumerable: true, get: function () { return dsl_2.iterateDeclaredModules; } });
|
|
23
|
+
var dsl_3 = require("./dsl");
|
|
24
|
+
Object.defineProperty(exports, "ACTION_ORDER", { enumerable: true, get: function () { return dsl_3.ACTION_ORDER; } });
|
|
25
|
+
// Developer-only one-shot tool to read the current DB state and emit a
|
|
26
|
+
// declarative `permissions.ts` source file. CLI use only — see the JSDoc
|
|
27
|
+
// on `dumpRbacMatrix` for the canonical script template.
|
|
28
|
+
var dump_1 = require("./dump");
|
|
29
|
+
Object.defineProperty(exports, "dumpRbacMatrix", { enumerable: true, get: function () { return dump_1.dumpRbacMatrix; } });
|
|
30
|
+
// Note: the DSL's `Action` string-literal union is intentionally not re-exported
|
|
31
|
+
// from the library root; `common/enums/action.ts` already exports an `Action`
|
|
32
|
+
// enum with the same string values. Deep consumers can import it via
|
|
33
|
+
// `@carlonicora/nestjs-neo4jsonapi/foundations/rbac/dsl` if needed.
|
|
12
34
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/foundations/rbac/index.ts"],"names":[],"mappings":";;;AAAA,6CAA2C;AAAlC,yGAAA,UAAU,OAAA;AACnB,mDAA2D;AAAlD,yHAAA,uBAAuB,OAAA;AAChC,8EAA2E;AAAlE,gIAAA,qBAAqB,OAAA;AAC9B,kEAA+D;AAAtD,oHAAA,eAAe,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/foundations/rbac/index.ts"],"names":[],"mappings":";;;AAAA,6CAA2C;AAAlC,yGAAA,UAAU,OAAA;AACnB,mDAA2D;AAAlD,yHAAA,uBAAuB,OAAA;AAChC,8EAA2E;AAAlE,gIAAA,qBAAqB,OAAA;AAC9B,kEAA+D;AAAtD,oHAAA,eAAe,OAAA;AAIxB,mEAAmE;AACnE,gDAAgD;AAChD,6BAA4D;AAAnD,2FAAA,IAAI,OAAA;AAAE,iGAAA,UAAU,OAAA;AAAE,wGAAA,iBAAiB,OAAA;AAC5C,6BAAqG;AAA5F,qGAAA,cAAc,OAAA;AAAE,qGAAA,cAAc,OAAA;AAAE,2GAAA,oBAAoB,OAAA;AAAE,6GAAA,sBAAsB,OAAA;AACrF,6BAAqC;AAA5B,mGAAA,YAAY,OAAA;AAGrB,uEAAuE;AACvE,yEAAyE;AACzE,yDAAyD;AACzD,+BAAwC;AAA/B,sGAAA,cAAc,OAAA;AAEvB,iFAAiF;AACjF,8EAA8E;AAC9E,qEAAqE;AACrE,oEAAoE"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { DynamicModule } from "@nestjs/common";
|
|
2
|
+
import type { RbacMatrix } from "./dsl/types";
|
|
2
3
|
export declare class RbacModule {
|
|
3
4
|
static register(options: {
|
|
4
|
-
moduleUserPaths: Record<string, string[]>;
|
|
5
|
+
moduleUserPaths: Record<string, readonly string[]>;
|
|
6
|
+
rbac?: RbacMatrix;
|
|
7
|
+
devMode?: boolean;
|
|
5
8
|
}): DynamicModule;
|
|
6
9
|
}
|
|
7
10
|
//# sourceMappingURL=rbac.module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac.module.d.ts","sourceRoot":"","sources":["../../../src/foundations/rbac/rbac.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"rbac.module.d.ts","sourceRoot":"","sources":["../../../src/foundations/rbac/rbac.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA0B,MAAM,gBAAgB,CAAC;AAUvE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,qBACa,UAAU;IACrB,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE;QACvB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,EAAE,UAAU,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,GAAG,aAAa;CA6BlB"}
|
|
@@ -13,24 +13,38 @@ const rbac_controller_1 = require("./controllers/rbac.controller");
|
|
|
13
13
|
const rbac_module_paths_controller_1 = require("./controllers/rbac-module-paths.controller");
|
|
14
14
|
const rbac_repository_1 = require("./repositories/rbac.repository");
|
|
15
15
|
const rbac_service_1 = require("./services/rbac.service");
|
|
16
|
+
const rbac_reconciler_service_1 = require("./services/rbac-reconciler.service");
|
|
16
17
|
const permission_mapping_serialiser_1 = require("./serialisers/permission-mapping.serialiser");
|
|
17
18
|
const module_paths_serialiser_1 = require("./serialisers/module-paths.serialiser");
|
|
18
19
|
const rbac_constants_1 = require("./rbac.constants");
|
|
20
|
+
const rbac_tokens_1 = require("./rbac.tokens");
|
|
21
|
+
const rbac_dev_controller_1 = require("./controllers/rbac-dev.controller");
|
|
22
|
+
const conditional_service_decorator_1 = require("../../common/decorators/conditional-service.decorator");
|
|
19
23
|
let RbacModule = RbacModule_1 = class RbacModule {
|
|
20
24
|
static register(options) {
|
|
25
|
+
const providers = [
|
|
26
|
+
rbac_repository_1.RbacRepository,
|
|
27
|
+
rbac_service_1.RbacService,
|
|
28
|
+
permission_mapping_serialiser_1.PermissionMappingSerialiser,
|
|
29
|
+
module_paths_serialiser_1.ModulePathsSerialiser,
|
|
30
|
+
(0, conditional_service_decorator_1.createWorkerProvider)(rbac_reconciler_service_1.RbacReconcilerService),
|
|
31
|
+
{
|
|
32
|
+
provide: rbac_constants_1.MODULE_USER_PATHS_TOKEN,
|
|
33
|
+
useValue: options.moduleUserPaths,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
provide: rbac_tokens_1.RBAC_MATRIX_TOKEN,
|
|
37
|
+
useValue: options.rbac ?? null,
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
const controllers = [rbac_controller_1.RbacController, rbac_module_paths_controller_1.RbacModulePathsController];
|
|
41
|
+
if (options.devMode) {
|
|
42
|
+
controllers.push(rbac_dev_controller_1.RbacDevController);
|
|
43
|
+
}
|
|
21
44
|
return {
|
|
22
45
|
module: RbacModule_1,
|
|
23
|
-
controllers
|
|
24
|
-
providers
|
|
25
|
-
rbac_repository_1.RbacRepository,
|
|
26
|
-
rbac_service_1.RbacService,
|
|
27
|
-
permission_mapping_serialiser_1.PermissionMappingSerialiser,
|
|
28
|
-
module_paths_serialiser_1.ModulePathsSerialiser,
|
|
29
|
-
{
|
|
30
|
-
provide: rbac_constants_1.MODULE_USER_PATHS_TOKEN,
|
|
31
|
-
useValue: options.moduleUserPaths,
|
|
32
|
-
},
|
|
33
|
-
],
|
|
46
|
+
controllers,
|
|
47
|
+
providers,
|
|
34
48
|
exports: [rbac_service_1.RbacService],
|
|
35
49
|
};
|
|
36
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac.module.js","sourceRoot":"","sources":["../../../src/foundations/rbac/rbac.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,
|
|
1
|
+
{"version":3,"file":"rbac.module.js","sourceRoot":"","sources":["../../../src/foundations/rbac/rbac.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2CAAuE;AACvE,mEAA+D;AAC/D,6FAAuF;AACvF,oEAAgE;AAChE,0DAAsD;AACtD,gFAA2E;AAC3E,+FAA0F;AAC1F,mFAA8E;AAC9E,qDAA2D;AAC3D,+CAAkD;AAElD,2EAAsE;AACtE,yGAA6F;AAGtF,IAAM,UAAU,kBAAhB,MAAM,UAAU;IACrB,MAAM,CAAC,QAAQ,CAAC,OAIf;QACC,MAAM,SAAS,GAAe;YAC5B,gCAAc;YACd,0BAAW;YACX,2DAA2B;YAC3B,+CAAqB;YACrB,IAAA,oDAAoB,EAAC,+CAAqB,CAAC;YAC3C;gBACE,OAAO,EAAE,wCAAuB;gBAChC,QAAQ,EAAE,OAAO,CAAC,eAAe;aAClC;YACD;gBACE,OAAO,EAAE,+BAAiB;gBAC1B,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;aAC/B;SACF,CAAC;QAEF,MAAM,WAAW,GAAgB,CAAC,gCAAc,EAAE,wDAAyB,CAAC,CAAC;QAC7E,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,uCAAiB,CAAC,CAAC;QACtC,CAAC;QAED,OAAO;YACL,MAAM,EAAE,YAAU;YAClB,WAAW;YACX,SAAS;YACT,OAAO,EAAE,CAAC,0BAAW,CAAC;SACvB,CAAC;IACJ,CAAC;CACF,CAAA;AAlCY,gCAAU;qBAAV,UAAU;IADtB,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,UAAU,CAkCtB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DI token for the declarative RBAC matrix.
|
|
3
|
+
*
|
|
4
|
+
* Applications provide an `RbacMatrix` under this token; `RbacReconcilerService`
|
|
5
|
+
* reads it at bootstrap and reconciles Neo4j against it.
|
|
6
|
+
*
|
|
7
|
+
* Note: `MODULE_USER_PATHS_TOKEN` already lives in `rbac.constants.ts` — import
|
|
8
|
+
* it from there rather than duplicating it here.
|
|
9
|
+
*/
|
|
10
|
+
export declare const RBAC_MATRIX_TOKEN: unique symbol;
|
|
11
|
+
//# sourceMappingURL=rbac.tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac.tokens.d.ts","sourceRoot":"","sources":["../../../src/foundations/rbac/rbac.tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,eAA8B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RBAC_MATRIX_TOKEN = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* DI token for the declarative RBAC matrix.
|
|
6
|
+
*
|
|
7
|
+
* Applications provide an `RbacMatrix` under this token; `RbacReconcilerService`
|
|
8
|
+
* reads it at bootstrap and reconciles Neo4j against it.
|
|
9
|
+
*
|
|
10
|
+
* Note: `MODULE_USER_PATHS_TOKEN` already lives in `rbac.constants.ts` — import
|
|
11
|
+
* it from there rather than duplicating it here.
|
|
12
|
+
*/
|
|
13
|
+
exports.RBAC_MATRIX_TOKEN = Symbol("RBAC_MATRIX_TOKEN");
|
|
14
|
+
//# sourceMappingURL=rbac.tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac.tokens.js","sourceRoot":"","sources":["../../../src/foundations/rbac/rbac.tokens.ts"],"names":[],"mappings":";;;AAAA;;;;;;;;GAQG;AACU,QAAA,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RbacMatrix } from "../dsl/types";
|
|
2
|
+
interface Options {
|
|
3
|
+
roleNames: Record<string, string>;
|
|
4
|
+
moduleNames: Record<string, string>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Serialise an RbacMatrix to formatted TypeScript source.
|
|
8
|
+
* Deterministic: module and role keys are sorted by UUID; tokens are
|
|
9
|
+
* normalised per action.
|
|
10
|
+
*/
|
|
11
|
+
export declare function serializeMatrixToTs(matrix: RbacMatrix, opts: Options): Promise<string>;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=matrix-to-ts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix-to-ts.d.ts","sourceRoot":"","sources":["../../../../src/foundations/rbac/serializer/matrix-to-ts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,cAAc,CAAC;AAE1D,UAAU,OAAO;IACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC5F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.serializeMatrixToTs = serializeMatrixToTs;
|
|
7
|
+
// packages/nestjs-neo4jsonapi/src/foundations/rbac/serializer/matrix-to-ts.ts
|
|
8
|
+
const prettier_1 = __importDefault(require("prettier"));
|
|
9
|
+
/**
|
|
10
|
+
* Serialise an RbacMatrix to formatted TypeScript source.
|
|
11
|
+
* Deterministic: module and role keys are sorted by UUID; tokens are
|
|
12
|
+
* normalised per action.
|
|
13
|
+
*/
|
|
14
|
+
async function serializeMatrixToTs(matrix, opts) {
|
|
15
|
+
const moduleIds = Object.keys(matrix).sort();
|
|
16
|
+
const lines = [];
|
|
17
|
+
lines.push(`// Auto-maintained by the RBAC UI. Edit via \`pnpm dev\` + UI, or by hand.`);
|
|
18
|
+
lines.push(``);
|
|
19
|
+
lines.push(`import { RoleId, ModuleId } from "@neural-erp/shared";`);
|
|
20
|
+
lines.push(`import { perm, defineRbac } from "@carlonicora/nestjs-neo4jsonapi";`);
|
|
21
|
+
lines.push(`import { MODULE_USER_PATHS } from "../features/rbac/module-relationships.map";`);
|
|
22
|
+
lines.push(``);
|
|
23
|
+
lines.push(`export const rbac = defineRbac<typeof MODULE_USER_PATHS>({`);
|
|
24
|
+
for (const moduleId of moduleIds) {
|
|
25
|
+
const block = matrix[moduleId];
|
|
26
|
+
if (!block)
|
|
27
|
+
continue;
|
|
28
|
+
const moduleName = opts.moduleNames[moduleId];
|
|
29
|
+
if (!moduleName) {
|
|
30
|
+
throw new Error(`Unknown module UUID: ${moduleId}. Check module-id.map.json.`);
|
|
31
|
+
}
|
|
32
|
+
lines.push(` [ModuleId.${moduleName}]: {`);
|
|
33
|
+
lines.push(` default: ${renderTokens(block.default)},`);
|
|
34
|
+
const roleIds = Object.keys(block)
|
|
35
|
+
.filter((k) => k !== "default")
|
|
36
|
+
.sort();
|
|
37
|
+
for (const roleId of roleIds) {
|
|
38
|
+
const roleName = opts.roleNames[roleId];
|
|
39
|
+
if (!roleName)
|
|
40
|
+
throw new Error(`Unknown role UUID: ${roleId}`);
|
|
41
|
+
lines.push(` [RoleId.${roleName}]: ${renderTokens(block[roleId])},`);
|
|
42
|
+
}
|
|
43
|
+
lines.push(` },`);
|
|
44
|
+
}
|
|
45
|
+
lines.push(`});`);
|
|
46
|
+
lines.push(``);
|
|
47
|
+
const raw = lines.join("\n");
|
|
48
|
+
return prettier_1.default.format(raw, { parser: "typescript" });
|
|
49
|
+
}
|
|
50
|
+
function renderTokens(tokens) {
|
|
51
|
+
// `scope === false` has no emission (absence of a token is the "deny"
|
|
52
|
+
// semantics). Drop defensively before any shape-checking so malformed state
|
|
53
|
+
// never leaks to disk as `perm.X("false")`.
|
|
54
|
+
const valid = tokens.filter((t) => t.scope === true || (typeof t.scope === "string" && t.scope.length > 0));
|
|
55
|
+
// perm.full collapse
|
|
56
|
+
const isFull = valid.length === 4 && valid.every((t) => t.scope === true) && new Set(valid.map((t) => t.action)).size === 4;
|
|
57
|
+
if (isFull)
|
|
58
|
+
return "perm.full";
|
|
59
|
+
if (valid.length === 0)
|
|
60
|
+
return "[]";
|
|
61
|
+
// Render each token
|
|
62
|
+
const parts = [...valid]
|
|
63
|
+
.sort((a, b) => {
|
|
64
|
+
const order = { read: 0, create: 1, update: 2, delete: 3 };
|
|
65
|
+
return order[a.action] - order[b.action];
|
|
66
|
+
})
|
|
67
|
+
.map((t) => {
|
|
68
|
+
if (t.scope === true)
|
|
69
|
+
return `perm.${t.action}`;
|
|
70
|
+
return `perm.${t.action}("${t.scope}")`;
|
|
71
|
+
});
|
|
72
|
+
return `[${parts.join(", ")}]`;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=matrix-to-ts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matrix-to-ts.js","sourceRoot":"","sources":["../../../../src/foundations/rbac/serializer/matrix-to-ts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { OnApplicationBootstrap } from "@nestjs/common";
|
|
2
|
+
import { Neo4jService } from "../../../core/neo4j/services/neo4j.service";
|
|
3
|
+
import { AppLoggingService } from "../../../core/logging/services/logging.service";
|
|
4
|
+
import type { RbacMatrix } from "../dsl/types";
|
|
5
|
+
/**
|
|
6
|
+
* Applies the declared `RbacMatrix` to Neo4j at application bootstrap.
|
|
7
|
+
*
|
|
8
|
+
* Behaviour (per spec §6.3):
|
|
9
|
+
* - Administrator role is never written as an HAS_PERMISSIONS edge — the
|
|
10
|
+
* security layer short-circuits for it.
|
|
11
|
+
* - Module defaults are stored on `Module.permissions`.
|
|
12
|
+
* - Role-specific permissions are stored on `(Role)-[:HAS_PERMISSIONS]->(Module)`.
|
|
13
|
+
* - Deletions are scoped to modules declared in the matrix: edges for
|
|
14
|
+
* undeclared modules are left untouched.
|
|
15
|
+
* - Preflight aborts with a clear error if any referenced role or module is
|
|
16
|
+
* missing from the DB (seed migrations must run first).
|
|
17
|
+
*/
|
|
18
|
+
export declare class RbacReconcilerService implements OnApplicationBootstrap {
|
|
19
|
+
private readonly neo4j;
|
|
20
|
+
private readonly matrix;
|
|
21
|
+
private readonly logger;
|
|
22
|
+
constructor(neo4j: Neo4jService, matrix: RbacMatrix | null, logger: AppLoggingService);
|
|
23
|
+
onApplicationBootstrap(): Promise<void>;
|
|
24
|
+
private preflight;
|
|
25
|
+
private findMissing;
|
|
26
|
+
private readActualState;
|
|
27
|
+
private computeDiff;
|
|
28
|
+
private apply;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=rbac-reconciler.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rbac-reconciler.service.d.ts","sourceRoot":"","sources":["../../../../src/foundations/rbac/services/rbac-reconciler.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAC1E,OAAO,EAAE,iBAAiB,EAAE,MAAM,gDAAgD,CAAC;AAGnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAe/C;;;;;;;;;;;;GAYG;AACH,qBACa,qBAAsB,YAAW,sBAAsB;IAEhE,OAAO,CAAC,QAAQ,CAAC,KAAK;IACiB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,KAAK,EAAE,YAAY,EACoB,MAAM,EAAE,UAAU,GAAG,IAAI,EAChE,MAAM,EAAE,iBAAiB;IAGtC,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;YAsB/B,SAAS;YAyBT,WAAW;YAOX,eAAe;IAsB7B,OAAO,CAAC,WAAW;YAkEL,KAAK;CA4BpB"}
|