@endora-commerce/mod-admin-roles 0.100.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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/dist/admin/index.d.ts +47 -0
  4. package/dist/admin/index.d.ts.map +1 -0
  5. package/dist/admin/index.js +27 -0
  6. package/dist/admin/index.js.map +1 -0
  7. package/dist/backend/demo/reset.d.ts +20 -0
  8. package/dist/backend/demo/reset.d.ts.map +1 -0
  9. package/dist/backend/demo/reset.js +13 -0
  10. package/dist/backend/demo/reset.js.map +1 -0
  11. package/dist/backend/demo/rows.d.ts +64 -0
  12. package/dist/backend/demo/rows.d.ts.map +1 -0
  13. package/dist/backend/demo/rows.js +74 -0
  14. package/dist/backend/demo/rows.js.map +1 -0
  15. package/dist/backend/demo/seed.d.ts +20 -0
  16. package/dist/backend/demo/seed.d.ts.map +1 -0
  17. package/dist/backend/demo/seed.js +29 -0
  18. package/dist/backend/demo/seed.js.map +1 -0
  19. package/dist/backend/entities/admin-role.entity.d.ts +20 -0
  20. package/dist/backend/entities/admin-role.entity.d.ts.map +1 -0
  21. package/dist/backend/entities/admin-role.entity.js +65 -0
  22. package/dist/backend/entities/admin-role.entity.js.map +1 -0
  23. package/dist/backend/index.d.ts +96 -0
  24. package/dist/backend/index.d.ts.map +1 -0
  25. package/dist/backend/index.js +114 -0
  26. package/dist/backend/index.js.map +1 -0
  27. package/dist/backend/permission-inventory.d.ts +117 -0
  28. package/dist/backend/permission-inventory.d.ts.map +1 -0
  29. package/dist/backend/permission-inventory.js +585 -0
  30. package/dist/backend/permission-inventory.js.map +1 -0
  31. package/dist/backend/services/admin-role-ports.d.ts +39 -0
  32. package/dist/backend/services/admin-role-ports.d.ts.map +1 -0
  33. package/dist/backend/services/admin-role-ports.js +72 -0
  34. package/dist/backend/services/admin-role-ports.js.map +1 -0
  35. package/dist/backend/services/admin-role-service.d.ts +77 -0
  36. package/dist/backend/services/admin-role-service.d.ts.map +1 -0
  37. package/dist/backend/services/admin-role-service.js +219 -0
  38. package/dist/backend/services/admin-role-service.js.map +1 -0
  39. package/dist/backend/services/permission-catalogue.service.d.ts +130 -0
  40. package/dist/backend/services/permission-catalogue.service.d.ts.map +1 -0
  41. package/dist/backend/services/permission-catalogue.service.js +175 -0
  42. package/dist/backend/services/permission-catalogue.service.js.map +1 -0
  43. package/dist/backend/services/permission-service.d.ts +24 -0
  44. package/dist/backend/services/permission-service.d.ts.map +1 -0
  45. package/dist/backend/services/permission-service.js +40 -0
  46. package/dist/backend/services/permission-service.js.map +1 -0
  47. package/dist/manifest.d.ts +169 -0
  48. package/dist/manifest.d.ts.map +1 -0
  49. package/dist/manifest.js +192 -0
  50. package/dist/manifest.js.map +1 -0
  51. package/docs/admin_roles.md +38 -0
  52. package/i18n/en.json +10 -0
  53. package/i18n/pl.json +10 -0
  54. package/package.json +73 -0
  55. package/tailwind.css +14 -0
