@astram/guard 0.21.0 → 0.23.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 (39) hide show
  1. package/dist/audit/audit-chain-sealer.d.ts +1 -1
  2. package/dist/audit/audit-chain-sealer.d.ts.map +1 -1
  3. package/dist/audit/audit-sealer.service.d.ts +9 -2
  4. package/dist/audit/audit-sealer.service.d.ts.map +1 -1
  5. package/dist/audit/audit-sealer.service.js +20 -3
  6. package/dist/auth/connections.d.ts +66 -8
  7. package/dist/auth/connections.d.ts.map +1 -1
  8. package/dist/auth/connections.js +100 -18
  9. package/dist/auth/persistence.module.d.ts +11 -6
  10. package/dist/auth/persistence.module.d.ts.map +1 -1
  11. package/dist/auth/persistence.module.js +34 -11
  12. package/dist/auth/tokens.d.ts +6 -0
  13. package/dist/auth/tokens.d.ts.map +1 -1
  14. package/dist/auth/tokens.js +8 -2
  15. package/dist/authentication/mariadb-email-address-changer.d.ts +2 -1
  16. package/dist/authentication/mariadb-email-address-changer.d.ts.map +1 -1
  17. package/dist/authentication/mariadb-email-address-changer.js +3 -3
  18. package/dist/boot/boot-sequence.d.ts +7 -2
  19. package/dist/boot/boot-sequence.d.ts.map +1 -1
  20. package/dist/boot/boot-sequence.js +21 -4
  21. package/dist/completeness/catalog-reconciler.d.ts +16 -1
  22. package/dist/completeness/catalog-reconciler.d.ts.map +1 -1
  23. package/dist/completeness/catalog-reconciler.js +70 -6
  24. package/dist/completeness/ports/catalog-store.d.ts +38 -3
  25. package/dist/completeness/ports/catalog-store.d.ts.map +1 -1
  26. package/dist/config/app-config.d.ts +45 -3
  27. package/dist/config/app-config.d.ts.map +1 -1
  28. package/dist/config/app-config.js +52 -3
  29. package/dist/identity/module-registry.bridge.d.ts +9 -1
  30. package/dist/identity/module-registry.bridge.d.ts.map +1 -1
  31. package/dist/identity/module-registry.bridge.js +19 -1
  32. package/dist/index.d.ts +6 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +14 -5
  35. package/dist/internal.d.ts +6 -0
  36. package/dist/internal.d.ts.map +1 -1
  37. package/dist/internal.js +22 -15
  38. package/migrations/1710000000107-AddPermissionTextAndFirstSeen.cjs +43 -0
  39. package/package.json +5 -5
@@ -1,6 +1,6 @@
1
1
  import { type OnApplicationBootstrap } from '@nestjs/common';
2
2
  import type { FrameworkSchemas } from '@astram/core';
3
- import { type AppConfig, type PoolBudgetConfig } from '../config/app-config.js';
3
+ import { type AppConfig, type PoolBudgetConfig, type PoolTuning } from '../config/app-config.js';
4
4
  /**
5
5
  * Boot sequence extension point (Infrastructure layer — ADR-0018).
6
6
  *
@@ -11,7 +11,7 @@ import { type AppConfig, type PoolBudgetConfig } from '../config/app-config.js';
11
11
  * ───────────────────────────────────────────────────────────────────────────
12
12
  * ADR-0018 connection-pool assertion (FILLED).
13
13
  * {@link assertConnectionPoolReady} computes the connection budget
14
- * workers × Σ(per-account runtime pool max) + headroom ≤ maxConnections
14
+ * workers × (Σ(per-account runtime pool max) + 1 audit sealer) + headroom ≤ maxConnections
15
15
  * and THROWS (fail-closed, abort boot) on violation, so a pool config that
16
16
  * would exceed MariaDB's `max_connections` is caught at boot, never under load.
17
17
  * ───────────────────────────────────────────────────────────────────────────
@@ -35,6 +35,11 @@ export declare class BootSequence implements OnApplicationBootstrap {
35
35
  }
36
36
  /** The boot log line naming the resolved framework databases (names only, spec 5.E). */
37
37
  export declare function frameworkDatabasesLogLine(s: FrameworkSchemas): string;
