@astram/engine 0.8.0 → 0.9.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.
@@ -1 +1 @@
1
- {"version":3,"file":"engine.module.d.ts","sourceRoot":"","sources":["../../src/module/engine.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEL,KAAK,aAAa,EAKnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAuC,OAAO,EAAE,MAAM,aAAa,CAAC;AAIhF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC7F,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,0CAA0C,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,QAAQ,CAAC;AAMpD;;;;2EAI2E;AAC3E,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB;;;;qCAIqC;AACrC,eAAO,MAAM,wBAAwB,eAAqC,CAAC;AAE3E;;;;+CAI+C;AAC/C,eAAO,MAAM,yBAAyB,eAAsC,CAAC;AAmC7E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B;iFAC6E;IAC7E,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACpD,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IACpC,wCAAwC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CACzB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CACnB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,KACX,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CAC3D;AAYD,qBACa,YAAY;IACvB;;;;;;;;;OASG;IACH,MAAM,CAAC,UAAU,CACf,aAAa,EAAE,SAAS,eAAe,EAAE,EACzC,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,SAAS,CAAC,gBAAgB,GAAG,QAAQ,CAAC,EAAE,CAAA;KAAE,GAClE,aAAa;IAMhB;2FACuF;IACvF,MAAM,CAAC,aAAa,IAAI,IAAI;IAK5B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa;CAqG5D"}
1
+ {"version":3,"file":"engine.module.d.ts","sourceRoot":"","sources":["../../src/module/engine.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEL,KAAK,aAAa,EAMnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAuC,OAAO,EAAE,MAAM,aAAa,CAAC;AAIhF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAC7F,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEzD,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,0CAA0C,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,QAAQ,CAAC;AAMpD;;;;2EAI2E;AAC3E,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB;;;;qCAIqC;AACrC,eAAO,MAAM,wBAAwB,eAAqC,CAAC;AAE3E;;;;+CAI+C;AAC/C,eAAO,MAAM,yBAAyB,eAAsC,CAAC;AAmC7E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B;iFAC6E;IAC7E,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IACpD,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IACpC,wCAAwC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CACzB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB;;;;;;;;OAQG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CACnB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,KACX,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CAC3D;AAYD,qBACa,YAAY;IACvB;;;;;;;;;OASG;IACH,MAAM,CAAC,UAAU,CACf,aAAa,EAAE,SAAS,eAAe,EAAE,EACzC,IAAI,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,SAAS,CAAC,gBAAgB,GAAG,QAAQ,CAAC,EAAE,CAAA;KAAE,GAClE,aAAa;IAMhB;2FACuF;IACvF,MAAM,CAAC,aAAa,IAAI,IAAI;IAK5B,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,mBAAmB,GAAG,aAAa;CA6G5D"}
@@ -144,7 +144,15 @@ let EngineModule = EngineModule_1 = class EngineModule {
144
144
  const registryProvider = {
145
145
  provide: ENGINE_REGISTRY,
146
146
  useFactory: () => {
147
- const registry = new registry_js_1.TableRegistry(schemas);
147
+ const logger = new common_1.Logger('EngineModule');
148
+ const registry = new registry_js_1.TableRegistry(schemas, {
149
+ warn: (m) => logger.warn(m),
150
+ // Reserved with the framework tables (spec 5.B, ADR-0041); an invalid name is
151
+ // ignored by the registry and the default ledger name applies.
152
+ ...(process.env.APP_MIGRATION_TABLE !== undefined
153
+ ? { ledgerTable: process.env.APP_MIGRATION_TABLE }
154
+ : {}),
155
+ });
148
156
  for (const reg of allRegistrations)
149
157
  registry.register(reg);
150
158
  return registry;
@@ -11,7 +11,14 @@
11
11
  import { type FrameworkSchemas } from '@astram/core';
12
12
  import type { FieldSpec, PkStrategy, ObjectType, Principal } from './types.js';
13
13
  /** The four resolved names `resolveObjectTypeSchema` needs (a core `FrameworkSchemas` fits). */
14
- export type FrameworkSchemaNames = Pick<FrameworkSchemas, 'app' | 'identity' | 'authz' | 'audit'>;
14
+ export type FrameworkSchemaNames = Pick<FrameworkSchemas, 'app' | 'identity' | 'authz' | 'audit'> & Partial<Pick<FrameworkSchemas, 'layout'>>;
15
+ /** Options for {@link TableRegistry} (single-database-layout spec 5.B, ADR-0041). */
16
+ export interface TableRegistryOptions {
17
+ /** Receives one message per would-be collision in the four layout (never throws there). */
18
+ readonly warn?: (message: string) => void;
19
+ /** The migration ledger table name (`APP_MIGRATION_TABLE`); absent or invalid ⇒ the default. */
20
+ readonly ledgerTable?: string;
21
+ }
15
22
  /**
16
23
  * Return `reg` with every {@link FRAMEWORK_SCHEMA} token in `schema` and
17
24
  * `readScope.subquerySql` replaced by the resolved name (configurable-framework-db, spec 5.B).
@@ -26,16 +33,33 @@ export declare function resolveObjectTypeSchema(reg: ObjectType, schemas: Framew
26
33
  export declare class TableRegistry {
27
34
  private readonly schemas?;
28
35
  private readonly byType;
36
+ /** Single layout: lower-cased `db.table` → typeKey, for the duplicate check. */
37
+ private readonly byPhysical;
38
+ /** Lower-cased table name -> first typeKey, for the four-layout duplicate warning. */
39
+ private readonly byTableName;
40
+ private readonly ledgerTable;
41
+ private readonly warn;
29
42
  /**
30
43
  * @param schemas the resolved framework database names `FRAMEWORK_SCHEMA` tokens resolve to.
31
44
  * Absent ⇒ a registration that uses a token fails (fail closed); others are unaffected.
45
+ * @param opts `warn` (four-layout collision warnings) and `ledgerTable` (reserved with the
46
+ * framework tables). Single layout refuses collisions; four layout only warns
47
+ * (single-database-layout spec 5.B, ADR-0041).
32
48
  */
33
- constructor(schemas?: FrameworkSchemaNames | undefined);
49
+ constructor(schemas?: FrameworkSchemaNames | undefined, opts?: TableRegistryOptions);
34
50
  /**
35
51
  * Register a table. Resolves `FRAMEWORK_SCHEMA` tokens first (an unresolved token throws),
36
52
  * then throws on a duplicate typeKey or an invalid registration.
37
53
  */
38
54
  register(input: ObjectType): void;
55
+ /**
56
+ * Reserved framework table names (single-database-layout spec 5.B, ADR-0041). Single layout:
57
+ * refuse a reserved table in the framework database unless the registration declared a
58
+ * `FRAMEWORK_SCHEMA` token, and refuse a duplicate `(database, table)`; returns the `db.table`
59
+ * key to record. Four layout: warnings by table name only (reserved clash, or a name another
60
+ * registration already uses), never a throw; returns `undefined`.
61
+ */
62
+ private checkReservedTables;
39
63
  /** Resolve a registration, or throw a RegistrationError if unknown. */
40
64
  require(typeKey: string): ObjectType;
41
65
  has(typeKey: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAOrE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE/E,gGAAgG;AAChG,MAAM,MAAM,oBAAoB,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;AAOlG;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,oBAAoB,GAAG,SAAS,GACxC,UAAU,CAuCZ;AAED,qBAAa,aAAa;IAOZ,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IANrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IAExD;;;OAGG;gBAC0B,OAAO,CAAC,EAAE,oBAAoB,YAAA;IAE3D;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IASjC,uEAAuE;IACvE,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAWpC,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI7B,GAAG,IAAI,SAAS,UAAU,EAAE;CAG7B;AAED,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAEjD;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,EAAE,EAAE,UAAU,GAAG,MAAM,CAKnD;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAEhD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAG1D;AAED,6FAA6F;AAC7F,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI,CAG7D;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,IAAI,CAGrF;AAaD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,SAAS,GACf;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,GAAG,IAAI,CAYpD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAEvD;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAMvF;AAmDD,8FAA8F;AAC9F,KAAK,iBAAiB,GAAG,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,aAAa,CAAC,GAAG;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAgEF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,GAAG,SAAS,MAAM,EAAE,CAI1E"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
package/dist/registry.js CHANGED
@@ -75,24 +75,88 @@ function resolveObjectTypeSchema(reg, schemas) {
75
75
  class TableRegistry {
76
76
  schemas;
77
77
  byType = new Map();
78
+ /** Single layout: lower-cased `db.table` → typeKey, for the duplicate check. */
79
+ byPhysical = new Map();
80
+ /** Lower-cased table name -> first typeKey, for the four-layout duplicate warning. */
81
+ byTableName = new Map();
82
+ ledgerTable;
83
+ warn;
78
84
  /**
79
85
  * @param schemas the resolved framework database names `FRAMEWORK_SCHEMA` tokens resolve to.
80
86
  * Absent ⇒ a registration that uses a token fails (fail closed); others are unaffected.
87
+ * @param opts `warn` (four-layout collision warnings) and `ledgerTable` (reserved with the
88
+ * framework tables). Single layout refuses collisions; four layout only warns
89
+ * (single-database-layout spec 5.B, ADR-0041).
81
90
  */
82
- constructor(schemas) {
91
+ constructor(schemas, opts = {}) {
83
92
  this.schemas = schemas;
93
+ this.warn = opts.warn;
94
+ this.ledgerTable =
95
+ opts.ledgerTable !== undefined && core_1.MIGRATION_LEDGER_TABLE_PATTERN.test(opts.ledgerTable)
96
+ ? opts.ledgerTable
97
+ : undefined;
84
98
  }
85
99
  /**
86
100
  * Register a table. Resolves `FRAMEWORK_SCHEMA` tokens first (an unresolved token throws),
87
101
  * then throws on a duplicate typeKey or an invalid registration.
88
102
  */
89
103
  register(input) {
104
+ // "The framework itself" is declared by a FRAMEWORK_SCHEMA token, never inferred from a table
105
+ // name; captured before resolution replaces the token.
106
+ const declaredFramework = Object.values(types_js_1.FRAMEWORK_SCHEMA).includes(input.schema ?? '');
90
107
  const reg = resolveObjectTypeSchema(input, this.schemas);
91
108
  validate(reg);
92
109
  if (this.byType.has(reg.typeKey)) {
93
110
  throw new errors_js_1.RegistrationError(`duplicate table registration for typeKey '${reg.typeKey}'`);
94
111
  }
112
+ const physical = this.checkReservedTables(reg, declaredFramework);
95
113
  this.byType.set(reg.typeKey, reg);
114
+ if (physical !== undefined)
115
+ this.byPhysical.set(physical, reg.typeKey);
116
+ const name = reg.table.toLowerCase();
117
+ if (!this.byTableName.has(name))
118
+ this.byTableName.set(name, reg.typeKey);
119
+ }
120
+ /**
121
+ * Reserved framework table names (single-database-layout spec 5.B, ADR-0041). Single layout:
122
+ * refuse a reserved table in the framework database unless the registration declared a
123
+ * `FRAMEWORK_SCHEMA` token, and refuse a duplicate `(database, table)`; returns the `db.table`
124
+ * key to record. Four layout: warnings by table name only (reserved clash, or a name another
125
+ * registration already uses), never a throw; returns `undefined`.
126
+ */
127
+ checkReservedTables(reg, declaredFramework) {
128
+ const schemas = this.schemas;
129
+ if (schemas === undefined)
130
+ return undefined;
131
+ const table = reg.table.toLowerCase();
132
+ if (schemas.layout === 'single') {
133
+ const db = (reg.schema ?? schemas.app).toLowerCase();
134
+ const key = `${db}.${table}`;
135
+ if (!declaredFramework &&
136
+ (0, core_1.isReservedFrameworkTable)(table, this.ledgerTable) &&
137
+ db === schemas.app.toLowerCase()) {
138
+ throw new errors_js_1.RegistrationError(`registration '${reg.typeKey}': table '${key}' is reserved in the single-database ` +
139
+ `layout (framework table or migration ledger); choose another table name.`);
140
+ }
141
+ const other = this.byPhysical.get(key);
142
+ if (other !== undefined) {
143
+ throw new errors_js_1.RegistrationError(`registration '${reg.typeKey}': table '${key}' is already registered by '${other}'.`);
144
+ }
145
+ return key;
146
+ }
147
+ if (this.warn === undefined)
148
+ return undefined;
149
+ if (!declaredFramework && (0, core_1.isReservedFrameworkTable)(table, this.ledgerTable)) {
150
+ this.warn(`registration '${reg.typeKey}': table '${reg.table}' would collide with framework table ` +
151
+ `${table} in the single-database layout (SHIELD_DB_LAYOUT=single).`);
152
+ return undefined;
153
+ }
154
+ const other = this.byTableName.get(table);
155
+ if (other !== undefined) {
156
+ this.warn(`registration '${reg.typeKey}': table '${reg.table}' is also registered by '${other}'; ` +
157
+ `this would refuse to boot in the single-database layout`);
158
+ }
159
+ return undefined;
96
160
  }
97
161
  /** Resolve a registration, or throw a RegistrationError if unknown. */
98
162
  require(typeKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astram/engine",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "license": "MIT",
5
5
  "description": "Astram framework — the paved road. ONE unbypassable write pipe (resolve-schema → permission gate → derive-write-context → validate → compute → write → junction-sync → audit → emit-event) over real physical tables, that every feature's CRUD flows through. Feature code receives ONLY the RecordEngine facade — never a raw pool/DataSource/QueryRunner (the physical wall). Security-gate + audit are mandatory stages. Missing capability → a typed CapabilityNotSupportedError (the gap-flag STOP). Builds on @astram/core (metadata contract, decide(), audit) + @astram/guard (decision authority).",
6
6
  "type": "commonjs",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "mariadb": "^3.5.4",
35
- "@astram/core": "1.7.0"
35
+ "@astram/core": "1.8.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@nestjs/common": "^11",