@vertesia/studio-utils 1.4.0-dev.20260615.051508Z → 1.4.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.
Files changed (45) hide show
  1. package/lib/conditions/index.d.ts +2 -0
  2. package/lib/conditions/index.d.ts.map +1 -0
  3. package/lib/conditions/index.js +2 -0
  4. package/lib/conditions/index.js.map +1 -0
  5. package/lib/conditions/match.d.ts +54 -0
  6. package/lib/conditions/match.d.ts.map +1 -0
  7. package/lib/conditions/match.js +156 -0
  8. package/lib/conditions/match.js.map +1 -0
  9. package/lib/index.d.ts +1 -0
  10. package/lib/index.d.ts.map +1 -1
  11. package/lib/index.js +1 -0
  12. package/lib/index.js.map +1 -1
  13. package/lib/logger.d.ts +6 -0
  14. package/lib/logger.d.ts.map +1 -0
  15. package/lib/logger.js +15 -0
  16. package/lib/logger.js.map +1 -0
  17. package/lib/roles/classes.d.ts +59 -0
  18. package/lib/roles/classes.d.ts.map +1 -0
  19. package/lib/roles/classes.js +60 -0
  20. package/lib/roles/classes.js.map +1 -0
  21. package/lib/roles/content.d.ts +13 -0
  22. package/lib/roles/content.d.ts.map +1 -0
  23. package/lib/roles/content.js +39 -0
  24. package/lib/roles/content.js.map +1 -0
  25. package/lib/roles/index.d.ts +37 -0
  26. package/lib/roles/index.d.ts.map +1 -0
  27. package/lib/roles/index.js +87 -0
  28. package/lib/roles/index.js.map +1 -0
  29. package/lib/roles/system.d.ts +3 -0
  30. package/lib/roles/system.d.ts.map +1 -0
  31. package/lib/roles/system.js +187 -0
  32. package/lib/roles/system.js.map +1 -0
  33. package/lib/vertesia-studio-utils.js +1 -1
  34. package/lib/vertesia-studio-utils.js.map +1 -1
  35. package/package.json +26 -9
  36. package/src/conditions/index.ts +1 -0
  37. package/src/conditions/match.test.ts +75 -0
  38. package/src/conditions/match.ts +146 -0
  39. package/src/index.ts +1 -0
  40. package/src/logger.ts +25 -0
  41. package/src/roles/classes.ts +78 -0
  42. package/src/roles/content.ts +46 -0
  43. package/src/roles/index.test.ts +206 -0
  44. package/src/roles/index.ts +96 -0
  45. package/src/roles/system.ts +204 -0
