@i4e/invest4edu-access-core 0.1.0 → 0.2.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/package.json +4 -3
- package/src/index.js +8 -2
- package/src/role-capabilities.js +79 -0
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@i4e/invest4edu-access-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Shared tenant-isolation / access-control primitives (Track 3 D1 keystone) for NeoFindesk backends.",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Shared tenant-isolation / access-control primitives (Track 3 D1 keystone + role capabilities) for NeoFindesk backends.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": "./src/index.js",
|
|
8
8
|
"./tenant-context": "./src/tenant-context.js",
|
|
9
|
-
"./tenant-plugin": "./src/tenant-plugin.js"
|
|
9
|
+
"./tenant-plugin": "./src/tenant-plugin.js",
|
|
10
|
+
"./role-capabilities": "./src/role-capabilities.js"
|
|
10
11
|
},
|
|
11
12
|
"files": [
|
|
12
13
|
"src",
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* @i4e/invest4edu-access-core — shared access-control primitives for the NFD backends.
|
|
3
|
+
* Tenant isolation (D1 keystone) + role capabilities (G7).
|
|
4
4
|
*/
|
|
5
5
|
export { default as als, runWithTenant, runAsSystem, getTenantStore } from "./tenant-context.js";
|
|
6
6
|
export { default as tenantPlugin } from "./tenant-plugin.js";
|
|
7
|
+
export {
|
|
8
|
+
CAPABILITY_FLAGS,
|
|
9
|
+
DEFAULT_ROLE_CAPABILITIES,
|
|
10
|
+
buildCapabilityMap,
|
|
11
|
+
resolveCapabilities,
|
|
12
|
+
} from "./role-capabilities.js";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role capabilities — @i4e/invest4edu-access-core (Track 3 C1 · G7).
|
|
3
|
+
*
|
|
4
|
+
* Turns role classification from hardcoded per-repo Sets into DATA. A `roleCapabilities`
|
|
5
|
+
* collection (one row per role) overrides these defaults; with no rows, `resolveCapabilities`
|
|
6
|
+
* reproduces the exact legacy behaviour, so wiring this in is behaviour-neutral until config
|
|
7
|
+
* is populated.
|
|
8
|
+
*
|
|
9
|
+
* Flags:
|
|
10
|
+
* isFullAccess — sees all data within the account (BROKER_ADMIN-style super-role)
|
|
11
|
+
* isEmployee — eligible for the reportee-tree / 5-field visibility scope
|
|
12
|
+
* canGovernDelegation — may grant / edit / reactivate delegations
|
|
13
|
+
* canCorrectE1 — may run the audited E1 correction
|
|
14
|
+
* canCrossAccount — audited sysadmin cross-account path (default: none)
|
|
15
|
+
* productScoped — pages + records restricted to the user's mapped products
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export const CAPABILITY_FLAGS = Object.freeze([
|
|
19
|
+
"isFullAccess",
|
|
20
|
+
"isEmployee",
|
|
21
|
+
"canGovernDelegation",
|
|
22
|
+
"canCorrectE1",
|
|
23
|
+
"canCrossAccount",
|
|
24
|
+
"productScoped",
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Legacy-parity defaults. MUST mirror the hardcoded Sets they replace:
|
|
29
|
+
* FULL_ACCESS_ROLES = SUPER_ADMIN, SYSTEM_ADMIN, BROKER_ADMIN, BACKOFFICE_USER, HR_USER
|
|
30
|
+
* EMPLOYEE_ROLES = SALES_USER, PAT_SALES
|
|
31
|
+
* GRANT_ROLES (deleg)= SUPER_ADMIN, SYSTEM_ADMIN, BROKER_ADMIN
|
|
32
|
+
* ALLOWED_ROLES (e1) = SUPER_ADMIN, SYSTEM_ADMIN, BROKER_ADMIN, BACKOFFICE_USER
|
|
33
|
+
*/
|
|
34
|
+
export const DEFAULT_ROLE_CAPABILITIES = Object.freeze({
|
|
35
|
+
SUPER_ADMIN: { isFullAccess: true, canGovernDelegation: true, canCorrectE1: true },
|
|
36
|
+
SYSTEM_ADMIN: { isFullAccess: true, canGovernDelegation: true, canCorrectE1: true },
|
|
37
|
+
BROKER_ADMIN: { isFullAccess: true, canGovernDelegation: true, canCorrectE1: true },
|
|
38
|
+
BACKOFFICE_USER: { isFullAccess: true, canCorrectE1: true },
|
|
39
|
+
HR_USER: { isFullAccess: true },
|
|
40
|
+
SALES_USER: { isEmployee: true },
|
|
41
|
+
PAT_SALES: { isEmployee: true },
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function pickFlags(row) {
|
|
45
|
+
const out = {};
|
|
46
|
+
for (const f of CAPABILITY_FLAGS) if (row[f] != null) out[f] = !!row[f];
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Merge DB rows over the parity defaults → a role→capabilities map.
|
|
52
|
+
* @param {Array<{role:string} & Record<string, boolean>>} dbRows
|
|
53
|
+
*/
|
|
54
|
+
export function buildCapabilityMap(dbRows = []) {
|
|
55
|
+
const map = {};
|
|
56
|
+
for (const [role, caps] of Object.entries(DEFAULT_ROLE_CAPABILITIES)) map[role] = { ...caps };
|
|
57
|
+
for (const row of dbRows) {
|
|
58
|
+
if (!row || !row.role) continue;
|
|
59
|
+
map[row.role] = { ...(map[row.role] || {}), ...pickFlags(row) };
|
|
60
|
+
}
|
|
61
|
+
return map;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* OR-combine the capability flags across all of a caller's roles (multi-role = union).
|
|
66
|
+
* @param {string[]} roles
|
|
67
|
+
* @param {Record<string, Record<string, boolean>>} [capabilityMap] defaults if omitted
|
|
68
|
+
* @returns {Record<string, boolean>} every CAPABILITY_FLAG resolved to a boolean
|
|
69
|
+
*/
|
|
70
|
+
export function resolveCapabilities(roles, capabilityMap = DEFAULT_ROLE_CAPABILITIES) {
|
|
71
|
+
const out = {};
|
|
72
|
+
for (const f of CAPABILITY_FLAGS) out[f] = false;
|
|
73
|
+
for (const role of Array.isArray(roles) ? roles : [roles].filter(Boolean)) {
|
|
74
|
+
const caps = capabilityMap[role];
|
|
75
|
+
if (!caps) continue;
|
|
76
|
+
for (const f of CAPABILITY_FLAGS) if (caps[f]) out[f] = true;
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|