38
+ /**
39
+ * The boot log line with the effective pool idle settings (G-026 spec 5.N), numbers only, e.g.
40
+ * `DB pools: minIdle=1 idleTimeout=600s queryTimeout=off leakDetection=off sealer=1`.
41
+ */
42
+ export declare function poolTuningLogLine(t: PoolTuning): string;
38
43
  /**
39
44
  * Single-database-layout spec §5.C, AC-1 (ADR-0041): the warning for `SHIELD_DB_NAME` set under
40
45
  * the four layout (it is read only when `SHIELD_DB_LAYOUT=single`), else `undefined`. Names the
@@ -1 +1 @@
1
- {"version":3,"file":"boot-sequence.d.ts","sourceRoot":"","sources":["../../src/boot/boot-sequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,qBACa,YAAa,YAAW,sBAAsB;IAGzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;gBAEE,MAAM,EAAE,SAAS;IAE5D,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAa7C;;;;;;;;;OASG;YACW,yBAAyB;CAIxC;AAED,wFAAwF;AACxF,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAMrE;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,SAAS,CAKrF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CAsC5D"}
1
+ {"version":3,"file":"boot-sequence.d.ts","sourceRoot":"","sources":["../../src/boot/boot-sequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,UAAU,EAChB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,qBACa,YAAa,YAAW,sBAAsB;IAGzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFvD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;gBAEE,MAAM,EAAE,SAAS;IAE5D,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAe7C;;;;;;;;;OASG;YACW,yBAAyB;CAIxC;AAED,wFAAwF;AACxF,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAMrE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAOvD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,SAAS,CAKrF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI,CA0C5D"}
@@ -14,6 +14,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.BootSequence = void 0;
16
16
  exports.frameworkDatabasesLogLine = frameworkDatabasesLogLine;
17
+ exports.poolTuningLogLine = poolTuningLogLine;
17
18
  exports.shieldDbNameIgnoredWarning = shieldDbNameIgnoredWarning;
18
19
  exports.assertPoolBudget = assertPoolBudget;
19
20
  const common_1 = require("@nestjs/common");
@@ -29,7 +30,7 @@ const app_config_js_1 = require("../config/app-config.js");
29
30
  * ───────────────────────────────────────────────────────────────────────────
30
31
  * ADR-0018 connection-pool assertion (FILLED).
31
32
  * {@link assertConnectionPoolReady} computes the connection budget
32
- * workers × Σ(per-account runtime pool max) + headroom ≤ maxConnections
33
+ * workers × (Σ(per-account runtime pool max) + 1 audit sealer) + headroom ≤ maxConnections
33
34
  * and THROWS (fail-closed, abort boot) on violation, so a pool config that
34
35
  * would exceed MariaDB's `max_connections` is caught at boot, never under load.
35
36
  * ───────────────────────────────────────────────────────────────────────────
@@ -44,6 +45,8 @@ let BootSequence = class BootSequence {
44
45
  // configurable-framework-db spec 5.E: the resolved database names, once per boot. Names
45
46
  // only — never a user, password, host or connection string.
46
47
  this.logger.log(frameworkDatabasesLogLine((0, app_config_js_1.frameworkSchemasOf)(this.config)));
48
+ // G-026 spec 5.N: the effective pool idle settings, numbers only.
49
+ this.logger.log(poolTuningLogLine((0, app_config_js_1.poolTuningOf)(this.config)));
47
50
  // Spec 5.C/AC-1: SHIELD_DB_NAME is read only in the single layout; say so when it is ignored.
48
51
  const ignored = shieldDbNameIgnoredWarning(process.env);
49
52
  if (ignored !== undefined)
@@ -81,6 +84,16 @@ function frameworkDatabasesLogLine(s) {
81
84
  return (`Shield databases: namespace=${s.namespace} app=${s.app} identity=${s.identity} ` +
82
85
  `authz=${s.authz} audit=${s.audit}`);
83
86
  }
87
+ /**
88
+ * The boot log line with the effective pool idle settings (G-026 spec 5.N), numbers only, e.g.
89
+ * `DB pools: minIdle=1 idleTimeout=600s queryTimeout=off leakDetection=off sealer=1`.
90
+ */
91
+ function poolTuningLogLine(t) {
92
+ const ms = (v) => (v === undefined ? 'off' : `${v}ms`);
93
+ return (`DB pools: minIdle=${t.minimumIdle} idleTimeout=${t.idleTimeoutS}s ` +
94
+ `queryTimeout=${ms(t.queryTimeoutMs)} leakDetection=${ms(t.leakDetectionMs)} ` +
95
+ `sealer=${app_config_js_1.AUDIT_SEALER_POOL_CONNECTIONS}`);
96
+ }
84
97
  /**
85
98
  * Single-database-layout spec §5.C, AC-1 (ADR-0041): the warning for `SHIELD_DB_NAME` set under
86
99
  * the four layout (it is read only when `SHIELD_DB_LAYOUT=single`), else `undefined`. Names the
@@ -113,7 +126,8 @@ function assertPoolBudget(cfg) {
113
126
  if (!e.withinUserBudget) {
114
127
  throw new Error('[ADR-0018] connection-pool assertion FAILED (fail-closed): single layout needs ' +
115
128
  `${e.requiredConnections} connections (workers(${cfg.workers}) × ` +
116
- `${e.perWorkerConnections} + headroom(${cfg.headroom})) but the account allows ` +
129
+ `${e.perWorkerConnections} (audit sealer's ${app_config_js_1.AUDIT_SEALER_POOL_CONNECTIONS} per worker ` +
130
+ `included) + headroom(${cfg.headroom})) but the account allows ` +
117
131
  `${cfg.maxUserConnections} (APP_DB_MAX_USER_CONNECTIONS). Reduce POOL_MAX_CORE, ` +
118
132
  'POOL_MAX_ENGINE, APP_AUTHZ_POOL_MAX, POOL_WORKERS or POOL_HEADROOM, or raise ' +
119
133
  'MAX_USER_CONNECTIONS on the account (ADR-0041).');
@@ -122,11 +136,14 @@ function assertPoolBudget(cfg) {
122
136
  throw new Error('[ADR-0018] connection-pool assertion FAILED (fail-closed): required ' +
123
137
  `connections ${e.requiredConnections} exceed max_connections ` +
124
138
  `${cfg.maxConnections}. Budget = workers(${cfg.workers}) × ` +
125
- `Σ(per-account pool max)(${e.perWorkerConnections}) + headroom(` +
139
+ `(Σ(per-account pool max) + audit sealer ${app_config_js_1.AUDIT_SEALER_POOL_CONNECTIONS})` +
140
+ `(${e.perWorkerConnections}) + headroom(` +
126
141
  `${cfg.headroom}) = ${e.requiredConnections} > ${cfg.maxConnections}. ` +
142
+ `The audit sealer's own pool counts ${app_config_js_1.AUDIT_SEALER_POOL_CONNECTIONS} per worker. ` +
127
143
  (cfg.layout === 'single'
128
144
  ? 'Single layout: one account opens POOL_MAX_CORE + POOL_MAX_ENGINE (unset ⇒ ' +
129
- 'APP_DB_MAX_CONNECTIONS, else 10) + APP_AUTHZ_POOL_MAX per worker; set POOL_MAX_ENGINE ' +
145
+ 'APP_DB_MAX_CONNECTIONS, else 10) + APP_AUTHZ_POOL_MAX + 1 (audit sealer) per worker; ' +
146
+ 'set POOL_MAX_ENGINE ' +
130
147
  'explicitly, lower a pool cap or the worker count, or raise max_connections.'
131
148
  : 'Reduce a per-account pool cap, the worker count, or raise ' +
132
149
  'max_connections (and MariaDB my.cnf) to restore the budget.'));
@@ -1,4 +1,5 @@
1
1
  import type { OperationInventory, ModuleRegistry } from '@astram/core';
2
+ import type { PermissionText } from '@astram/engine';
2
3
  import type { CatalogStore, ReconcileReport } from './ports/catalog-store.js';
3
4
  /** A @Classified route could not be gated (stranded or key-not-registered). Boot must
4
5
  * abort — an ungatable route may never serve traffic (ADR-0002 fail-closed). */
