@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,
|
|
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
|
|
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;
|
package/dist/registry.d.ts
CHANGED
|
@@ -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;
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,
|
|
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.
|
|
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.
|
|
35
|
+
"@astram/core": "1.8.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@nestjs/common": "^11",
|