@@ -0,0 +1,2 @@
1
+ export { matchConditions, matchLike, resolvePath } from './match.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conditions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { matchConditions, matchLike, resolvePath } from './match.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/conditions/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,54 @@
1
+ import type { PropertyConditions } from '@vertesia/common';
2
+ /**
3
+ * Resolve a property path against a context object.
4
+ *
5
+ * Supports:
6
+ * - `clearance` → obj.clearance
7
+ * - `email` → obj.email
8
+ * - `properties.department` → obj.properties.department (one nested level under `properties`)
9
+ *
10
+ * Returns `undefined` if any segment is missing or non-traversable.
11
+ */
12
+ export declare function resolvePath(obj: Record<string, unknown>, path: string): unknown;
13
+ /**
14
+ * Match a wildcard pattern against a string value.
15
+ *
16
+ * Supports `*` as wildcard:
17
+ * - `"*@domain.com"` — ends with
18
+ * - `"bogdan.*"` — starts with
19
+ * - `"bogdan+*@vertesia.com"` — contains
20
+ * - `"*"` — match all
21
+ *
22
+ * Case-insensitive. Non-string `value` always returns `false`.
23
+ */
24
+ export declare function matchLike(value: unknown, pattern: string): boolean;
25
+ /**
26
+ * Evaluate a PropertyConditions object against a set of properties (JS-side, in-memory).
27
+ *
28
+ * Supports the MongoDB query syntax subset shared across token-server (principal property
29
+ * matching at JWT-mint time) and zeno-server (write-path ABAC permission checks against an
30
+ * in-memory document):
31
+ *
32
+ * - Direct value match (`{ field: literal }`)
33
+ * - `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`
34
+ * - `$in`, `$nin` (against array `expected`)
35
+ * - `$exists` (boolean)
36
+ * - `$empty` (boolean) — true for undefined/null/empty-string/empty-array
37
+ * - `$like` (wildcard string, see {@link matchLike})
38
+ *
39
+ * All field-level conditions are AND'd (every field must match). Within a single field, all
40
+ * operators are AND'd.
41
+ *
42
+ * Mirrors the Mongo-side filter built by `conditionsToMongoFilter` (zeno-server utils.ts) and
43
+ * the ES-side filter built by `conditionsToEsQuery`. Use this when conditions need to be
44
+ * evaluated against a single hydrated document instead of pushed down as a query.
45
+ *
46
+ * Unknown operators emit a warning via the studio-utils logger and return false — surfacing
47
+ * misconfiguration loudly without breaking the surrounding token mint or permission check.
48
+ *
49
+ * `$principal.X` substitutions in conditions are expected to have already been resolved at
50
+ * JWT-mint time by `resolveConditions` in token-server; values reaching this function are
51
+ * concrete.
52
+ */
53
+ export declare function matchConditions(conditions: PropertyConditions, properties: Record<string, unknown>): boolean;
54
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../../src/conditions/match.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAG3D;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAQ/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKlE;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CA2D5G"}
@@ -0,0 +1,156 @@
1
+ import { getStudioUtilsLogger } from '../logger.js';
2
+ /**
3
+ * Resolve a property path against a context object.
4
+ *
5
+ * Supports:
6
+ * - `clearance` → obj.clearance
7
+ * - `email` → obj.email
8
+ * - `properties.department` → obj.properties.department (one nested level under `properties`)
9
+ *
10
+ * Returns `undefined` if any segment is missing or non-traversable.
11
+ */
12
+ export function resolvePath(obj, path) {
13
+ if (path.startsWith('properties.')) {
14
+ const properties = obj.properties;
15
+ return properties && typeof properties === 'object'
16
+ ? properties[path.slice(11)]
17
+ : undefined;
18
+ }
19
+ return obj[path];
20
+ }
21
+ /**
22
+ * Match a wildcard pattern against a string value.
23
+ *
24
+ * Supports `*` as wildcard:
25
+ * - `"*@domain.com"` — ends with
26
+ * - `"bogdan.*"` — starts with
27
+ * - `"bogdan+*@vertesia.com"` — contains
28
+ * - `"*"` — match all
29
+ *
30
+ * Case-insensitive. Non-string `value` always returns `false`.
31
+ */
32
+ export function matchLike(value, pattern) {
33
+ if (typeof value !== 'string')
34
+ return false;
35
+ // Convert wildcard pattern to regex: escape regex chars except *, then replace * with .*
36
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
37
+ return new RegExp(`^${escaped}$`, 'i').test(value);
38
+ }
39
+ function compareOrdered(value, expected, op) {
40
+ if (typeof value !== 'number' && typeof value !== 'string')
41
+ return false;
42
+ if (typeof value !== typeof expected)
43
+ return false;
44
+ const left = value;
45
+ const right = expected;
46
+ switch (op) {
47
+ case '$gt':
48
+ return left > right;
49
+ case '$gte':
50
+ return left >= right;
51
+ case '$lt':
52
+ return left < right;
53
+ case '$lte':
54
+ return left <= right;
55
+ }
56
+ }
57
+ /**
58
+ * Evaluate a PropertyConditions object against a set of properties (JS-side, in-memory).
59
+ *
60
+ * Supports the MongoDB query syntax subset shared across token-server (principal property
61
+ * matching at JWT-mint time) and zeno-server (write-path ABAC permission checks against an
62
+ * in-memory document):
63
+ *
64
+ * - Direct value match (`{ field: literal }`)
65
+ * - `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`
66
+ * - `$in`, `$nin` (against array `expected`)
67
+ * - `$exists` (boolean)
68
+ * - `$empty` (boolean) — true for undefined/null/empty-string/empty-array
69
+ * - `$like` (wildcard string, see {@link matchLike})
70
+ *
71
+ * All field-level conditions are AND'd (every field must match). Within a single field, all
72
+ * operators are AND'd.
73
+ *
74
+ * Mirrors the Mongo-side filter built by `conditionsToMongoFilter` (zeno-server utils.ts) and
75
+ * the ES-side filter built by `conditionsToEsQuery`. Use this when conditions need to be
76
+ * evaluated against a single hydrated document instead of pushed down as a query.
77
+ *
78
+ * Unknown operators emit a warning via the studio-utils logger and return false — surfacing
79
+ * misconfiguration loudly without breaking the surrounding token mint or permission check.
80
+ *
81
+ * `$principal.X` substitutions in conditions are expected to have already been resolved at
82
+ * JWT-mint time by `resolveConditions` in token-server; values reaching this function are
83
+ * concrete.
84
+ */
85
+ export function matchConditions(conditions, properties) {
86
+ for (const [key, condition] of Object.entries(conditions)) {
87
+ const value = resolvePath(properties, key);
88
+ if (condition === null || condition === undefined || typeof condition !== 'object') {
89
+ // Direct value match
90
+ if (value !== condition)
91
+ return false;
92
+ }
93
+ else {
94
+ // Operator object
95
+ const ops = condition;
96
+ for (const [op, expected] of Object.entries(ops)) {
97
+ switch (op) {
98
+ case '$eq':
99
+ if (value !== expected)
100
+ return false;
101
+ break;
102
+ case '$ne':
103
+ if (value === expected)
104
+ return false;
105
+ break;
106
+ case '$gt':
107
+ if (!compareOrdered(value, expected, '$gt'))
108
+ return false;
109
+ break;
110
+ case '$gte':
111
+ if (!compareOrdered(value, expected, '$gte'))
112
+ return false;
113
+ break;
114
+ case '$lt':
115
+ if (!compareOrdered(value, expected, '$lt'))
116
+ return false;
117
+ break;
118
+ case '$lte':
119
+ if (!compareOrdered(value, expected, '$lte'))
120
+ return false;
121
+ break;
122
+ case '$in':
123
+ if (!Array.isArray(expected) || !expected.includes(value))
124
+ return false;
125
+ break;
126
+ case '$nin':
127
+ if (Array.isArray(expected) && expected.includes(value))
128
+ return false;
129
+ break;
130
+ case '$exists':
131
+ if (typeof expected !== 'boolean' || (value !== undefined) !== expected)
132
+ return false;
133
+ break;
134
+ case '$empty': {
135
+ const isEmpty = value === undefined ||
136
+ value === null ||
137
+ value === '' ||
138
+ (Array.isArray(value) && value.length === 0);
139
+ if (typeof expected !== 'boolean' || isEmpty !== expected)
140
+ return false;
141
+ break;
142
+ }
143
+ case '$like':
144
+ if (typeof expected !== 'string' || !matchLike(value, expected))
145
+ return false;
146
+ break;
147
+ default:
148
+ getStudioUtilsLogger().warn({ op, key }, 'Unknown operator in PropertyConditions');
149
+ return false;
150
+ }
151
+ }
152
+ }
153
+ }
154
+ return true;
155
+ }
156
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../../src/conditions/match.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export { extractHandlebarsVariables } from './prompts/extract-vars.js';
2
2
  export { generateMockData } from './prompts/mock-data.js';