@@ -15,7 +16,21 @@ export declare class CatalogReconciler {
15
16
  * CRON — mutating. Auto-adds an ACTIVE catalog row per registered non-public action,
16
17
  * marks orphaned any stored row with no registered action, reactivates revived ones.
17
18
  * Idempotent. Returns a report for logging + /health/catalog.
19
+ *
20
+ * G-027 (spec §5E): `opts.text` (from `permissionTextByKey`) supplies label, description
21
+ * and caution; a key without text gets the engine's generated label. An insert stamps
22
+ * `firstSeenAt`/`lastActivatedAt = nowIso` and `firstSeenVersion = opts.release ?? null`;
23
+ * a reactivation stamps `lastActivatedAt` only. First-seen fields are never sent anywhere
24
+ * but the insert (spec §11, §13). A registered row whose text differs from `opts.text` is
25
+ * rewritten through ONE `store.updateText` call (skipped when the store lacks it).
18
26
  */
19
- reconcile(registry: ModuleRegistry, store: CatalogStore, nowIso: string): Promise<ReconcileReport>;
27
+ reconcile(registry: ModuleRegistry, store: CatalogStore, nowIso: string, opts?: ReconcileOptions): Promise<ReconcileReport>;
28
+ }
29
+ /** Options of {@link CatalogReconciler.reconcile} (G-027, spec §5E). */
30
+ export interface ReconcileOptions {
31
+ /** Permission key → code text (`permissionTextByKey`). Absent ⇒ generated labels, no relabel. */
32
+ readonly text?: ReadonlyMap<string, PermissionText>;
33
+ /** The app release (`APP_RELEASE`) stamped as `firstSeenVersion` on insert; absent ⇒ null. */
34
+ readonly release?: string | null;
20
35
  }
21
36
  //# sourceMappingURL=catalog-reconciler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-reconciler.d.ts","sourceRoot":"","sources":["../../src/completeness/catalog-reconciler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE9E;iFACiF;AACjF,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAiB;IAC5B;;;OAGG;IACH,aAAa,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAgB5E;;;;OAIG;IACG,SAAS,CACb,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,eAAe,CAAC;CAoC5B"}