@@ -0,0 +1,585 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, join, relative, resolve } from 'node:path';
4
+ /**
5
+ * Static inventory of the permission codes the backend actually enforces.
6
+ *
7
+ * It exists so `/admin-roles` can never advertise less than the server checks:
8
+ * a code enforced at a gate but absent from the assignable catalogue is a screen
9
+ * only a `'*'` role can open, and nothing else in the tree notices.
10
+ *
11
+ * The scanner therefore has to read the gate call in **every shape the tree
12
+ * writes it**, not the one shape it was first written against. It previously
13
+ * required an optional-call dot before the argument list, so a plain
14
+ * `requireAdmin('code')` — nearly the whole tree — was invisible to it, and it
15
+ * read clean while modules gated screens on codes no role could hold. The shapes are
16
+ * enumerated on `collectFromSource` and each is covered by a fixture in
17
+ * `test/unit/admin_roles/permission-inventory-scanner.test.ts`; an argument the
18
+ * scanner cannot resolve is reported as `unresolved` rather than dropped,
19
+ * because a silently dropped gate is exactly the failure this file guards.
20
+ */
21
+ /**
22
+ * `packages/contracts/src` — permission maps shared across modules live here.
23
+ *
24
+ * Resolved through the package's own `package.json`, never by climbing out of
25
+ * this file's directory (D-100). The climb worked while this module lived at
26
+ * `backend/src/modules/admin_roles/` and answered a *different* directory the
27
+ * day it became a package — silently, because every path it produced still
28
+ * existed. `createRequire` asks the resolver the question the manifest already
29
+ * answers, and this module declares `@endora-commerce/contracts` as a peer.
30
+ */
31
+ const CONTRACTS_SRC = (() => {
32
+ // Its entry point, then up to the directory that owns the manifest. Asking
33
+ // for `./package.json` directly is not available: that package's `exports`
34
+ // map answers a wildcard and resolves the request to `dist/package.json.js`.
35
+ let dir = dirname(createRequire(import.meta.url).resolve('@endora-commerce/contracts'));
36
+ for (;;) {
37
+ if (existsSync(join(dir, 'package.json')))
38
+ return join(dir, 'src');
39
+ const parent = dirname(dir);
40
+ if (parent === dir)
41
+ return '';
42
+ dir = parent;
43
+ }
44
+ })();
45
+ /**
46
+ * The roots a bare-core build enforces gates in, plus the active deployment's
47
+ * overlay modules (feature 057 — an overlay module is an ordinary lifecycle
48
+ * participant, so its gates count for that deployment and for no other).
49
+ *
50
+ * `src/apps` is skipped during the walk rather than excluded by name: a
51
+ * deployment that is not the selected one is not part of this build, and its
52
+ * permissions are not assignable here.
53
+ *
54
+ * **A module that is a workspace package is not here, and is the caller's to
55
+ * supply.** This scanner has no runtime caller — its two callers are
56
+ * `test/contract/admin_users/permission-inventory.test.ts` and the scanner's own
57
+ * unit test — and the module layout is derived by `scripts/lib/module-roots.ts`,
58
+ * which a module may not import (`check:module-boundary`, and it is right to
59
+ * refuse: this file belongs to `admin_roles`). So the root list is an input, and
60
+ * the caller that already resolves the layout passes it. Leaving a packaged
61
+ * module out silently reports its codes as *"grantable but enforced by no
62
+ * gate"* — a checkbox `/admin-roles` says grants nothing while the gate is
63
+ * there — which is what the contract test caught the day `blog` moved.
64
+ *
65
+ * **The overlay root is an input for the same reason** (feature 080, T051). It
66
+ * used to be computed here, from `overlay/overlay-roots.js` — a file
67
+ * `contracts/host-package.md` §1.4l classifies **A**, because `overlay/*` is
68
+ * how the platform *discovers* overlays and a module reading it as an installed
69
+ * package would be an artefact enumerating its own siblings (O3's cycle). The
70
+ * answer is the same one this paragraph already gives for a packaged module:
71
+ * the caller resolves the layout, and there is no runtime caller to inconvenience.
72
+ * `null` means a bare-core build, which is what a deployment-less environment
73
+ * has always produced.
74
+ */
75
+ export function defaultScanRoots(applicationSourceRoot, overlayModulesRoot) {
76
+ return overlayModulesRoot === null
77
+ ? [applicationSourceRoot]
78
+ : [applicationSourceRoot, overlayModulesRoot];
79
+ }
80
+ /**
81
+ * Distinct permission codes referenced by an enforcement site under the scan
82
+ * roots. Kept for callers that only need the set (SC-001).
83
+ */
84
+ export function scanEnforcedPermissionCodes(roots) {
85
+ return scanEnforcedPermissionGates(roots).codes;
86
+ }
87
+ /**
88
+ * Every enforcement site under `roots`, classified.
89
+ *
90
+ * `roots` is required. It used to default to `defaultScanRoots()`, which
91
+ * resolved the active deployment for itself; that resolution is the caller's
92
+ * now (see {@link defaultScanRoots}), and a default of "bare core" would be a
93
+ * scan that silently covered less than it was asked for.
94
+ *
95
+ * Each site's `file` is reported relative to the **first bare-string root**,
96
+ * which is the application's own source root by construction of
97
+ * {@link defaultScanRoots} — a module package is passed as an object carrying
98
+ * its `moduleId`. It used to be relative to a `backend/src` this file computed
99
+ * by climbing out of its own directory, which answered a different directory
100
+ * the day `admin_roles` became a package (feature 080, T040b).
101
+ */
102
+ export function scanEnforcedPermissionGates(roots) {
103
+ const sites = [];
104
+ const seen = new Set();
105
+ const resolver = new ConstantResolver();
106
+ const base = roots.find((entry) => typeof entry === 'string') ?? '';
107
+ for (const entry of roots) {
108
+ const root = typeof entry === 'string' ? { dir: entry } : entry;
109
+ for (const file of walkSources(root.dir, seen)) {
110
+ collectFromFile(file, root, base, resolver, sites);
111
+ }
112
+ }
113
+ const codes = new Set();
114
+ for (const site of sites)
115
+ for (const code of site.codes)
116
+ codes.add(code);
117
+ return {
118
+ codes,
119
+ sites,
120
+ unresolved: sites.filter((s) => s.resolution === 'unresolved'),
121
+ runtimeValue: sites.filter((s) => s.resolution === 'runtime-value'),
122
+ authenticatedAdminOnly: sites.filter((s) => s.resolution === 'authenticated-admin'),
123
+ };
124
+ }
125
+ function* walkSources(dir, seen) {
126
+ if (!existsSync(dir))
127
+ return;
128
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
129
+ const path = join(dir, entry.name);
130
+ if (entry.isDirectory()) {
131
+ // `apps` is reached through `defaultScanRoots`, and only for the selected
132
+ // deployment; `node_modules` is never ours. `dist` is a module package's
133
+ // build output — the same gates a second time, compiled, which would
134
+ // double every site and attribute half of them to a path nobody edits.
135
+ if (entry.name === 'node_modules' || entry.name === 'apps' || entry.name === 'dist') {
136
+ continue;
137
+ }
138
+ yield* walkSources(path, seen);
139
+ continue;
140
+ }
141
+ if (!entry.isFile() || !/\.(ts|js)$/.test(entry.name))
142
+ continue;
143
+ // **A test is not an enforcement site, and this exclusion had no subject
144
+ // until feature 106.** Every test used to live under `backend/test`, which
145
+ // no scan root reaches, so the walk could not meet one; 106 moved the
146
+ // co-located tests *into* `packages/modules/<id>/src/`, and this scanner's
147
+ // own unit test — whose fixtures are deliberately fake codes and
148
+ // deliberately unreadable gate arguments — moved with them. Its fixtures
149
+ // were then read as real gates: 18 codes reported *"enforced but not
150
+ // grantable"* and 2 as unresolvable, red on `master`. A gate written in a
151
+ // test guards nothing an operator can reach, so the population is source
152
+ // and never a test, whichever directory the test now sits in. The predicate
153
+ // is the suffix and not the substring: a module legitimately named for test
154
+ // infrastructure keeps its gates.
155
+ if (/\.(test|spec)\.(ts|js)$/.test(entry.name))
156
+ continue;
157
+ if (seen.has(path))
158
+ continue;
159
+ seen.add(path);
160
+ yield path;
161
+ }
162
+ }
163
+ /** The module directory owning `file`, for attribution in failure messages. */
164
+ function moduleIdFor(file, root) {
165
+ // A root that names its module **is** that module's directory, whatever it
166
+ // keeps inside it.
167
+ if (root.moduleId !== undefined)
168
+ return root.moduleId;
169
+ const rel = relative(root.dir, file);
170
+ const segments = rel.split(/[\\/]/);
171
+ if (segments[0] === 'modules')
172
+ return segments[1] ?? null;
173
+ // An overlay root IS the modules root, so the first segment is the module id.
174
+ return segments.length > 1 ? (segments[0] ?? null) : null;
175
+ }
176
+ function collectFromFile(file, root, base, resolver, out) {
177
+ const source = resolver.sourceOf(file);
178
+ if (source === null)
179
+ return;
180
+ if (!/requireAdmin|hasPermission/.test(source))
181
+ return;
182
+ const moduleId = moduleIdFor(file, root);
183
+ const relFile = relative(base, file);
184
+ for (const site of collectFromSource(source, file, resolver)) {
185
+ out.push({ ...site, file: relFile, moduleId });
186
+ }
187
+ }
188
+ /**
189
+ * The enforcement shapes this recognises, all of them present in the tree:
190
+ *
191
+ * - `requireAdmin('code')`, and the same call reached through a dependency bag
192
+ * or a container cradle (`deps.requireAdmin(…)`, `cradle().requireAdmin(…)`);
193
+ * - the optional-call form `requireAdmin?.('code')`;
194
+ * - `requireAdminAny(['a', 'b'])` in either of the above positions;
195
+ * - a constant argument, resolved module-locally, through a relative import, or
196
+ * through `@endora-commerce/contracts`, including a member read of a permission map;
197
+ * - `permissionService.hasPermission(actor, 'code')` — the capability check a
198
+ * service uses where there is no route to hang a `preHandler` on.
199
+ *
200
+ * Comments and regular-expression literals are blanked first: a doc comment
201
+ * quoting a gate is not a gate, several files quote one, and this file's own
202
+ * matcher would otherwise read itself as a call site.
203
+ */
204
+ function* collectFromSource(source, file, resolver) {
205
+ const bound = collectRuntimeBindings(source);
206
+ const callRe = /(?:[\w$]+\s*\??\.\s*)*(requireAdmin(?:Any)?|hasPermission)\s*(?:\?\.)?\s*\(/g;
207
+ let m;
208
+ while ((m = callRe.exec(source)) !== null) {
209
+ const callee = m[1] ?? '';
210
+ const open = source.indexOf('(', m.index + m[0].length - 1);
211
+ if (open === -1)
212
+ continue;
213
+ const args = readBalanced(source, open);
214
+ // A parameter list, not an argument list: the guard's own signature in an
215
+ // interface or an implementation. Nothing is enforced by a declaration.
216
+ if (PARAMETER_LIST_RE.test(args))
217
+ continue;
218
+ // `hasPermission(actor, 'code')` puts the code second; the guards put it first.
219
+ const argument = (callee === 'hasPermission' ? lastArgument(args) : firstArgument(args)).trim();
220
+ const expression = argument.replace(/\s+/g, ' ');
221
+ if (argument === '') {
222
+ if (callee === 'hasPermission')
223
+ continue;
224
+ yield { expression: '', resolution: 'authenticated-admin', codes: [] };
225
+ continue;
226
+ }
227
+ // `permission ?? ''` is the same runtime value with a default.
228
+ const normalised = argument.replace(/\s*\?\?\s*(['"]).*?\1\s*$/, '').trim();
229
+ if (/^['"[]/.test(normalised)) {
230
+ const codes = [...normalised.matchAll(/(['"])([^'"]*)\1/g)]
231
+ .map((lit) => lit[2] ?? '')
232
+ .filter((code) => code.length > 0);
233
+ yield codes.length > 0
234
+ ? { expression, resolution: 'code', codes }
235
+ : { expression, resolution: 'unresolved', codes: [] };
236
+ continue;
237
+ }
238
+ // Resolve before classifying: a constant that happens to share a name with
239
+ // a parameter somewhere in the file is still a constant.
240
+ const identifier = /^[A-Za-z_$][\w$]*$/.test(normalised) ? normalised : null;
241
+ const member = /^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/.exec(normalised);
242
+ const value = identifier
243
+ ? resolver.lookup(file, identifier, null)
244
+ : member?.[1] && member[2]
245
+ ? resolver.lookup(file, member[1], member[2])
246
+ : null;
247
+ if (value !== null) {
248
+ yield { expression, resolution: 'code', codes: [value] };
249
+ continue;
250
+ }
251
+ const rootName = identifier ?? member?.[1] ?? null;
252
+ yield rootName !== null && bound.has(rootName)
253
+ ? { expression, resolution: 'runtime-value', codes: [] }
254
+ : { expression, resolution: 'unresolved', codes: [] };
255
+ }
256
+ }
257
+ /** A leading `name:` or `name?:` marks a parameter list rather than arguments. */
258
+ const PARAMETER_LIST_RE = /^\s*(?:readonly\s+)?[A-Za-z_$][\w$]*\s*\??\s*:/;
259
+ /**
260
+ * Identifiers the file binds to a value only known at runtime: function and
261
+ * arrow parameters, `for (const x of …)` loop variables, and a `const` whose
262
+ * initialiser is not a string literal (a registry lookup, say). An argument
263
+ * rooted in one of these carries no literal to check; the literal — if there is
264
+ * one — is written at the caller or the contributor, a site this scan reads
265
+ * separately. Resolution is attempted first, so a genuine constant that shares
266
+ * a name with a binding is still read as a constant.
267
+ */
268
+ function collectRuntimeBindings(source) {
269
+ const bound = new Set();
270
+ let m;
271
+ const computedBindingRe = /(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::\s*[^=;]+)?=\s*(?!['"])/g;
272
+ while ((m = computedBindingRe.exec(source)) !== null) {
273
+ if (m[1])
274
+ bound.add(m[1]);
275
+ }
276
+ const typedParamRe = /[(,]\s*(?:readonly\s+)?([A-Za-z_$][\w$]*)\s*\??\s*:/g;
277
+ while ((m = typedParamRe.exec(source)) !== null) {
278
+ if (m[1])
279
+ bound.add(m[1]);
280
+ }
281
+ const arrowHeadRe = /\(([^()]*)\)\s*=>/g;
282
+ while ((m = arrowHeadRe.exec(source)) !== null) {
283
+ for (const part of (m[1] ?? '').split(',')) {
284
+ const name = /^\s*([A-Za-z_$][\w$]*)\s*$/.exec(part);
285
+ if (name?.[1])
286
+ bound.add(name[1]);
287
+ }
288
+ }
289
+ const loopBindingRe = /for\s*\(\s*(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s+(?:of|in)\b/g;
290
+ while ((m = loopBindingRe.exec(source)) !== null) {
291
+ if (m[1])
292
+ bound.add(m[1]);
293
+ }
294
+ return bound;
295
+ }
296
+ /** Text between `openIndex`'s bracket and its match, quotes respected. */
297
+ function readBalanced(source, openIndex) {
298
+ let depth = 0;
299
+ let i = openIndex;
300
+ for (; i < source.length; i += 1) {
301
+ const c = source[i];
302
+ if (c === '(' || c === '[' || c === '{')
303
+ depth += 1;
304
+ else if (c === ')' || c === ']' || c === '}') {
305
+ depth -= 1;
306
+ if (depth === 0)
307
+ break;
308
+ }
309
+ else if (c === "'" || c === '"' || c === '`') {
310
+ i = skipString(source, i);
311
+ }
312
+ }
313
+ return source.slice(openIndex + 1, i);
314
+ }
315
+ /** Split on top-level commas only — an array or object argument keeps its own. */
316
+ function splitArguments(args) {
317
+ const parts = [];
318
+ let depth = 0;
319
+ let start = 0;
320
+ for (let i = 0; i < args.length; i += 1) {
321
+ const c = args[i];
322
+ if (c === '(' || c === '[' || c === '{')
323
+ depth += 1;
324
+ else if (c === ')' || c === ']' || c === '}')
325
+ depth -= 1;
326
+ else if (c === "'" || c === '"' || c === '`')
327
+ i = skipString(args, i);
328
+ else if (c === ',' && depth === 0) {
329
+ parts.push(args.slice(start, i));
330
+ start = i + 1;
331
+ }
332
+ }
333
+ parts.push(args.slice(start));
334
+ return parts;
335
+ }
336
+ function firstArgument(args) {
337
+ return splitArguments(args)[0] ?? '';
338
+ }
339
+ function lastArgument(args) {
340
+ const parts = splitArguments(args);
341
+ return parts[parts.length - 1] ?? '';
342
+ }
343
+ /** Index of the closing quote of the string starting at `i`. */
344
+ function skipString(source, i) {
345
+ const quote = source[i];
346
+ let j = i + 1;
347
+ while (j < source.length) {
348
+ if (source[j] === '\\') {
349
+ j += 2;
350
+ continue;
351
+ }
352
+ if (source[j] === quote)
353
+ return j;
354
+ j += 1;
355
+ }
356
+ return j;
357
+ }
358
+ /**
359
+ * Resolves a constant argument to its literal, following at most a few hops:
360
+ * module-local, a relative import, or `@endora-commerce/contracts`. Deeper indirection has
361
+ * never appeared, and pretending to resolve it would hide the same gate the
362
+ * `unresolved` bucket is there to surface.
363
+ *
364
+ * Exported for `scripts/check-action-route-permissions.ts` (issue #232), which
365
+ * asks the third direction — is an action's `requiredPermission` the code
366
+ * enforced on **its own** target route — and needs the same argument shapes read
367
+ * the same way. A second resolver would answer the same question differently the
368
+ * first time either of them learned a shape.
369
+ */
370
+ export class ConstantResolver {
371
+ #facts = new Map();
372
+ #contractsFiles = null;
373
+ sourceOf(file) {
374
+ return this.#factsFor(file)?.source ?? null;
375
+ }
376
+ lookup(file, name, property, depth = 0) {
377
+ if (depth > 4)
378
+ return null;
379
+ const facts = this.#factsFor(file);
380
+ if (!facts)
381
+ return null;
382
+ if (property === null) {
383
+ const scalar = facts.scalars.get(name);
384
+ if (scalar !== undefined)
385
+ return scalar;
386
+ }
387
+ else {
388
+ const value = facts.objects.get(name)?.get(property);
389
+ if (value !== undefined)
390
+ return value;
391
+ }
392
+ const imported = facts.imports.get(name);
393
+ if (!imported)
394
+ return null;
395
+ for (const target of this.#resolveSpecifier(file, imported.specifier)) {
396
+ const value = this.lookup(target, imported.exportedAs, property, depth + 1);
397
+ if (value !== null)
398
+ return value;
399
+ }
400
+ return null;
401
+ }
402
+ #factsFor(file) {
403
+ if (this.#facts.has(file))
404
+ return this.#facts.get(file) ?? null;
405
+ let raw;
406
+ try {
407
+ raw = readFileSync(file, 'utf8');
408
+ }
409
+ catch {
410
+ this.#facts.set(file, null);
411
+ return null;
412
+ }
413
+ const source = blankComments(raw);
414
+ const facts = {
415
+ source,
416
+ scalars: collectScalars(source),
417
+ objects: collectObjects(source),
418
+ imports: collectImports(source),
419
+ };
420
+ this.#facts.set(file, facts);
421
+ return facts;
422
+ }
423
+ /** Candidate files a specifier may resolve to, in preference order. */
424
+ #resolveSpecifier(from, specifier) {
425
+ if (specifier === '@endora-commerce/contracts')
426
+ return this.#contractsSources();
427
+ if (!specifier.startsWith('.'))
428
+ return [];
429
+ const base = resolve(dirname(from), specifier);
430
+ const candidates = [base.replace(/\.js$/, '.ts'), `${base}.ts`, join(base, 'index.ts'), base];
431
+ return candidates.filter((c) => existsSync(c) && statSync(c).isFile());
432
+ }
433
+ /**
434
+ * `@endora-commerce/contracts` re-exports everything from its barrel, so following the
435
+ * barrel would mean parsing every `export *`. Scanning the package's own
436
+ * sources for the constant reaches the same answer in one hop.
437
+ */
438
+ #contractsSources() {
439
+ if (this.#contractsFiles !== null)
440
+ return this.#contractsFiles;
441
+ const files = [];
442
+ if (existsSync(CONTRACTS_SRC)) {
443
+ for (const entry of readdirSync(CONTRACTS_SRC, { withFileTypes: true })) {
444
+ if (entry.isFile() && entry.name.endsWith('.ts'))
445
+ files.push(join(CONTRACTS_SRC, entry.name));
446
+ }
447
+ }
448
+ this.#contractsFiles = files;
449
+ return files;
450
+ }
451
+ }
452
+ /**
453
+ * Replace comment and regular-expression bodies with spaces, preserving offsets
454
+ * and string literals.
455
+ *
456
+ * A regex literal is a `/` in a position where an expression may start (after an
457
+ * operator, a bracket or a keyword), which is what distinguishes it from
458
+ * division — division follows a value. Blanking them keeps a matcher written as
459
+ * a pattern, this file's included, from reading as the thing it matches.
460
+ */
461
+ function blankComments(source) {
462
+ let out = '';
463
+ let i = 0;
464
+ while (i < source.length) {
465
+ const c = source[i];
466
+ const next = source[i + 1];
467
+ if (c === '/' && next !== '/' && next !== '*' && startsExpression(out)) {
468
+ const end = skipRegex(source, i);
469
+ out += '/';
470
+ for (let k = i + 1; k < end; k += 1)
471
+ out += source[k] === '\n' ? '\n' : ' ';
472
+ out += end < source.length ? '/' : '';
473
+ i = end + 1;
474
+ continue;
475
+ }
476
+ if (c === '/' && next === '/') {
477
+ while (i < source.length && source[i] !== '\n') {
478
+ out += ' ';
479
+ i += 1;
480
+ }
481
+ continue;
482
+ }
483
+ if (c === '/' && next === '*') {
484
+ while (i < source.length && !(source[i] === '*' && source[i + 1] === '/')) {
485
+ out += source[i] === '\n' ? '\n' : ' ';
486
+ i += 1;
487
+ }
488
+ out += ' ';
489
+ i += 2;
490
+ continue;
491
+ }
492
+ if (c === "'" || c === '"' || c === '`') {
493
+ const end = skipString(source, i);
494
+ out += source.slice(i, end + 1);
495
+ i = end + 1;
496
+ continue;
497
+ }
498
+ out += c;
499
+ i += 1;
500
+ }
501
+ return out;
502
+ }
503
+ /** True when the last significant character allows an expression to start. */
504
+ function startsExpression(emitted) {
505
+ const trimmed = emitted.replace(/\s+$/, '');
506
+ if (trimmed.length === 0)
507
+ return true;
508
+ const last = trimmed[trimmed.length - 1] ?? '';
509
+ if ('([{,;:=!&|?+-*%~^<>'.includes(last))
510
+ return true;
511
+ return /\b(?:return|typeof|case|in|of|new|delete|void|do|else)$/.test(trimmed);
512
+ }
513
+ /** Index of the closing `/` of the regex literal starting at `i`. */
514
+ function skipRegex(source, i) {
515
+ let j = i + 1;
516
+ let inClass = false;
517
+ while (j < source.length) {
518
+ const c = source[j];
519
+ if (c === '\\') {
520
+ j += 2;
521
+ continue;
522
+ }
523
+ if (c === '\n')
524
+ return j - 1;
525
+ if (c === '[')
526
+ inClass = true;
527
+ else if (c === ']')
528
+ inClass = false;
529
+ else if (c === '/' && !inClass)
530
+ return j;
531
+ j += 1;
532
+ }
533
+ return j;
534
+ }
535
+ function collectScalars(source) {
536
+ const scalars = new Map();
537
+ const re = /(?:export\s+)?(?:const|let)\s+([A-Za-z_$][\w$]*)\s*(?::\s*[^=;]+)?=\s*(['"])([^'"]*)\2/g;
538
+ let m;
539
+ while ((m = re.exec(source)) !== null) {
540
+ if (m[1] && m[3] !== undefined)
541
+ scalars.set(m[1], m[3]);
542
+ }
543
+ return scalars;
544
+ }
545
+ /** Flat `{ KEY: 'code' }` permission maps; nothing in the tree nests one. */
546
+ function collectObjects(source) {
547
+ const objects = new Map();
548
+ const re = /(?:export\s+)?const\s+([A-Za-z_$][\w$]*)\s*(?::\s*[^={;]+)?=\s*\{([^{}]*)\}/g;
549
+ let m;
550
+ while ((m = re.exec(source)) !== null) {
551
+ const name = m[1];
552
+ const body = m[2];
553
+ if (!name || body === undefined)
554
+ continue;
555
+ const entries = new Map();
556
+ const propRe = /([A-Za-z_$][\w$]*)\s*:\s*(['"])([^'"]*)\2/g;
557
+ let p;
558
+ while ((p = propRe.exec(body)) !== null) {
559
+ if (p[1] && p[3] !== undefined)
560
+ entries.set(p[1], p[3]);
561
+ }
562
+ if (entries.size > 0)
563
+ objects.set(name, entries);
564
+ }
565
+ return objects;
566
+ }
567
+ function collectImports(source) {
568
+ const imports = new Map();
569
+ const re = /import\s*(?:type\s+)?\{([^}]*)\}\s*from\s*['"]([^'"]+)['"]/g;
570
+ let m;
571
+ while ((m = re.exec(source)) !== null) {
572
+ const clause = m[1];
573
+ const specifier = m[2];
574
+ if (!clause || !specifier)
575
+ continue;
576
+ for (const part of clause.split(',')) {
577
+ const named = /^(?:type\s+)?([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/.exec(part.trim());
578
+ if (!named?.[1])
579
+ continue;
580
+ imports.set(named[2] ?? named[1], { exportedAs: named[1], specifier });
581
+ }
582
+ }
583
+ return imports;
584
+ }
585
+ //# sourceMappingURL=permission-inventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission-inventory.js","sourceRoot":"","sources":["../../src/backend/permission-inventory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { AdminRolePort, AdminRoleRecord, SystemRoleCodePort } from '@endora-commerce/contracts';
3
+ import { AdminRole } from '../entities/admin-role.entity.js';
4
+ import { type AdminRoleService } from './admin-role-service.js';
5
+ /**
6
+ * The published face of `admin_roles` (feature 075, Phase P).
7
+ *
8
+ * Fourteen inbound sites: `admin_users` reads a role beside its user and
9
+ * enforces `requiresTwoFactor` at login, `admin_actions` filters the command
10
+ * palette by a user's permissions, `blog` protects the role it seeds, and the
11
+ * dev seed creates one.
12
+ *
13
+ * `findByCode` is the method with no direct predecessor. `admin_users`'
14
+ * service and the dev seed both look a role up by code with
15
+ * `em.findOne(AdminRole, { code })`, which is the read it replaces.
16
+ */
17
+ export declare class AdminRoleReadService {
18
+ private readonly emFactory;
19
+ constructor(emFactory: () => EntityManager);
20
+ findByCode(code: string): Promise<AdminRoleRecord | null>;
21
+ }
22
+ /**
23
+ * The full role port, adapting `AdminRoleService` and adding the by-code
24
+ * lookup. The service arrives as a getter so the adapter resolves it per call
25
+ * rather than capturing it.
26
+ */
27
+ export declare function createAdminRolePort(emFactory: () => EntityManager, getService: () => AdminRoleService): AdminRolePort;
28
+ /**
29
+ * The contribution seam for deletion-protected role codes.
30
+ *
31
+ * Deliberately a plain object over the module-level set rather than anything
32
+ * gated: `blog` registers its seeded code from a boot hook, and a gate would
33
+ * both throw during composition and — worse — let an operator delete a
34
+ * protected role by switching its owner off for a moment. See the port's
35
+ * contract for the full reasoning.
36
+ */
37
+ export declare function createSystemRoleCodePort(): SystemRoleCodePort;
38
+ export declare function toAdminRoleRecord(role: AdminRole): AdminRoleRecord;
39
+ //# sourceMappingURL=admin-role-ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-role-ports.d.ts","sourceRoot":"","sources":["../../../src/backend/services/admin-role-ports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrG,OAAO,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAC7D,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAoB;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM,aAAa;IAErD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;CAIhE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,aAAa,EAC9B,UAAU,EAAE,MAAM,gBAAgB,GACjC,aAAa,CAef;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,kBAAkB,CAK7D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,GAAG,eAAe,CAUlE"}