3
3
  export { executeHandlebars, executeJST, renderPrompt, renderSegments, renderSegmentsOrErrors, renderTemplate, type SegmentPreview, } from './prompts/render.js';
4
4
  export { type PromptValidationInput, type PromptValidationIssue, type PromptValidationIssueSeverity, type PromptValidationIssueType, type PromptValidationResult, validatePrompt, } from './prompts/validate.js';
5
+ export * from './roles/index.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,KAAK,cAAc,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,cAAc,GACjB,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,EACd,KAAK,cAAc,GACtB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,EAC3B,cAAc,GACjB,MAAM,uBAAuB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
package/lib/index.js CHANGED
@@ -2,4 +2,5 @@ export { extractHandlebarsVariables } from './prompts/extract-vars.js';
2
2
  export { generateMockData } from './prompts/mock-data.js';
3
3
  export { executeHandlebars, executeJST, renderPrompt, renderSegments, renderSegmentsOrErrors, renderTemplate, } from './prompts/render.js';
4
4
  export { validatePrompt, } from './prompts/validate.js';
5
+ export * from './roles/index.js';
5
6
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAMH,cAAc,GACjB,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACH,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,cAAc,GAEjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAMH,cAAc,GACjB,MAAM,uBAAuB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface StudioUtilsLogger {
2
+ warn(details: Record<string, unknown>, message: string): void;
3
+ }
4
+ export declare function getStudioUtilsLogger(): StudioUtilsLogger;
5
+ export declare function installStudioUtilsLogger(customLogger: StudioUtilsLogger): StudioUtilsLogger;
6
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAC9B,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjE;AAcD,wBAAgB,oBAAoB,IAAI,iBAAiB,CAExD;AAED,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,iBAAiB,GAAG,iBAAiB,CAI3F"}
package/lib/logger.js ADDED
@@ -0,0 +1,15 @@
1
+ const consoleLogger = {
2
+ warn: (details, message) => {
3
+ console.warn(message, details);
4
+ },
5
+ };
6
+ let logger = consoleLogger;
7
+ export function getStudioUtilsLogger() {
8
+ return logger;
9
+ }
10
+ export function installStudioUtilsLogger(customLogger) {
11
+ const previousLogger = logger;
12
+ logger = customLogger;
13
+ return previousLogger;
14
+ }
15
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAQA,MAAM,aAAa,GAAsB;IACrC,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;QACvB,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;CACJ,CAAC;AAEF,IAAI,MAAM,GAAsB,aAAa,CAAC;AAE9C,MAAM,UAAU,oBAAoB;IAChC,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,YAA+B;IACpE,MAAM,cAAc,GAAG,MAAM,CAAC;IAC9B,MAAM,GAAG,YAAY,CAAC;IACtB,OAAO,cAAc,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,59 @@
1
+ import type { AbacScope, Permission, RoleDomain } from '@vertesia/common';
2
+ /**
3
+ * Class hierarchy and registry-bound interface for the role system. These
4
+ * are LOGIC — they have runtime behavior (constructors, instance methods,
5
+ * subclass dispatch via `instanceof`). They live in `@vertesia/studio-utils`
6
+ * (not common) per the package-layering contract: only types stay in common.
7
+ */
8
+ /**
9
+ * A role: a named bundle of permissions that ACEs reference by name.
10
+ *
11
+ * Generic over the permission type so subclasses can tighten it:
12
+ * - **System roles** declare `extends Role<Permission>` — construction time
13
+ * type-checks against the central `Permission` enum.
14
+ * - **ABAC roles** (`AbacRole`) declare `extends Role<string>` — permissions
15
+ * are bare verbs (`'read'`, `'write'`, `'delete'`, future domain-specific
16
+ * verbs) consumed by the JWT generator to form `{scope}:{verb}` keys in
17
+ * `content_security`.
18
+ *
19
+ * The registry stores `Role` (defaulting to `Role<string>`) — the loose type
20
+ * is the lowest common denominator. Tight typing is only enforced at
21
+ * declaration sites of the role subclasses.
22
+ */
23
+ export declare class Role<PermissionType extends string = string> {
24
+ name: string;
25
+ domain: RoleDomain;
26
+ permissions: Set<PermissionType>;
27
+ constructor(name: string, permissions: PermissionType[], domain: RoleDomain);
28
+ hasPermission(permission: PermissionType): boolean;
29
+ }
30
+ /**
31
+ * Base class for built-in system roles. Hardcodes `domain: 'system'` and
32
+ * specializes `Role<Permission>` so subclasses get compile-time type-checking
33
+ * against the central `Permission` enum at construction.
34
+ */
35
+ export declare class SystemRole extends Role<Permission> {
36
+ constructor(name: string, permissions: Permission[]);
37
+ }
38
+ /**
39
+ * A role usable in ContentSet ACEs. Adds `applicableScopes` — the kinds of
40
+ * objects the role can be applied to at the ABAC scope level. Inherits
41
+ * `Role<string>` because ABAC verbs aren't constrained to the central
42
+ * `Permission` enum.
43
+ *
44
+ * The IAM UI filters via `listAbacRolesForScope` which checks `instanceof AbacRole`.
45
+ */
46
+ export declare class AbacRole extends Role<string> {
47
+ applicableScopes: readonly AbacScope[];
48
+ constructor(name: string, permissions: string[], domain: RoleDomain, applicableScopes: readonly AbacScope[]);
49
+ }
50
+ /**
51
+ * A logical bucket of roles owned by a single domain. The registry iterates
52
+ * partitions in registration order — first match wins. The `system` partition
53
+ * is registered first so domain partitions cannot shadow built-in system roles.
54
+ */
55
+ export interface RolePartition {
56
+ domain: RoleDomain;
57
+ roles: Map<string, Role>;
58
+ }
59
+ //# sourceMappingURL=classes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classes.d.ts","sourceRoot":"","sources":["../../src/roles/classes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,qBAAa,IAAI,CAAC,cAAc,SAAS,MAAM,GAAG,MAAM;IAGzC,IAAI,EAAE,MAAM;IAEZ,MAAM,EAAE,UAAU;IAJ7B,WAAW,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;gBAEtB,IAAI,EAAE,MAAM,EACnB,WAAW,EAAE,cAAc,EAAE,EACtB,MAAM,EAAE,UAAU;IAK7B,aAAa,CAAC,UAAU,EAAE,cAAc;CAG3C;AAED;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,IAAI,CAAC,UAAU,CAAC;gBAChC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE;CAGtD;AAED;;;;;;;GAOG;AACH,qBAAa,QAAS,SAAQ,IAAI,CAAC,MAAM,CAAC;IAK3B,gBAAgB,EAAE,SAAS,SAAS,EAAE;gBAH7C,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,UAAU,EACX,gBAAgB,EAAE,SAAS,SAAS,EAAE;CAIpD;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAC5B"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Class hierarchy and registry-bound interface for the role system. These
3
+ * are LOGIC — they have runtime behavior (constructors, instance methods,
4
+ * subclass dispatch via `instanceof`). They live in `@vertesia/studio-utils`
5
+ * (not common) per the package-layering contract: only types stay in common.
6
+ */
7
+ /**
8
+ * A role: a named bundle of permissions that ACEs reference by name.
9
+ *
10
+ * Generic over the permission type so subclasses can tighten it:
11
+ * - **System roles** declare `extends Role<Permission>` — construction time
12
+ * type-checks against the central `Permission` enum.
13
+ * - **ABAC roles** (`AbacRole`) declare `extends Role<string>` — permissions
14
+ * are bare verbs (`'read'`, `'write'`, `'delete'`, future domain-specific
15
+ * verbs) consumed by the JWT generator to form `{scope}:{verb}` keys in
16
+ * `content_security`.
17
+ *
18
+ * The registry stores `Role` (defaulting to `Role<string>`) — the loose type
19
+ * is the lowest common denominator. Tight typing is only enforced at
20
+ * declaration sites of the role subclasses.
21
+ */
22
+ export class Role {
23
+ name;
24
+ domain;
25
+ permissions;
26
+ constructor(name, permissions, domain) {
27
+ this.name = name;
28
+ this.domain = domain;
29
+ this.permissions = new Set(permissions);
30
+ }
31
+ hasPermission(permission) {
32
+ return this.permissions.has(permission);
33
+ }
34
+ }
35
+ /**
36
+ * Base class for built-in system roles. Hardcodes `domain: 'system'` and
37
+ * specializes `Role<Permission>` so subclasses get compile-time type-checking
38
+ * against the central `Permission` enum at construction.
39
+ */
40
+ export class SystemRole extends Role {
41
+ constructor(name, permissions) {
42
+ super(name, permissions, 'system');
43
+ }
44
+ }
45
+ /**
46
+ * A role usable in ContentSet ACEs. Adds `applicableScopes` — the kinds of
47
+ * objects the role can be applied to at the ABAC scope level. Inherits
48
+ * `Role<string>` because ABAC verbs aren't constrained to the central
49
+ * `Permission` enum.
50
+ *
51
+ * The IAM UI filters via `listAbacRolesForScope` which checks `instanceof AbacRole`.
52
+ */
53
+ export class AbacRole extends Role {
54
+ applicableScopes;
55
+ constructor(name, permissions, domain, applicableScopes) {
56
+ super(name, permissions, domain);
57
+ this.applicableScopes = applicableScopes;
58
+ }
59
+ }
60
+ //# sourceMappingURL=classes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classes.js","sourceRoot":"","sources":["../../src/roles/classes.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,IAAI;IAGF;IAEA;IAJX,WAAW,CAAsB;IACjC,YACW,IAAY,EACnB,WAA6B,EACtB,MAAkB;QAFlB,SAAI,GAAJ,IAAI,CAAQ;QAEZ,WAAM,GAAN,MAAM,CAAY;QAEzB,IAAI,CAAC,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;IAC5C,CAAC;IAED,aAAa,CAAC,UAA0B;QACpC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC5C,CAAC;CACJ;AAED;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,IAAgB;IAC5C,YAAY,IAAY,EAAE,WAAyB;QAC/C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;CACJ;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,QAAS,SAAQ,IAAY;IAK3B;IAJX,YACI,IAAY,EACZ,WAAqB,EACrB,MAAkB,EACX,gBAAsC;QAE7C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;QAF1B,qBAAgB,GAAhB,gBAAgB,CAAsB;IAGjD,CAAC;CACJ"}
@@ -0,0 +1,13 @@
1
+ import { type RolePartition } from './classes.js';
2
+ /**
3
+ * Names of roles owned by the `content` domain. Apply to ContentSet ACEs
4
+ * scoped to either `document` or `collection` — the semantics of "read
5
+ * content" are the same for both kinds.
6
+ */
7
+ export declare enum ContentRoleNames {
8
+ content_reader = "content_reader",
9
+ content_writer = "content_writer",
10
+ content_manager = "content_manager"
11
+ }
12
+ export declare const contentPartition: RolePartition;
13
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/roles/content.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAMvE;;;;GAIG;AACH,oBAAY,gBAAgB;IACxB,cAAc,mBAAmB;IACjC,cAAc,mBAAmB;IACjC,eAAe,oBAAoB;CACtC;AA0BD,eAAO,MAAM,gBAAgB,EAAE,aAG9B,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { AbacRole } from './classes.js';
2
+ const ContentRoleDomain = 'content';
3
+ const APPLICABLE_SCOPES = ['document', 'collection'];
4
+ /**
5
+ * Names of roles owned by the `content` domain. Apply to ContentSet ACEs
6
+ * scoped to either `document` or `collection` — the semantics of "read
7
+ * content" are the same for both kinds.
8
+ */
9
+ export var ContentRoleNames;
10
+ (function (ContentRoleNames) {
11
+ ContentRoleNames["content_reader"] = "content_reader";
12
+ ContentRoleNames["content_writer"] = "content_writer";
13
+ ContentRoleNames["content_manager"] = "content_manager";
14
+ })(ContentRoleNames || (ContentRoleNames = {}));
15
+ class ContentReaderRole extends AbacRole {
16
+ constructor() {
17
+ super(ContentRoleNames.content_reader, ['read'], ContentRoleDomain, APPLICABLE_SCOPES);
18
+ }
19
+ }
20
+ class ContentWriterRole extends AbacRole {
21
+ constructor() {
22
+ super(ContentRoleNames.content_writer, ['read', 'write'], ContentRoleDomain, APPLICABLE_SCOPES);
23
+ }
24
+ }
25
+ class ContentManagerRole extends AbacRole {
26
+ constructor() {
27
+ super(ContentRoleNames.content_manager, ['read', 'write', 'delete'], ContentRoleDomain, APPLICABLE_SCOPES);
28
+ }
29
+ }
30
+ const contentRoles = {
31
+ [ContentRoleNames.content_reader]: new ContentReaderRole(),
32
+ [ContentRoleNames.content_writer]: new ContentWriterRole(),
33
+ [ContentRoleNames.content_manager]: new ContentManagerRole(),
34
+ };
35
+ export const contentPartition = {
36
+ domain: ContentRoleDomain,
37
+ roles: new Map(Object.entries(contentRoles)),
38
+ };
39
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/roles/content.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAiC,MAAM,cAAc,CAAC;AAEvE,MAAM,iBAAiB,GAAe,SAAS,CAAC;AAEhD,MAAM,iBAAiB,GAAyB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,CAAN,IAAY,gBAIX;AAJD,WAAY,gBAAgB;IACxB,qDAAiC,CAAA;IACjC,qDAAiC,CAAA;IACjC,uDAAmC,CAAA;AACvC,CAAC,EAJW,gBAAgB,KAAhB,gBAAgB,QAI3B;AAED,MAAM,iBAAkB,SAAQ,QAAQ;IACpC;QACI,KAAK,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,MAAM,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IAC3F,CAAC;CACJ;AAED,MAAM,iBAAkB,SAAQ,QAAQ;IACpC;QACI,KAAK,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IACpG,CAAC;CACJ;AAED,MAAM,kBAAmB,SAAQ,QAAQ;IACrC;QACI,KAAK,CAAC,gBAAgB,CAAC,eAAe,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;IAC/G,CAAC;CACJ;AAED,MAAM,YAAY,GAAmC;IACjD,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,IAAI,iBAAiB,EAAE;IAC1D,CAAC,gBAAgB,CAAC,cAAc,CAAC,EAAE,IAAI,iBAAiB,EAAE;IAC1D,CAAC,gBAAgB,CAAC,eAAe,CAAC,EAAE,IAAI,kBAAkB,EAAE;CAC/D,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAkB;IAC3C,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;CAC/C,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { AbacScope, RoleDomain } from '@vertesia/common';
2
+ import { AbacRole, type Role, SystemRole } from './classes.js';
3
+ export { AbacRole, Role, type RolePartition, SystemRole } from './classes.js';
4
+ export { ContentRoleNames } from './content.js';
5
+ /** Look up a role by its name across all registered partitions. */
6
+ export declare function getRoleByName(name: string): Role;
7
+ /** List every role across all partitions, in partition registration order. */
8
+ export declare function listRoles(): Role[];
9
+ /** Roles owned by a specific domain (e.g. `'system'`, `'content'`). */
10
+ export declare function listRolesByDomain(domain: RoleDomain): Role[];
11
+ /**
12
+ * ABAC roles applicable to a given ContentSet scope (e.g. `'document'`,
13
+ * `'collection'`). System roles are excluded — they don't carry scope semantics.
14
+ */
15
+ export declare function listAbacRolesForScope(scope: AbacScope): AbacRole[];
16
+ /** Shortcut for the system partition: returns only `SystemRole` instances. */
17
+ export declare function listSystemRoles(): SystemRole[];
18
+ /** Names of every registered role across all partitions — suited for mongoose schema enum constraints. */
19
+ export declare function getAllRoleNames(): string[];
20
+ /**
21
+ * Merge the permissions granted by a set of roles into a single array.
22
+ * Intended for the system-role gating path. For ABAC roles, the bare-verb
23
+ * permissions returned here aren't directly meaningful — use the JWT
24
+ * `content_security` pathway instead.
25
+ */
26
+ export declare function getPermissionsForRoles(roleNames: Iterable<string>): string[];
27
+ /**
28
+ * A list of roles with a unified `hasPermission` check across them.
29
+ */
30
+ export declare class RoleList {
31
+ readonly roles: Role[];
32
+ private constructor();
33
+ static fromRoleNames(roleNames: string[]): RoleList;
34
+ static fromRoleName(roleName: string): RoleList;
35
+ hasPermission(perm: string): boolean;
36
+ }
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/roles/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,KAAK,IAAI,EAAsB,UAAU,EAAE,MAAM,cAAc,CAAC;AAInF,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAShD,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMhD;AAED,8EAA8E;AAC9E,wBAAgB,SAAS,IAAI,IAAI,EAAE,CAQlC;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,EAAE,CAG5D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,EAAE,CAElE;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,IAAI,UAAU,EAAE,CAE9C;AAED,0GAA0G;AAC1G,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAS5E;AAED;;GAEG;AACH,qBAAa,QAAQ;aACmB,KAAK,EAAE,IAAI,EAAE;IAAjD,OAAO;IAEP,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,QAAQ;IAKnD,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAK/C,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAGvC"}
@@ -0,0 +1,87 @@
1
+ import { AbacRole, SystemRole } from './classes.js';
2
+ import { contentPartition } from './content.js';
3
+ import { systemPartition } from './system.js';
4
+ export { AbacRole, Role, SystemRole } from './classes.js';
5
+ export { ContentRoleNames } from './content.js';
6
+ /**
7
+ * The ordered partition registry. Partitions are queried in this order — first
8
+ * match wins. The `system` partition is registered first so domain-specific
9
+ * partitions (added later) cannot shadow built-in system roles.
10
+ */
11
+ const partitions = [systemPartition, contentPartition];
12
+ /** Look up a role by its name across all registered partitions. */
13
+ export function getRoleByName(name) {
14
+ for (const partition of partitions) {
15
+ const role = partition.roles.get(name);
16
+ if (role)
17
+ return role;
18
+ }
19
+ throw new Error(`Role ${name} not found`);
20
+ }
21
+ /** List every role across all partitions, in partition registration order. */
22
+ export function listRoles() {
23
+ const result = [];
24
+ for (const partition of partitions) {
25
+ for (const role of partition.roles.values()) {
26
+ result.push(role);
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ /** Roles owned by a specific domain (e.g. `'system'`, `'content'`). */
32
+ export function listRolesByDomain(domain) {
33
+ const partition = partitions.find((p) => p.domain === domain);
34
+ return partition ? Array.from(partition.roles.values()) : [];
35
+ }
36
+ /**
37
+ * ABAC roles applicable to a given ContentSet scope (e.g. `'document'`,
38
+ * `'collection'`). System roles are excluded — they don't carry scope semantics.
39
+ */
40
+ export function listAbacRolesForScope(scope) {
41
+ return listRoles().filter((r) => r instanceof AbacRole && r.applicableScopes.includes(scope));
42
+ }
43
+ /** Shortcut for the system partition: returns only `SystemRole` instances. */
44
+ export function listSystemRoles() {
45
+ return listRoles().filter((r) => r instanceof SystemRole);
46
+ }
47
+ /** Names of every registered role across all partitions — suited for mongoose schema enum constraints. */
48
+ export function getAllRoleNames() {
49
+ return listRoles().map((r) => r.name);
50
+ }
51
+ /**
52
+ * Merge the permissions granted by a set of roles into a single array.
53
+ * Intended for the system-role gating path. For ABAC roles, the bare-verb
54
+ * permissions returned here aren't directly meaningful — use the JWT
55
+ * `content_security` pathway instead.
56
+ */
57
+ export function getPermissionsForRoles(roleNames) {
58
+ const permissions = new Set();
59
+ for (const roleName of roleNames) {
60
+ const role = getRoleByName(roleName);
61
+ for (const permission of role.permissions) {
62
+ permissions.add(permission);
63
+ }
64
+ }
65
+ return Array.from(permissions);
66
+ }
67
+ /**
68
+ * A list of roles with a unified `hasPermission` check across them.
69
+ */
70
+ export class RoleList {
71
+ roles;
72
+ constructor(roles) {
73
+ this.roles = roles;
74
+ }
75
+ static fromRoleNames(roleNames) {
76
+ const roles = roleNames.map((r) => getRoleByName(r));
77
+ return new RoleList(roles);
78
+ }
79
+ static fromRoleName(roleName) {
80
+ const roles = [getRoleByName(roleName)];
81
+ return new RoleList(roles);
82
+ }
83
+ hasPermission(perm) {
84
+ return this.roles.some((role) => role.hasPermission(perm));
85
+ }
86
+ }
87
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/roles/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type RolePartition } from './classes.js';
2
+ export declare const systemPartition: RolePartition;
3
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/roles/system.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,aAAa,EAAc,MAAM,cAAc,CAAC;AAuMzE,eAAO,MAAM,eAAe,EAAE,aAG7B,CAAC"}