1
+ {"version":3,"file":"catalog-reconciler.d.ts","sourceRoot":"","sources":["../../src/completeness/catalog-reconciler.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD,OAAO,KAAK,EAEV,YAAY,EAEZ,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAElC;iFACiF;AACjF,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,iBAAiB;IAC5B;;;OAGG;IACH,aAAa,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAgB5E;;;;;;;;;;;OAWG;IACG,SAAS,CACb,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,gBAAgB,GACtB,OAAO,CAAC,eAAe,CAAC;CA2D5B;AAED,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,iGAAiG;IACjG,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACpD,8FAA8F;IAC9F,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC"}
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CatalogReconciler = exports.CatalogGatabilityError = void 0;
4
4
  // astram-framework/packages/guard/src/completeness/catalog-reconciler.ts
5
5
  const core_1 = require("@astram/core");
6
+ const engine_1 = require("@astram/engine");
7
+ const identity_actions_js_1 = require("../identity/identity-actions.js");
6
8
  /** A @Classified route could not be gated (stranded or key-not-registered). Boot must
7
9
  * abort — an ungatable route may never serve traffic (ADR-0002 fail-closed). */
8
10
  class CatalogGatabilityError extends Error {
@@ -32,43 +34,105 @@ class CatalogReconciler {
32
34
  * CRON — mutating. Auto-adds an ACTIVE catalog row per registered non-public action,
33
35
  * marks orphaned any stored row with no registered action, reactivates revived ones.
34
36
  * Idempotent. Returns a report for logging + /health/catalog.
37
+ *
38
+ * G-027 (spec §5E): `opts.text` (from `permissionTextByKey`) supplies label, description
39
+ * and caution; a key without text gets the engine's generated label. An insert stamps
40
+ * `firstSeenAt`/`lastActivatedAt = nowIso` and `firstSeenVersion = opts.release ?? null`;
41
+ * a reactivation stamps `lastActivatedAt` only. First-seen fields are never sent anywhere
42
+ * but the insert (spec §11, §13). A registered row whose text differs from `opts.text` is
43
+ * rewritten through ONE `store.updateText` call (skipped when the store lacks it).
35
44
  */
36
- async reconcile(registry, store, nowIso) {
45
+ async reconcile(registry, store, nowIso, opts) {
46
+ const text = opts?.text;
47
+ const release = opts?.release ?? null;
37
48
  const stored = await store.listPermissions();
38
49
  const storedByKey = new Map(stored.map((r) => [r.permissionKey, r]));
39
50
  const registered = registry.listActions().filter((a) => a.tier !== 'public');
40
51
  const registeredKeys = new Set(registered.map((a) => a.permissionKey));
41
- // code → catalog: add missing rows; revive orphaned-but-now-registered.
52
+ // code → catalog: add missing rows; revive orphaned-but-now-registered; queue text rewrites.
42
53
  const added = [];
43
54
  const reactivated = [];
55
+ const textUpdates = [];
44
56
  for (const a of registered) {
45
57
  const key = a.permissionKey;
46
58
  const existing = storedByKey.get(key);
47
59
  if (!existing) {
60
+ const t = text?.get(key) ?? generatedText(registry, a.action.typeKey, a.action.actionKey);
48
61
  const inserted = await store.upsertPermission({
49
62
  permissionKey: key,
50
63
  moduleKey: a.moduleKey,
51
64
  typeKey: a.action.typeKey,
52
65
  action: a.action.actionKey,
53
- label: `${a.action.actionKey} ${a.action.typeKey}`,
66
+ label: t.label,
54
67
  tier: a.tier,
68
+ description: t.description,
69
+ caution: t.caution,
70
+ firstSeenAt: nowIso,
71
+ firstSeenVersion: release,
72
+ lastActivatedAt: nowIso,
55
73
  });
56
74
  if (inserted)
57
75
  added.push(key);
76
+ continue;
58
77
  }
59
- else if (existing.status === 'orphaned') {
78
+ if (existing.status === 'orphaned')
60
79
  reactivated.push(key);
80
+ const t = text?.get(key);
81
+ if (t && textDiffers(existing, t)) {
82
+ textUpdates.push({
83
+ permissionKey: key,
84
+ label: t.label,
85
+ description: t.description,
86
+ caution: t.caution,
87
+ });
61
88
  }
62
89
  }
63
90
  if (reactivated.length)
64
- await store.markActive(reactivated);
91
+ await store.markActive(reactivated, nowIso);
92
+ const relabelled = [];
93
+ if (textUpdates.length && store.updateText) {
94
+ await store.updateText(textUpdates);
95
+ relabelled.push(...textUpdates.map((u) => u.permissionKey));
96
+ }
65
97
  // catalog → code: mark orphaned any active stored row with no registered action.
66
98
  const orphaned = stored
67
99
  .filter((r) => r.status === 'active' && !registeredKeys.has(r.permissionKey))
68
100
  .map((r) => r.permissionKey);
69
101
  if (orphaned.length)
70
102
  await store.markOrphaned(orphaned);
71
- return { added, orphaned, reactivated, at: nowIso };
103
+ return { added, orphaned, reactivated, relabelled, at: nowIso };
72
104
  }
73
105
  }
74
106
  exports.CatalogReconciler = CatalogReconciler;
107
+ /** Stored vs code text, with absent/undefined normalised to null. */
108
+ function textDiffers(row, t) {
109
+ return (row.label !== t.label ||
110
+ (row.description ?? null) !== (t.description ?? null) ||
111
+ (row.caution ?? null) !== (t.caution ?? null));
112
+ }
113
+ /**
114
+ * The engine's generated text for a key with no text map entry (spec §10): engine
115
+ * `permissionTextOf` over a one-action declaration, the type label taken from the registry
116
+ * descriptor when it differs from the typeKey (the bridge sets `reg.label ?? typeKey`), else
117
+ * the humanized typeKey. A registry the engine rules cannot describe (e.g. a non-engine
118
+ * module's reserved action or an out-of-limits label) keeps the pre-G-027 label.
119
+ */
120
+ function generatedText(registry, typeKey, actionKey) {
121
+ const descriptorLabel = registry.resolveObjectType(typeKey)?.label;
122
+ const label = descriptorLabel && descriptorLabel !== typeKey ? descriptorLabel : undefined;
123
+ const isCrud = identity_actions_js_1.IDENTITY_ACTIONS.includes(actionKey);
124
+ try {
125
+ const [t] = (0, engine_1.permissionTextOf)({
126
+ typeKey,
127
+ ...(label !== undefined ? { label } : {}),
128
+ ...(isCrud ? {} : { crudActions: false, actions: [actionKey] }),
129
+ }).filter((p) => p.action === actionKey);
130
+ if (t)
131
+ return t;
132
+ }
133
+ catch (err) {
134
+ if (!(err instanceof engine_1.RegistrationError))
135
+ throw err;
136
+ }
137
+ return { label: `${actionKey} ${typeKey}`, description: null, caution: null };
138
+ }
@@ -3,6 +3,12 @@
3
3
  * the consumer app supplies the implementation (ADR-0003 — guard does no DB). A row is
4
4
  * keyed by its permission key (`moduleKey:typeKey:actionKey`); `status` is the soft
5
5
  * active/orphaned marker (never hard-delete).
6
+ *
7
+ * G-027 (permission text + first seen): the text and date fields are OPTIONAL and additive,
8
+ * so a store written before them keeps compiling. `firstSeenAt`/`firstSeenVersion` are
9
+ * written once, by the insert, and never changed afterwards (insert-only; the reconciler never
10
+ * asks the store to update them). Dates are ISO strings; `null` = unknown (e.g. a key that
11
+ * existed before tracking).
6
12
  */
7
13
  export interface CatalogPermissionRow {
8
14
  readonly permissionKey: string;
@@ -12,22 +18,51 @@ export interface CatalogPermissionRow {
12
18
  readonly label: string;
13
19
  readonly tier: string;
14
20
  readonly status: 'active' | 'orphaned';
21
+ /** What holding the permission lets a person do (plain text). */
22
+ readonly description?: string | null;
23
+ /** Optional warning shown to whoever grants it (plain text). */
24
+ readonly caution?: string | null;
25
+ /** When the key was first catalogued (ISO); insert-only. */
26
+ readonly firstSeenAt?: string | null;
27
+ /** The app release (`APP_RELEASE`) that first catalogued the key; insert-only. */
28
+ readonly firstSeenVersion?: string | null;
29
+ /** When the key last became active (insert or orphaned → active), ISO. */
30
+ readonly lastActivatedAt?: string | null;
31
+ }
32
+ /** One text rewrite the reconciler asks for (code text replaces stored text, G-027). */
33
+ export interface CatalogTextUpdate {
34
+ readonly permissionKey: string;
35
+ readonly label: string;
36
+ readonly description: string | null;
37
+ readonly caution: string | null;
15
38
  }
16
39
  /** The result of one mutating reconcile pass — surfaced via /health/catalog + logged. */
17
40
  export interface ReconcileReport {
18
41
  readonly added: readonly string[];
19
42
  readonly orphaned: readonly string[];
20
43
  readonly reactivated: readonly string[];
44
+ readonly relabelled: readonly string[];
21
45
  readonly at: string;
22
46
  }
23
47
  export interface CatalogStore {
24
48
  /** All catalog rows (both active + orphaned). */
25
49
  listPermissions(): Promise<CatalogPermissionRow[]>;
26
- /** Idempotent insert of an ACTIVE row (no-op if the key already exists as active). */
50
+ /**
51
+ * Idempotent insert of an ACTIVE row (no-op if the key already exists). Insert-only: an
52
+ * existing row is never updated here, so its first-seen fields keep their first values.
53
+ */
27
54
  upsertPermission(row: Omit<CatalogPermissionRow, 'status'>): Promise<boolean>;
28
55
  /** Mark keys orphaned (soft). No-op for keys already orphaned. */
29
56
  markOrphaned(keys: readonly string[]): Promise<void>;
30
- /** Flip keys orphaned → active (a route returned). */
31
- markActive(keys: readonly string[]): Promise<void>;
57
+ /**
58
+ * Flip keys orphaned → active (a route returned). With `nowIso`, stamp `lastActivatedAt`;
59
+ * never touch `firstSeenAt`/`firstSeenVersion`.
60
+ */
61
+ markActive(keys: readonly string[], nowIso?: string): Promise<void>;
62
+ /**
63
+ * OPTIONAL (G-027): rewrite label/description/caution of existing rows to the code's text.
64
+ * Writes only those three fields. A store without it still reconciles (no relabelling).
65
+ */
66
+ updateText?(rows: readonly CatalogTextUpdate[]): Promise<void>;
32
67
  }
33
68
  //# sourceMappingURL=catalog-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-store.d.ts","sourceRoot":"","sources":["../../../src/completeness/ports/catalog-store.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;CACxC;AAED,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,eAAe,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACnD,sFAAsF;IACtF,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9E,kEAAkE;IAClE,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,sDAAsD;IACtD,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD"}
1
+ {"version":3,"file":"catalog-store.d.ts","sourceRoot":"","sources":["../../../src/completeness/ports/catalog-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,CAAC;IACvC,iEAAiE;IACjE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,gEAAgE;IAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,4DAA4D;IAC5D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,kFAAkF;IAClF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED,wFAAwF;AACxF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,yFAAyF;AACzF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,eAAe,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACnD;;;OAGG;IACH,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9E,kEAAkE;IAClE,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE;;;OAGG;IACH,UAAU,CAAC,CAAC,IAAI,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE"}
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * ─────────────────────────────────────────────────────────────────────────────
13
13
  * ADR-0018 budget (the invariant this config feeds):
14
- * workers × Σ(per-account RUNTIME pool max) + headroom ≤ maxConnections
14
+ * workers × (Σ(per-account RUNTIME pool max) + 1 audit sealer) + headroom ≤ maxConnections
15
15
  *
16
16
  * "Runtime" pools are the pools each PM2 cluster worker holds open: shield_core,
17
17
  * shield_app_crud, shield_schema_svc. The deploy/ops accounts (migrate, backup,
@@ -20,7 +20,7 @@
20
20
  *
21
21
  * Defaults below agree byte-for-byte with infra/mariadb/conf.d/my.cnf
22
22
  * (max_connections=250) and the local docker-compose substrate:
23
- * 8 × (12 + 8 + 1) + 40 = 208 ≤ 250 ✓
23
+ * 8 × (12 + 8 + 1 + 1 sealer) + 40 = 216 ≤ 250 ✓ (G-026: the sealer's own 1-connection pool)
24
24
  * ─────────────────────────────────────────────────────────────────────────────
25
25
  */
26
26
  import type { FrameworkSchemas, SecretsProvider } from '@astram/core';
@@ -81,6 +81,13 @@ export interface AppConfig {
81
81
  * from `process.env` once at boot. Provided app-wide under `FRAMEWORK_SCHEMAS`.
82
82
  */
83
83
  readonly schemas?: FrameworkSchemas;
84
+ /**
85
+ * G-026 (db-pool-idle spec 5.A, 5.C): the idle and timeout settings every framework pool applies
86
+ * (`POOL_MIN_IDLE`, `POOL_IDLE_TIMEOUT_S`, `APP_DB_QUERY_TIMEOUT_MS`, `POOL_LEAK_DETECTION_MS`),
87
+ * filled by {@link loadAppConfig}. Optional so hand-built configs keep compiling; absent ⇒ the
88
+ * pool factories read {@link loadPoolTuning}`(process.env)` once at boot.
89
+ */
90
+ readonly poolTuning?: PoolTuning;
84
91
  }
85
92
  /**
86
93
  * The resolved framework database names for a config: `config.schemas`, else resolved from
@@ -219,6 +226,41 @@ export declare const SCHEMA_SVC_POOL_HARD_CAP = 2;
219
226
  * unset NODE_ENV is treated as "not dev").
220
227
  */
221
228
  export declare function isDevOrTestNodeEnv(raw: string | undefined): boolean;
229
+ /**
230
+ * G-026 (db-pool-idle spec 5.A, section 10): the idle and timeout settings of the framework pools.
231
+ * Caps are unchanged (they stay in {@link PoolBudgetConfig}); these only decide how many idle
232
+ * connections a pool keeps and how long a statement may run.
233
+ */
234
+ export interface PoolTuning {
235
+ /** `POOL_MIN_IDLE` (default 1, 0–1000): idle connections kept; each pool caps it at its own cap. */
236
+ readonly minimumIdle: number;
237
+ /** `POOL_IDLE_TIMEOUT_S` (default 600, 10–3600): seconds before an idle connection above the minimum closes. */
238
+ readonly idleTimeoutS: number;
239
+ /**
240
+ * `APP_DB_QUERY_TIMEOUT_MS` (unset ⇒ off, 1000–3600000): the session `max_statement_time` of every
241
+ * request-serving pool. Never applied to the audit sealer pool; framework lock waits opt out
242
+ * per statement (`withoutStatementTimeout`).
243
+ */
244
+ readonly queryTimeoutMs?: number;
245
+ /** `POOL_LEAK_DETECTION_MS` (unset ⇒ off, 1000–600000): log a connection held longer than this. */
246
+ readonly leakDetectionMs?: number;
247
+ }
248
+ /** Section 10 defaults: one idle connection per pool, closed after 10 idle minutes. */
249
+ export declare const DEFAULT_POOL_MIN_IDLE = 1;
250
+ export declare const DEFAULT_POOL_IDLE_TIMEOUT_S = 600;
251
+ /**
252
+ * Read the pool idle and timeout settings (db-pool-idle spec 5.A). Pure; every framework pool uses
253
+ * this one loader (no pool reads the variables itself). A set but invalid or out-of-range value
254
+ * throws naming the variable; blank or unset gives the default (off for the two optional ones).
255
+ */
256
+ export declare function loadPoolTuning(env?: NodeJS.ProcessEnv): PoolTuning;
257
+ /** The tuning for a config: `config.poolTuning`, else read from `process.env` (call at boot only). */
258
+ export declare function poolTuningOf(config: Pick<AppConfig, 'poolTuning'>): PoolTuning;
259
+ /**
260
+ * The audit sealer's own pool (db-pool-idle spec 5.D): one connection per worker, always counted
261
+ * in the budget (5.F), whether or not `auth: true` starts the sealer.
262
+ */
263
+ export declare const AUDIT_SEALER_POOL_CONNECTIONS = 1;
222
264
  /**
223
265
  * Build the {@link PoolBudgetConfig} from env with documented defaults.
224
266
  * Field ↔ env name:
@@ -393,7 +435,7 @@ export declare const DEFAULT_OBJECT_STORAGE_MAX_BYTES: number;
393
435
  export declare function loadObjectStorageConfig(env?: NodeJS.ProcessEnv, options?: LoadObjectStorageConfigOptions): ObjectStorageConfig | undefined;
394
436
  /** Result of evaluating a {@link PoolBudgetConfig} against the ADR-0018 budget. */
395
437
  export interface PoolBudgetEvaluation {
396
- /** Σ(per-account runtime pool max) for a single worker. */
438
+ /** Σ(per-account runtime pool max) + the audit sealer's 1, for a single worker. */
397
439
  readonly perWorkerConnections: number;
398
440
  /** workers × perWorkerConnections — total runtime connections at full load. */
399
441
  readonly runtimeConnections: number;
@@ -1 +1 @@
1
- {"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAWtE,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;IAC5D,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAGhC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,wBAAwB,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,gBAAgB,CAEvF;AAED,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,EAAE,kBAGpC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,WAAW,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC;IAC5B,2FAA2F;IAC3F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,8FAA8F;AAC9F,eAAO,MAAM,gCAAgC,OAAO,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,yDAAyD;IACzD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACxC;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAC3B,8FAA8F;IAC9F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,8EAA8E;IAC9E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,mGAAmG;IACnG,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,EAAE,gBASjC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAoB1C;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEnE;AA2BD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CA4CrF;AAWD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAKxD,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAoB1D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAC1B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,gBAA+C,GACvD,QAAQ,CA0BV;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,KAAK,GAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAGlD,GACA,WAAW,CAUb;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CAiBjF;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,wBAAwB,CAa1B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,kBAAkB,CAKzF;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE/E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASxD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAc7E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,CAAC,EAAE,eAAe,EAC1B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,SAAS,CAAC,CAIpB;AAMD,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,oGAAoG;IACpG,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,8FAA8F;IAC9F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,mDAAmD;AACnD,MAAM,WAAW,8BAA8B;IAC7C;;;;;;OAMG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAC/B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KAC9C,OAAO,CAAC;CACd;AAED,wFAAwF;AACxF,eAAO,MAAM,gCAAgC,QAAmB,CAAC;AAKjE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,OAAO,GAAE,8BAAmC,GAC3C,mBAAmB,GAAG,SAAS,CA+DjC;AA0BD,mFAAmF;AACnF,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,+EAA+E;IAC/E,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,GAAG,oBAAoB,CAyB9E"}
1
+ {"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_OBJECT_STORAGE_MAX_BYTES = exports.DEFAULT_REDIS_URL = exports.DEFAULT_DB_CONFIG = exports.SCHEMA_SVC_POOL_HARD_CAP = exports.DEFAULT_POOL_BUDGET = exports.DEFAULT_REDIS_COMMAND_TIMEOUT_MS = exports.DEFAULT_LOGIN_IP_LIMIT = void 0;
3
+ exports.DEFAULT_OBJECT_STORAGE_MAX_BYTES = exports.DEFAULT_REDIS_URL = exports.DEFAULT_DB_CONFIG = exports.AUDIT_SEALER_POOL_CONNECTIONS = exports.DEFAULT_POOL_IDLE_TIMEOUT_S = exports.DEFAULT_POOL_MIN_IDLE = exports.SCHEMA_SVC_POOL_HARD_CAP = exports.DEFAULT_POOL_BUDGET = exports.DEFAULT_REDIS_COMMAND_TIMEOUT_MS = exports.DEFAULT_LOGIN_IP_LIMIT = void 0;
4
4
  exports.frameworkSchemasOf = frameworkSchemasOf;
5
5
  exports.isDevOrTestNodeEnv = isDevOrTestNodeEnv;
6
+ exports.loadPoolTuning = loadPoolTuning;
7
+ exports.poolTuningOf = poolTuningOf;
6
8
  exports.loadPoolBudget = loadPoolBudget;
7
9
  exports.loadDbConfig = loadDbConfig;
8
10
  exports.loadDbTlsConfig = loadDbTlsConfig;
@@ -99,6 +101,51 @@ function strictOptionalPoolInt(raw, name) {
99
101
  throw new Error(`${name} must be a positive integer`);
100
102
  return n;
101
103
  }
104
+ /** Section 10 defaults: one idle connection per pool, closed after 10 idle minutes. */
105
+ exports.DEFAULT_POOL_MIN_IDLE = 1;
106
+ exports.DEFAULT_POOL_IDLE_TIMEOUT_S = 600;
107
+ /**
108
+ * A tuning variable: unset or blank gives `undefined`; otherwise plain digits (surrounding
109
+ * whitespace allowed) within `[min, max]`, or it throws naming the variable and the range, never the
110
+ * value (fail closed, Shield #1, core 70-secrets).
111
+ */
112
+ function strictOptionalRangeInt(raw, name, min, max) {
113
+ if (raw === undefined || raw.trim() === '')
114
+ return undefined;
115
+ const t = raw.trim();
116
+ const n = /^[0-9]+$/.test(t) ? Number(t) : Number.NaN;
117
+ if (!Number.isSafeInteger(n) || n < min || n > max) {
118
+ throw new Error(`${name} must be an integer ${min}–${max}`);
119
+ }
120
+ return n;
121
+ }
122
+ /**
123
+ * Read the pool idle and timeout settings (db-pool-idle spec 5.A). Pure; every framework pool uses
124
+ * this one loader (no pool reads the variables itself). A set but invalid or out-of-range value
125
+ * throws naming the variable; blank or unset gives the default (off for the two optional ones).
126
+ */
127
+ function loadPoolTuning(env = process.env) {
128
+ const minimumIdle = strictOptionalRangeInt(env.POOL_MIN_IDLE, 'POOL_MIN_IDLE', 0, 1000) ?? exports.DEFAULT_POOL_MIN_IDLE;
129
+ const idleTimeoutS = strictOptionalRangeInt(env.POOL_IDLE_TIMEOUT_S, 'POOL_IDLE_TIMEOUT_S', 10, 3600) ??
130
+ exports.DEFAULT_POOL_IDLE_TIMEOUT_S;
131
+ const queryTimeoutMs = strictOptionalRangeInt(env.APP_DB_QUERY_TIMEOUT_MS, 'APP_DB_QUERY_TIMEOUT_MS', 1000, 3_600_000);
132
+ const leakDetectionMs = strictOptionalRangeInt(env.POOL_LEAK_DETECTION_MS, 'POOL_LEAK_DETECTION_MS', 1000, 600_000);
133
+ return {
134
+ minimumIdle,
135
+ idleTimeoutS,
136
+ ...(queryTimeoutMs !== undefined ? { queryTimeoutMs } : {}),
137
+ ...(leakDetectionMs !== undefined ? { leakDetectionMs } : {}),
138
+ };
139
+ }
140
+ /** The tuning for a config: `config.poolTuning`, else read from `process.env` (call at boot only). */
141
+ function poolTuningOf(config) {
142
+ return config.poolTuning ?? loadPoolTuning(process.env);
143
+ }
144
+ /**
145
+ * The audit sealer's own pool (db-pool-idle spec 5.D): one connection per worker, always counted
146
+ * in the budget (5.F), whether or not `auth: true` starts the sealer.
147
+ */
148
+ exports.AUDIT_SEALER_POOL_CONNECTIONS = 1;
102
149
  /**
103
150
  * Build the {@link PoolBudgetConfig} from env with documented defaults.
104
151
  * Field ↔ env name:
@@ -362,6 +409,7 @@ function loadAppConfig(env = process.env) {
362
409
  lifetimes: loadSessionLifetimes(env),
363
410
  loginIpLimit: loadLoginIpLimit(env),
364
411
  ...(refreshReplayWindowMs !== undefined ? { refreshReplayWindowMs } : {}),
412
+ poolTuning: loadPoolTuning(env),
365
413
  };
366
414
  }
367
415
  /**
@@ -479,11 +527,12 @@ function parseStorageMaxBytes(raw) {
479
527
  */
480
528
  function evaluatePoolBudget(cfg) {
481
529
  // Single layout (AC-12): one account opens core + engine + authz; app_crud/schema_svc are never opened.
482
- const perWorkerConnections = cfg.layout === 'single'
530
+ // Both layouts add the audit sealer's own pool (G-026 spec 5.F: 1 per worker, always counted).
531
+ const perWorkerConnections = (cfg.layout === 'single'
483
532
  ? cfg.perAccountMax.shield_core + (cfg.engineMax ?? 10) + (cfg.authzMax ?? 4)
484
533
  : cfg.perAccountMax.shield_core +
485
534
  cfg.perAccountMax.shield_app_crud +
486
- cfg.perAccountMax.shield_schema_svc;
535
+ cfg.perAccountMax.shield_schema_svc) + exports.AUDIT_SEALER_POOL_CONNECTIONS;
487
536
  const runtimeConnections = cfg.workers * perWorkerConnections;
488
537
  const requiredConnections = runtimeConnections + cfg.headroom;
489
538
  const slack = cfg.maxConnections - requiredConnections;
@@ -1,4 +1,12 @@
1
1
  import type { ModuleRegistry } from '@astram/core';
2
- import type { ObjectTypeInput } from '@astram/engine';
2
+ import type { ObjectTypeInput, PermissionText } from '@astram/engine';
3
3
  export declare function buildIdentityModuleRegistry(inputs: readonly ObjectTypeInput[]): ModuleRegistry;
4
+ /**
5
+ * G-027 (spec §5D): the permission text of every action of the given types, keyed by the SAME
6
+ * permission key {@link buildIdentityModuleRegistry} registers (`MODULE_KEY` + core
7
+ * `derivePermissionKey`). Engine `permissionTextOf` gives the text in `effectiveActions` order
8
+ * (= {@link actionsOf}); declared text wins, else the generated label. Throws engine's
9
+ * `RegistrationError` on invalid text, like the registry build.
10
+ */
11
+ export declare function permissionTextByKey(inputs: readonly ObjectTypeInput[]): ReadonlyMap<string, PermissionText>;
4
12
  //# sourceMappingURL=module-registry.bridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module-registry.bridge.d.ts","sourceRoot":"","sources":["../../src/identity/module-registry.bridge.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,cAAc,EAIf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAc,eAAe,EAAE,MAAM,gBAAgB,CAAC;AASlE,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,cAAc,CA+B9F"}
1
+ {"version":3,"file":"module-registry.bridge.d.ts","sourceRoot":"","sources":["../../src/identity/module-registry.bridge.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,cAAc,EAIf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAc,eAAe,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AASlF,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,GAAG,cAAc,CAgC9F;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,eAAe,EAAE,GACjC,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAQrC"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildIdentityModuleRegistry = buildIdentityModuleRegistry;
4
+ exports.permissionTextByKey = permissionTextByKey;
4
5
  /**
5
6
  * Bridge: engine ObjectTypes → a populated core ModuleRegistry. Ported from astram3 (framework
6
7
  * now owns identity). Engine ObjectTypes describe physical tables; core's gates + the
@@ -25,7 +26,8 @@ function buildIdentityModuleRegistry(inputs) {
25
26
  const access = (0, core_access_js_1.coreAccessOf)(r.access);
26
27
  return {
27
28
  typeKey: r.typeKey,
28
- label: r.typeKey,
29
+ // G-027: the type's declared human name, else its typeKey (core contract unchanged).
30
+ label: r.label ?? r.typeKey,
29
31
  fields: r.fields.map((f) => {
30
32
  const ref = (0, engine_1.referencedTypeOf)(f);
31
33
  return { key: f.key, label: f.key, ...(ref ? { referencesTypeKey: ref } : {}) };
@@ -48,3 +50,19 @@ function buildIdentityModuleRegistry(inputs) {
48
50
  registry.register(metadata);
49
51
  return registry;
50
52
  }
53
+ /**
54
+ * G-027 (spec §5D): the permission text of every action of the given types, keyed by the SAME
55
+ * permission key {@link buildIdentityModuleRegistry} registers (`MODULE_KEY` + core
56
+ * `derivePermissionKey`). Engine `permissionTextOf` gives the text in `effectiveActions` order
57
+ * (= {@link actionsOf}); declared text wins, else the generated label. Throws engine's
58
+ * `RegistrationError` on invalid text, like the registry build.
59
+ */
60
+ function permissionTextByKey(inputs) {
61
+ const out = new Map();
62
+ for (const reg of inputs.map(toObjectType)) {
63
+ for (const t of (0, engine_1.permissionTextOf)(reg)) {
64
+ out.set((0, core_1.derivePermissionKey)(identity_actions_js_1.MODULE_KEY, reg.typeKey, t.action), t);
65
+ }
66
+ }
67
+ return out;
68
+ }
package/dist/index.d.ts CHANGED
@@ -15,7 +15,8 @@
15
15
  * `@nestjs/core`, `reflect-metadata`, `rxjs` so the host owns one copy of each.
16
16
  */
17
17
  export { guardMigrationsDir } from './migrations-dir.js';
18
- export { buildIdentityModuleRegistry } from './identity/module-registry.bridge.js';
18
+ export { buildIdentityModuleRegistry, permissionTextByKey, } from './identity/module-registry.bridge.js';
19
+ export type { PermissionText } from '@astram/engine';
19
20
  export { MODULE_KEY, IDENTITY_ACTIONS, CROSS_TENANT_GRANT_ACTIONS, RECORD_SHARE_ACTIONS, SERVICE_ACCOUNT_ACTIONS, actionsFor, actionsOf, } from './identity/identity-actions.js';
20
21
  export { ShieldModule, SHIELD_DECISION_AUTHORITY, SHIELD_RECORD_AUTHORIZATION, type ShieldModuleOptions, type ShieldModuleAsyncOptions, type RecordAuthorizationInputs, } from './module/shield.module.js';
21
22
  export { Public, Classified, CLASSIFICATION_METADATA, DEFAULT_CLASSIFIED_ACTION, normalizeClassification, } from './enforcement/classification.decorator.js';
@@ -23,7 +24,8 @@ export type { Classification } from './enforcement/classification.decorator.js';
23
24
  export { UuidPipe, uuidField, optionalUuidField, uuidArrayField } from './enforcement/uuid.pipe.js';
24
25
  export { OperationInventoryScanner } from './completeness/operation-inventory-scanner.js';
25
26
  export { CatalogReconciler, CatalogGatabilityError } from './completeness/catalog-reconciler.js';
26
- export type { CatalogStore, CatalogPermissionRow, ReconcileReport, } from './completeness/ports/catalog-store.js';
27
+ export type { ReconcileOptions } from './completeness/catalog-reconciler.js';
28
+ export type { CatalogStore, CatalogPermissionRow, CatalogTextUpdate, ReconcileReport, } from './completeness/ports/catalog-store.js';
27
29
  export { SHIELD_SESSION_TOKEN_BINDER, SHIELD_SERVICE_AUTHENTICATOR, } from './request-auth/tokens.js';
28
30
  export { SessionTokenBinder } from './request-auth/session-token-binder.js';
29
31
  export type { BoundPrincipalClaims, SessionTokenBinderOptions, } from './request-auth/session-token-binder.js';
@@ -70,10 +72,11 @@ export { FrameworkMigrationLedgerCheck, MigrationLedgerRegistry, SHIELD_MIGRATIO
70
72
  export { APP_CONFIG } from './config/config.module.js';
71
73
  export { FRAMEWORK_SCHEMAS } from './config/config.module.js';
72
74
  export type { FrameworkSchemaNames } from './config/framework-schema-names.js';
73
- export { frameworkSchemasOf, loadAppConfig, loadPoolBudget, evaluatePoolBudget, DEFAULT_POOL_BUDGET, SCHEMA_SVC_POOL_HARD_CAP, type AppConfig, type PoolBudgetConfig, type PoolBudgetEvaluation, type RuntimeAccountPools, loadDbConfig, loadRedisConfig, loadSessionLifetimes, loadRefreshHmacKey, assertRefreshHmacKey, DEFAULT_DB_CONFIG, DEFAULT_REDIS_URL, type DbConfig, type RedisConfig, type SessionLifetimeOverrides, loadLoginIpLimit, loadRefreshReplayWindowMs, DEFAULT_LOGIN_IP_LIMIT, isDevOrTestNodeEnv, type LoginIpLimitConfig, loadDbTlsConfig, type DbTlsConfig, } from './config/app-config.js';
75
+ export { frameworkSchemasOf, loadAppConfig, loadPoolBudget, evaluatePoolBudget, DEFAULT_POOL_BUDGET, SCHEMA_SVC_POOL_HARD_CAP, type AppConfig, type PoolBudgetConfig, type PoolBudgetEvaluation, type RuntimeAccountPools, loadDbConfig, loadRedisConfig, loadSessionLifetimes, loadRefreshHmacKey, assertRefreshHmacKey, DEFAULT_DB_CONFIG, DEFAULT_REDIS_URL, type DbConfig, type RedisConfig, type SessionLifetimeOverrides, loadLoginIpLimit, loadRefreshReplayWindowMs, DEFAULT_LOGIN_IP_LIMIT, isDevOrTestNodeEnv, type LoginIpLimitConfig, loadDbTlsConfig, type DbTlsConfig, loadPoolTuning, type PoolTuning, } from './config/app-config.js';
74
76
  export { rootIdsFromEnv } from './config/root-ids-from-env.js';
75
77
  export { ORG_BOOTSTRAP_PRINCIPAL_ID, assertNoReservedRootId, RESERVED_OPERATION_PRINCIPALS, reservedOperationPrincipal, type ReservedOperationPrincipal, } from './config/reserved-principal-ids.js';
76
78
  export { mariadbSslOption } from './auth/connections.js';
79
+ export { mariadbPoolTuningOptions, withoutStatementTimeout, type MariadbPoolTuningOptions, type MariadbPoolTuningOptionsOpts, } from './auth/connections.js';
77
80
  export { SHIELD_REDIS, SHIELD_CREDENTIAL_RESOLVER, SHIELD_PROFILE_RESOLVER, SHIELD_AUTHENTICATOR, SHIELD_SESSION_AUTHORITY, SHIELD_CREDENTIAL_WRITER, SHIELD_RESET_TOKEN_STORE, SHIELD_EMAIL_CHANGE_TOKEN_STORE, SHIELD_EMAIL_SENDER, SHIELD_MESSAGE_DISPATCHER, SHIELD_RECOVERY_CODE_STORE, SHIELD_PROFILE_WRITER, SHIELD_SESSION_SWEEPER, SHIELD_AUDIT_SINK, SHIELD_MFA_DEVICE_STORE, SHIELD_TOTP_VERIFIER_OVERRIDE, } from './auth/tokens.js';
78
81
  export { MariaDbCredentialResolver } from './authentication/mariadb-credential-resolver.js';
79
82
  export { resolveSignInWith, DEFAULT_SIGN_IN_WITH, type SignInMethod, } from './authentication/sign-in-with.js';