emilsoftware-utilities 2.0.0-dev.35 → 2.0.0-dev.37
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.
- package/dist/accessi-module/AccessiModule.d.ts +5 -0
- package/dist/accessi-module/AccessiModule.js +9 -4
- package/dist/accessi-module/AccessiModule.js.map +1 -1
- package/dist/accessi-module/Console/console.css +7 -0
- package/dist/accessi-module/Console/console.js +58 -4
- package/dist/accessi-module/Console/console.js.map +1 -1
- package/dist/accessi-module/Console/generated/accessiApi.d.ts +11 -1
- package/dist/accessi-module/Console/generated/accessiApi.js +9 -1
- package/dist/accessi-module/Console/generated/accessiApi.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/getSchemaResponse.d.ts +14 -0
- package/dist/accessi-module/Console/generated/model/getSchemaResponse.js +3 -0
- package/dist/accessi-module/Console/generated/model/getSchemaResponse.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/index.d.ts +3 -0
- package/dist/accessi-module/Console/generated/model/index.js +3 -0
- package/dist/accessi-module/Console/generated/model/index.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/schemaDdlResult.d.ts +20 -0
- package/dist/accessi-module/Console/generated/model/schemaDdlResult.js +3 -0
- package/dist/accessi-module/Console/generated/model/schemaDdlResult.js.map +1 -0
- package/dist/accessi-module/Console/generated/model/schemaDdlSection.d.ts +12 -0
- package/dist/accessi-module/Console/generated/model/schemaDdlSection.js +9 -0
- package/dist/accessi-module/Console/generated/model/schemaDdlSection.js.map +1 -0
- package/dist/accessi-module/Console/index.html +6 -0
- package/dist/accessi-module/Console/wiki.js +6 -1
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/SchemaController.d.ts +9 -0
- package/dist/accessi-module/Controllers/SchemaController.js +79 -0
- package/dist/accessi-module/Controllers/SchemaController.js.map +1 -0
- package/dist/accessi-module/Dtos/SchemaDtos.d.ts +19 -0
- package/dist/accessi-module/Dtos/SchemaDtos.js +84 -0
- package/dist/accessi-module/Dtos/SchemaDtos.js.map +1 -0
- package/dist/accessi-module/Dtos/index.d.ts +1 -0
- package/dist/accessi-module/Dtos/index.js +1 -0
- package/dist/accessi-module/Dtos/index.js.map +1 -1
- package/dist/accessi-module/Services/SchemaExportService/SchemaExportService.d.ts +36 -0
- package/dist/accessi-module/Services/SchemaExportService/SchemaExportService.js +125 -0
- package/dist/accessi-module/Services/SchemaExportService/SchemaExportService.js.map +1 -0
- package/dist/accessi-module/database-updates/AccessiCatalogMigrator.d.ts +19 -0
- package/dist/accessi-module/database-updates/AccessiCatalogMigrator.js +75 -3
- package/dist/accessi-module/database-updates/AccessiCatalogMigrator.js.map +1 -1
- package/dist/accessi-module/database-updates/runAccessiCatalogMigrations.js +14 -2
- package/dist/accessi-module/database-updates/runAccessiCatalogMigrations.js.map +1 -1
- package/dist/accessi-module/index.d.ts +3 -1
- package/dist/accessi-module/index.js +5 -1
- package/dist/accessi-module/index.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.37.tgz +0 -0
- package/package.json +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.35.tgz +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { AccessiOptions } from '../../AccessiModule';
|
|
2
|
+
export interface SchemaDdlSection {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
sql: string;
|
|
6
|
+
}
|
|
7
|
+
export interface SchemaDdlResult {
|
|
8
|
+
version: string;
|
|
9
|
+
sections: SchemaDdlSection[];
|
|
10
|
+
script: string;
|
|
11
|
+
}
|
|
12
|
+
export interface SchemaEntitiesResult {
|
|
13
|
+
presentTables: string[];
|
|
14
|
+
extraTables: string[];
|
|
15
|
+
canonicalTables: string[];
|
|
16
|
+
presentGenerators: string[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Genera il DDL delle entita Accessi a partire dallo schema canonico (stessa fonte della
|
|
20
|
+
* riconciliazione) e rileva le entita effettivamente presenti nel database. Serve a
|
|
21
|
+
* esportare lo schema per replicarlo su altre installazioni.
|
|
22
|
+
*/
|
|
23
|
+
export declare class SchemaExportService {
|
|
24
|
+
private readonly options;
|
|
25
|
+
constructor(options: AccessiOptions);
|
|
26
|
+
/** DDL completo e deterministico dello schema Accessi. */
|
|
27
|
+
buildDdl(): SchemaDdlResult;
|
|
28
|
+
/** Elenca le tabelle/generatori presenti nel database e segnala quelli fuori schema canonical. */
|
|
29
|
+
presentEntities(): Promise<SchemaEntitiesResult>;
|
|
30
|
+
private buildTablesSection;
|
|
31
|
+
private buildGeneratorsSection;
|
|
32
|
+
private buildForeignKeysSection;
|
|
33
|
+
private buildIndexesSection;
|
|
34
|
+
private buildChecksSection;
|
|
35
|
+
private buildTriggersSection;
|
|
36
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
16
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
17
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
18
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
19
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
20
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.SchemaExportService = void 0;
|
|
25
|
+
const common_1 = require("@nestjs/common");
|
|
26
|
+
const Orm_1 = require("../../../Orm");
|
|
27
|
+
const Utilities_1 = require("../../../Utilities");
|
|
28
|
+
const accessiSchema_1 = require("../../database-updates/accessiSchema");
|
|
29
|
+
/**
|
|
30
|
+
* Genera il DDL delle entita Accessi a partire dallo schema canonico (stessa fonte della
|
|
31
|
+
* riconciliazione) e rileva le entita effettivamente presenti nel database. Serve a
|
|
32
|
+
* esportare lo schema per replicarlo su altre installazioni.
|
|
33
|
+
*/
|
|
34
|
+
let SchemaExportService = class SchemaExportService {
|
|
35
|
+
constructor(options) {
|
|
36
|
+
this.options = options;
|
|
37
|
+
}
|
|
38
|
+
/** DDL completo e deterministico dello schema Accessi. */
|
|
39
|
+
buildDdl() {
|
|
40
|
+
const sections = [
|
|
41
|
+
this.buildTablesSection(),
|
|
42
|
+
this.buildGeneratorsSection(),
|
|
43
|
+
this.buildForeignKeysSection(),
|
|
44
|
+
this.buildIndexesSection(),
|
|
45
|
+
this.buildChecksSection(),
|
|
46
|
+
this.buildTriggersSection(),
|
|
47
|
+
];
|
|
48
|
+
const script = sections
|
|
49
|
+
.map((section) => `-- ============================================================\n-- ${section.title}\n-- ============================================================\n${section.sql}`)
|
|
50
|
+
.join('\n\n');
|
|
51
|
+
return { version: accessiSchema_1.ACCESSI_SCHEMA_VERSION, sections, script };
|
|
52
|
+
}
|
|
53
|
+
/** Elenca le tabelle/generatori presenti nel database e segnala quelli fuori schema canonical. */
|
|
54
|
+
presentEntities() {
|
|
55
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
+
const canonicalTables = Object.keys(accessiSchema_1.accessiTables).sort();
|
|
57
|
+
const canonicalSet = new Set(canonicalTables);
|
|
58
|
+
const tableRows = (yield Orm_1.Orm.query(this.options.databaseOptions, `SELECT TRIM(RDB$RELATION_NAME) AS NAME
|
|
59
|
+
FROM RDB$RELATIONS
|
|
60
|
+
WHERE COALESCE(RDB$SYSTEM_FLAG, 0) = 0 AND RDB$VIEW_BLR IS NULL
|
|
61
|
+
ORDER BY RDB$RELATION_NAME`, [], false));
|
|
62
|
+
const presentTables = tableRows
|
|
63
|
+
.map((row) => { var _a; return String((_a = Utilities_1.RestUtilities.convertKeysToCamelCase(row).name) !== null && _a !== void 0 ? _a : '').trim(); })
|
|
64
|
+
.filter(Boolean);
|
|
65
|
+
const generatorRows = (yield Orm_1.Orm.query(this.options.databaseOptions, `SELECT TRIM(RDB$GENERATOR_NAME) AS NAME
|
|
66
|
+
FROM RDB$GENERATORS
|
|
67
|
+
WHERE COALESCE(RDB$SYSTEM_FLAG, 0) = 0
|
|
68
|
+
ORDER BY RDB$GENERATOR_NAME`, [], false));
|
|
69
|
+
const presentGenerators = generatorRows
|
|
70
|
+
.map((row) => { var _a; return String((_a = Utilities_1.RestUtilities.convertKeysToCamelCase(row).name) !== null && _a !== void 0 ? _a : '').trim(); })
|
|
71
|
+
.filter(Boolean);
|
|
72
|
+
return {
|
|
73
|
+
presentTables,
|
|
74
|
+
extraTables: presentTables.filter((name) => !canonicalSet.has(name)),
|
|
75
|
+
canonicalTables,
|
|
76
|
+
presentGenerators,
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
buildTablesSection() {
|
|
81
|
+
const statements = [];
|
|
82
|
+
for (const [table, schema] of Object.entries(accessiSchema_1.accessiTables)) {
|
|
83
|
+
const columns = Object.entries(schema.columns)
|
|
84
|
+
.map(([name, definition]) => ` ${name} ${definition}`)
|
|
85
|
+
.join(',\n');
|
|
86
|
+
statements.push(`CREATE TABLE ${table} (\n${columns}\n);`);
|
|
87
|
+
statements.push(`ALTER TABLE ${table} ADD CONSTRAINT PK_${table} PRIMARY KEY (${schema.primaryKey.join(', ')});`);
|
|
88
|
+
}
|
|
89
|
+
return { id: 'tables', title: `Tabelle (${Object.keys(accessiSchema_1.accessiTables).length})`, sql: statements.join('\n\n') };
|
|
90
|
+
}
|
|
91
|
+
buildGeneratorsSection() {
|
|
92
|
+
const statements = accessiSchema_1.accessiGenerators.map((generator) => `-- Firebird 2.5: CREATE GENERATOR ${generator.name}\nCREATE SEQUENCE ${generator.name};`);
|
|
93
|
+
return { id: 'generators', title: `Generatori/Sequenze (${accessiSchema_1.accessiGenerators.length})`, sql: statements.join('\n\n') };
|
|
94
|
+
}
|
|
95
|
+
buildForeignKeysSection() {
|
|
96
|
+
const statements = accessiSchema_1.accessiForeignKeys.map((fk) => `ALTER TABLE ${fk.table} ADD CONSTRAINT ${fk.name} FOREIGN KEY (${fk.column}) REFERENCES ${fk.target} (${fk.targetColumn})${fk.cascade ? ' ON DELETE CASCADE' : ''};`);
|
|
97
|
+
return { id: 'foreignKeys', title: `Chiavi esterne (${accessiSchema_1.accessiForeignKeys.length})`, sql: statements.join('\n\n') };
|
|
98
|
+
}
|
|
99
|
+
buildIndexesSection() {
|
|
100
|
+
const statements = accessiSchema_1.accessiIndexes.map((index) => `CREATE INDEX ${index.name} ON ${index.table} (${index.columns.join(', ')});`);
|
|
101
|
+
return { id: 'indexes', title: `Indici (${accessiSchema_1.accessiIndexes.length})`, sql: statements.join('\n\n') };
|
|
102
|
+
}
|
|
103
|
+
buildChecksSection() {
|
|
104
|
+
const statements = accessiSchema_1.accessiChecks.map((check) => `ALTER TABLE ${check.table} ADD CONSTRAINT ${check.name} CHECK (${check.expression});`);
|
|
105
|
+
return { id: 'checks', title: `Vincoli CHECK (${accessiSchema_1.accessiChecks.length})`, sql: statements.join('\n\n') };
|
|
106
|
+
}
|
|
107
|
+
buildTriggersSection() {
|
|
108
|
+
if (accessiSchema_1.accessiTriggers.length === 0) {
|
|
109
|
+
return { id: 'triggers', title: 'Trigger (0)', sql: '-- Nessun trigger di dominio.' };
|
|
110
|
+
}
|
|
111
|
+
const statements = accessiSchema_1.accessiTriggers.map((trigger) => `CREATE TRIGGER ${trigger.name} FOR ${trigger.table} ACTIVE ${trigger.event} ${trigger.body}`);
|
|
112
|
+
return {
|
|
113
|
+
id: 'triggers',
|
|
114
|
+
title: `Trigger (${accessiSchema_1.accessiTriggers.length})`,
|
|
115
|
+
sql: `SET TERM ^ ;\n\n${statements.join('^\n\n')}^\n\nSET TERM ; ^`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
exports.SchemaExportService = SchemaExportService;
|
|
120
|
+
exports.SchemaExportService = SchemaExportService = __decorate([
|
|
121
|
+
(0, common_1.Injectable)(),
|
|
122
|
+
__param(0, (0, common_1.Inject)('ACCESSI_OPTIONS')),
|
|
123
|
+
__metadata("design:paramtypes", [Object])
|
|
124
|
+
], SchemaExportService);
|
|
125
|
+
//# sourceMappingURL=SchemaExportService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SchemaExportService.js","sourceRoot":"","sources":["../../../../src/accessi-module/Services/SchemaExportService/SchemaExportService.ts"],"names":[],"mappings":"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","sourcesContent":["import { Inject, Injectable } from '@nestjs/common';\nimport { Orm } from '../../../Orm';\nimport { RestUtilities } from '../../../Utilities';\nimport type { AccessiOptions } from '../../AccessiModule';\nimport {\n ACCESSI_SCHEMA_VERSION,\n accessiTables,\n accessiForeignKeys,\n accessiIndexes,\n accessiChecks,\n accessiTriggers,\n accessiGenerators,\n} from '../../database-updates/accessiSchema';\n\nexport interface SchemaDdlSection {\n id: string;\n title: string;\n sql: string;\n}\n\nexport interface SchemaDdlResult {\n version: string;\n sections: SchemaDdlSection[];\n script: string;\n}\n\nexport interface SchemaEntitiesResult {\n presentTables: string[];\n extraTables: string[];\n canonicalTables: string[];\n presentGenerators: string[];\n}\n\n/**\n * Genera il DDL delle entita Accessi a partire dallo schema canonico (stessa fonte della\n * riconciliazione) e rileva le entita effettivamente presenti nel database. Serve a\n * esportare lo schema per replicarlo su altre installazioni.\n */\n@Injectable()\nexport class SchemaExportService {\n constructor(@Inject('ACCESSI_OPTIONS') private readonly options: AccessiOptions) {}\n\n /** DDL completo e deterministico dello schema Accessi. */\n buildDdl(): SchemaDdlResult {\n const sections: SchemaDdlSection[] = [\n this.buildTablesSection(),\n this.buildGeneratorsSection(),\n this.buildForeignKeysSection(),\n this.buildIndexesSection(),\n this.buildChecksSection(),\n this.buildTriggersSection(),\n ];\n\n const script = sections\n .map((section) => `-- ============================================================\\n-- ${section.title}\\n-- ============================================================\\n${section.sql}`)\n .join('\\n\\n');\n\n return { version: ACCESSI_SCHEMA_VERSION, sections, script };\n }\n\n /** Elenca le tabelle/generatori presenti nel database e segnala quelli fuori schema canonical. */\n async presentEntities(): Promise<SchemaEntitiesResult> {\n const canonicalTables = Object.keys(accessiTables).sort();\n const canonicalSet = new Set(canonicalTables);\n\n const tableRows = (await Orm.query(\n this.options.databaseOptions,\n `SELECT TRIM(RDB$RELATION_NAME) AS NAME\n FROM RDB$RELATIONS\n WHERE COALESCE(RDB$SYSTEM_FLAG, 0) = 0 AND RDB$VIEW_BLR IS NULL\n ORDER BY RDB$RELATION_NAME`,\n [],\n false,\n )) as Array<Record<string, unknown>>;\n const presentTables = tableRows\n .map((row) => String(RestUtilities.convertKeysToCamelCase(row).name ?? '').trim())\n .filter(Boolean);\n\n const generatorRows = (await Orm.query(\n this.options.databaseOptions,\n `SELECT TRIM(RDB$GENERATOR_NAME) AS NAME\n FROM RDB$GENERATORS\n WHERE COALESCE(RDB$SYSTEM_FLAG, 0) = 0\n ORDER BY RDB$GENERATOR_NAME`,\n [],\n false,\n )) as Array<Record<string, unknown>>;\n const presentGenerators = generatorRows\n .map((row) => String(RestUtilities.convertKeysToCamelCase(row).name ?? '').trim())\n .filter(Boolean);\n\n return {\n presentTables,\n extraTables: presentTables.filter((name) => !canonicalSet.has(name)),\n canonicalTables,\n presentGenerators,\n };\n }\n\n private buildTablesSection(): SchemaDdlSection {\n const statements: string[] = [];\n for (const [table, schema] of Object.entries(accessiTables)) {\n const columns = Object.entries(schema.columns)\n .map(([name, definition]) => ` ${name} ${definition}`)\n .join(',\\n');\n statements.push(`CREATE TABLE ${table} (\\n${columns}\\n);`);\n statements.push(`ALTER TABLE ${table} ADD CONSTRAINT PK_${table} PRIMARY KEY (${schema.primaryKey.join(', ')});`);\n }\n return { id: 'tables', title: `Tabelle (${Object.keys(accessiTables).length})`, sql: statements.join('\\n\\n') };\n }\n\n private buildGeneratorsSection(): SchemaDdlSection {\n const statements = accessiGenerators.map(\n (generator) =>\n `-- Firebird 2.5: CREATE GENERATOR ${generator.name}\\nCREATE SEQUENCE ${generator.name};`,\n );\n return { id: 'generators', title: `Generatori/Sequenze (${accessiGenerators.length})`, sql: statements.join('\\n\\n') };\n }\n\n private buildForeignKeysSection(): SchemaDdlSection {\n const statements = accessiForeignKeys.map(\n (fk) =>\n `ALTER TABLE ${fk.table} ADD CONSTRAINT ${fk.name} FOREIGN KEY (${fk.column}) REFERENCES ${fk.target} (${fk.targetColumn})${fk.cascade ? ' ON DELETE CASCADE' : ''};`,\n );\n return { id: 'foreignKeys', title: `Chiavi esterne (${accessiForeignKeys.length})`, sql: statements.join('\\n\\n') };\n }\n\n private buildIndexesSection(): SchemaDdlSection {\n const statements = accessiIndexes.map(\n (index) => `CREATE INDEX ${index.name} ON ${index.table} (${index.columns.join(', ')});`,\n );\n return { id: 'indexes', title: `Indici (${accessiIndexes.length})`, sql: statements.join('\\n\\n') };\n }\n\n private buildChecksSection(): SchemaDdlSection {\n const statements = accessiChecks.map(\n (check) => `ALTER TABLE ${check.table} ADD CONSTRAINT ${check.name} CHECK (${check.expression});`,\n );\n return { id: 'checks', title: `Vincoli CHECK (${accessiChecks.length})`, sql: statements.join('\\n\\n') };\n }\n\n private buildTriggersSection(): SchemaDdlSection {\n if (accessiTriggers.length === 0) {\n return { id: 'triggers', title: 'Trigger (0)', sql: '-- Nessun trigger di dominio.' };\n }\n const statements = accessiTriggers.map(\n (trigger) => `CREATE TRIGGER ${trigger.name} FOR ${trigger.table} ACTIVE ${trigger.event} ${trigger.body}`,\n );\n return {\n id: 'triggers',\n title: `Trigger (${accessiTriggers.length})`,\n sql: `SET TERM ^ ;\\n\\n${statements.join('^\\n\\n')}^\\n\\nSET TERM ; ^`,\n };\n }\n}\n"]}
|
|
@@ -11,11 +11,22 @@ export interface CatalogMigrationReport {
|
|
|
11
11
|
discovered: number;
|
|
12
12
|
applied: string[];
|
|
13
13
|
skipped: string[];
|
|
14
|
+
invalid: {
|
|
15
|
+
script: string;
|
|
16
|
+
violations: string[];
|
|
17
|
+
}[];
|
|
14
18
|
failed: {
|
|
15
19
|
script: string;
|
|
16
20
|
error: string;
|
|
17
21
|
}[];
|
|
18
22
|
}
|
|
23
|
+
/** Estrae la prima parola chiave di uno statement, saltando spazi e commenti iniziali. */
|
|
24
|
+
export declare function leadingStatementKeyword(statement: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Valida gli statement di una catalog migration: ritorna la lista delle violazioni (vuota se conforme).
|
|
27
|
+
* Regola tassativa: solo DML. Nessuna modifica a colonne/schema/trigger/permessi.
|
|
28
|
+
*/
|
|
29
|
+
export declare function analyzeCatalogScript(statements: string[]): string[];
|
|
19
30
|
/** Hash SHA-256 del contenuto dello script, usato per rilevare modifiche non versionate. */
|
|
20
31
|
export declare function computeCatalogScriptChecksum(content: string): string;
|
|
21
32
|
/**
|
|
@@ -40,6 +51,10 @@ export declare function listPendingCatalogScripts(options: AccessiOptions): Prom
|
|
|
40
51
|
applied: string[];
|
|
41
52
|
pending: string[];
|
|
42
53
|
changed: string[];
|
|
54
|
+
invalid: {
|
|
55
|
+
script: string;
|
|
56
|
+
violations: string[];
|
|
57
|
+
}[];
|
|
43
58
|
}>;
|
|
44
59
|
/**
|
|
45
60
|
* Applica le catalog migrations presenti nella cartella configurata.
|
|
@@ -60,5 +75,9 @@ export declare class AccessiCatalogMigrator {
|
|
|
60
75
|
applied: string[];
|
|
61
76
|
pending: string[];
|
|
62
77
|
changed: string[];
|
|
78
|
+
invalid: {
|
|
79
|
+
script: string;
|
|
80
|
+
violations: string[];
|
|
81
|
+
}[];
|
|
63
82
|
}>;
|
|
64
83
|
}
|
|
@@ -10,6 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.AccessiCatalogMigrator = void 0;
|
|
13
|
+
exports.leadingStatementKeyword = leadingStatementKeyword;
|
|
14
|
+
exports.analyzeCatalogScript = analyzeCatalogScript;
|
|
13
15
|
exports.computeCatalogScriptChecksum = computeCatalogScriptChecksum;
|
|
14
16
|
exports.splitSqlStatements = splitSqlStatements;
|
|
15
17
|
exports.discoverCatalogScripts = discoverCatalogScripts;
|
|
@@ -20,6 +22,58 @@ const fs_1 = require("fs");
|
|
|
20
22
|
const path_1 = require("path");
|
|
21
23
|
const Orm_1 = require("../../Orm");
|
|
22
24
|
const Logger_1 = require("../../Logger");
|
|
25
|
+
/**
|
|
26
|
+
* Le catalog migrations possono modificare SOLO righe (DML). Questa whitelist rende tassativo il
|
|
27
|
+
* vincolo: qualunque altro statement (DDL, trigger, transazioni, GRANT, ...) viene rifiutato.
|
|
28
|
+
*/
|
|
29
|
+
const ALLOWED_STATEMENT_KEYWORDS = new Set([
|
|
30
|
+
'INSERT', 'UPDATE', 'DELETE', 'MERGE', 'SELECT', 'EXECUTE',
|
|
31
|
+
]);
|
|
32
|
+
/** Estrae la prima parola chiave di uno statement, saltando spazi e commenti iniziali. */
|
|
33
|
+
function leadingStatementKeyword(statement) {
|
|
34
|
+
let index = 0;
|
|
35
|
+
while (index < statement.length) {
|
|
36
|
+
const char = statement[index];
|
|
37
|
+
if (/\s/.test(char)) {
|
|
38
|
+
index += 1;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (char === '-' && statement[index + 1] === '-') {
|
|
42
|
+
const newline = statement.indexOf('\n', index);
|
|
43
|
+
if (newline === -1)
|
|
44
|
+
return '';
|
|
45
|
+
index = newline + 1;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === '/' && statement[index + 1] === '*') {
|
|
49
|
+
const end = statement.indexOf('*/', index + 2);
|
|
50
|
+
if (end === -1)
|
|
51
|
+
return '';
|
|
52
|
+
index = end + 2;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
const match = /^([A-Za-z]+)/.exec(statement.slice(index));
|
|
58
|
+
return match ? match[1].toUpperCase() : '';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Valida gli statement di una catalog migration: ritorna la lista delle violazioni (vuota se conforme).
|
|
62
|
+
* Regola tassativa: solo DML. Nessuna modifica a colonne/schema/trigger/permessi.
|
|
63
|
+
*/
|
|
64
|
+
function analyzeCatalogScript(statements) {
|
|
65
|
+
const violations = [];
|
|
66
|
+
for (const statement of statements) {
|
|
67
|
+
const keyword = leadingStatementKeyword(statement);
|
|
68
|
+
if (!keyword)
|
|
69
|
+
continue;
|
|
70
|
+
if (!ALLOWED_STATEMENT_KEYWORDS.has(keyword)) {
|
|
71
|
+
const preview = statement.replace(/\s+/g, ' ').trim().slice(0, 120);
|
|
72
|
+
violations.push(`Statement non consentito (${keyword}): le catalog migrations possono modificare solo righe (INSERT/UPDATE/DELETE/MERGE). Estratto: "${preview}"`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return violations;
|
|
76
|
+
}
|
|
23
77
|
/** Ritorna la policy di checksum effettiva (default `error`). */
|
|
24
78
|
function checksumPolicy(options) {
|
|
25
79
|
var _a;
|
|
@@ -183,19 +237,27 @@ function listPendingCatalogScripts(options) {
|
|
|
183
237
|
if (!(yield isLedgerPresent(options))) {
|
|
184
238
|
throw new Error('AccessiCatalogMigrator: tabella ACCESSI_CATALOG_SCRIPT assente. Eseguire prima AccessiDatabaseUpdater.run (db:update:accessi).');
|
|
185
239
|
}
|
|
240
|
+
const allowDdl = config.allowDdl === true;
|
|
186
241
|
const ledger = yield readLedger(options);
|
|
187
242
|
const discovered = discoverCatalogScripts(config);
|
|
188
243
|
const pending = [];
|
|
189
244
|
const changed = [];
|
|
245
|
+
const invalid = [];
|
|
190
246
|
for (const script of discovered) {
|
|
191
|
-
const
|
|
247
|
+
const content = (0, fs_1.readFileSync)(script.path, 'utf8');
|
|
248
|
+
const checksum = computeCatalogScriptChecksum(content);
|
|
249
|
+
const violations = allowDdl ? [] : analyzeCatalogScript(splitSqlStatements(content));
|
|
250
|
+
if (violations.length > 0) {
|
|
251
|
+
invalid.push({ script: script.name, violations });
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
192
254
|
const appliedChecksum = ledger.get(script.name);
|
|
193
255
|
if (appliedChecksum === undefined)
|
|
194
256
|
pending.push(script.name);
|
|
195
257
|
else if (appliedChecksum !== checksum)
|
|
196
258
|
changed.push(script.name);
|
|
197
259
|
}
|
|
198
|
-
return { applied: [...ledger.keys()].sort(), pending, changed };
|
|
260
|
+
return { applied: [...ledger.keys()].sort(), pending, changed, invalid };
|
|
199
261
|
});
|
|
200
262
|
}
|
|
201
263
|
/**
|
|
@@ -223,8 +285,9 @@ function applyCatalogScripts(options) {
|
|
|
223
285
|
const discovered = discoverCatalogScripts(config);
|
|
224
286
|
const ledger = yield readLedger(options);
|
|
225
287
|
const stopOnError = config.stopOnError !== false;
|
|
288
|
+
const allowDdl = config.allowDdl === true;
|
|
226
289
|
const maxScripts = Number.isInteger(config.maxScriptsPerRun) && ((_a = config.maxScriptsPerRun) !== null && _a !== void 0 ? _a : 0) > 0 ? config.maxScriptsPerRun : undefined;
|
|
227
|
-
const report = { folder, discovered: discovered.length, applied: [], skipped: [], failed: [] };
|
|
290
|
+
const report = { folder, discovered: discovered.length, applied: [], skipped: [], invalid: [], failed: [] };
|
|
228
291
|
logger.info(`Catalog migrations: ${discovered.length} script trovati in ${folder}.`);
|
|
229
292
|
for (const script of discovered) {
|
|
230
293
|
if (maxScripts !== undefined && report.applied.length >= maxScripts) {
|
|
@@ -255,6 +318,15 @@ function applyCatalogScripts(options) {
|
|
|
255
318
|
}
|
|
256
319
|
try {
|
|
257
320
|
const statements = splitSqlStatements(content);
|
|
321
|
+
const violations = allowDdl ? [] : analyzeCatalogScript(statements);
|
|
322
|
+
if (violations.length > 0) {
|
|
323
|
+
report.invalid.push({ script: script.name, violations });
|
|
324
|
+
for (const violation of violations) {
|
|
325
|
+
logger.error(`Catalog migration non conforme: ${script.name}. ${violation}`);
|
|
326
|
+
}
|
|
327
|
+
// Il file non viene applicato ne registrato nel ledger; il run prosegue con gli altri.
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
258
330
|
for (const statement of statements) {
|
|
259
331
|
yield Orm_1.Orm.execute(options.databaseOptions, statement, [], false);
|
|
260
332
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AccessiCatalogMigrator.js","sourceRoot":"","sources":["../../../src/accessi-module/database-updates/AccessiCatalogMigrator.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from 'crypto';\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport { extname, join, relative, resolve, sep } from 'path';\nimport { Orm } from '../../Orm';\nimport { Logger } from '../../Logger';\nimport type { AccessiOptions, CatalogScriptChecksumPolicy, CatalogScriptsOptions } from '../AccessiModule';\n\nexport interface CatalogScriptMigration {\n name: string;\n applied: boolean;\n skipped: boolean;\n reapplied: boolean;\n error?: string;\n}\n\nexport interface CatalogMigrationReport {\n folder: string;\n discovered: number;\n applied: string[];\n skipped: string[];\n failed: { script: string; error: string }[];\n}\n\n/** Ritorna la policy di checksum effettiva (default `error`). */\nfunction checksumPolicy(options: CatalogScriptsOptions): CatalogScriptChecksumPolicy {\n return options.onChecksumMismatch ?? 'error';\n}\n\n/** Hash SHA-256 del contenuto dello script, usato per rilevare modifiche non versionate. */\nexport function computeCatalogScriptChecksum(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/**\n * Divide un file SQL in statement eseguibili separatamente.\n *\n * Supporta:\n * - terminator personalizzati con `SET TERM <char>` / `SET TERM <char> ;`\n * - stringhe `'...'` con escape `''`\n * - commenti di riga `--` e di blocco `/* ... * /`\n *\n * Non interpreta la semantica SQL: e volutamente un tokenizer prudente che non spezza\n * mai all'interno di stringhe o commenti.\n */\nexport function splitSqlStatements(sql: string, defaultTerminator = ';'): string[] {\n const statements: string[] = [];\n const lines = sql.replace(/\\r\\n?/g, '\\n').split('\\n');\n let buffer = '';\n let terminator = defaultTerminator;\n let inString = false;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (const line of lines) {\n const setTerm = /^\\s*SET\\s+TERM\\s+(\\S+)/i.exec(line);\n if (setTerm && !inString && !inLineComment && !inBlockComment) {\n const raw = setTerm[1] ?? '';\n terminator = raw.length > 1 && raw.endsWith(';') ? raw.slice(0, -1) : raw || defaultTerminator;\n continue;\n }\n\n buffer += `${line}\\n`;\n\n let start = 0;\n let index = 0;\n while (index < buffer.length) {\n const char = buffer[index] as string;\n const next = buffer[index + 1];\n\n if (inLineComment) {\n if (char === '\\n') inLineComment = false;\n index += 1;\n continue;\n }\n if (inBlockComment) {\n if (char === '*' && next === '/') {\n inBlockComment = false;\n index += 2;\n continue;\n }\n index += 1;\n continue;\n }\n if (inString) {\n if (char === \"'\") {\n if (next === \"'\") {\n index += 2;\n continue;\n }\n inString = false;\n }\n index += 1;\n continue;\n }\n\n if (char === \"'\") {\n inString = true;\n index += 1;\n continue;\n }\n if (char === '-' && next === '-') {\n inLineComment = true;\n index += 2;\n continue;\n }\n if (char === '/' && next === '*') {\n inBlockComment = true;\n index += 2;\n continue;\n }\n if (buffer.startsWith(terminator, index)) {\n const statement = buffer.slice(start, index).trim();\n if (statement) statements.push(statement);\n index += terminator.length;\n start = index;\n continue;\n }\n index += 1;\n }\n\n buffer = buffer.slice(start);\n }\n\n const trailing = buffer.trim();\n if (trailing) statements.push(trailing);\n return statements;\n}\n\n/** Elenca gli script `.sql` della cartella, ordinati per percorso (prefissi numerici consigliati). */\nexport function discoverCatalogScripts(options: CatalogScriptsOptions): { name: string; path: string }[] {\n const folder = resolve(options.folder);\n if (!existsSync(folder)) {\n throw new Error(`AccessiCatalogMigrator: cartella non trovata: ${folder}`);\n }\n\n const include = options.include && options.include.length > 0 ? options.include : ['.sql'];\n const found: { name: string; path: string }[] = [];\n\n const walk = (directory: string): void => {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const absolute = join(directory, entry.name);\n if (entry.isDirectory()) {\n walk(absolute);\n continue;\n }\n if (!entry.isFile()) continue;\n const matches = include.some((pattern) =>\n pattern.startsWith('.') ? extname(entry.name).toLowerCase() === pattern.toLowerCase() : entry.name.includes(pattern),\n );\n if (!matches) continue;\n const name = relative(folder, absolute).split(sep).join('/');\n found.push({ name, path: absolute });\n }\n };\n\n walk(folder);\n return found.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction isLedgerPresent(options: AccessiOptions): Promise<boolean> {\n return Orm.query(\n options.databaseOptions,\n \"SELECT 1 FROM RDB$RELATIONS WHERE TRIM(RDB$RELATION_NAME) = 'ACCESSI_CATALOG_SCRIPT'\",\n [],\n false,\n ).then((rows) => rows.length > 0);\n}\n\n/** Legge il ledger come mappa `script -> checksum`. */\nasync function readLedger(options: AccessiOptions): Promise<Map<string, string>> {\n const rows = (await Orm.query(\n options.databaseOptions,\n 'SELECT SCRIPT_NAME AS NAME, CHECKSUM FROM ACCESSI_CATALOG_SCRIPT',\n [],\n false,\n )) as Array<Record<string, unknown>>;\n const ledger = new Map<string, string>();\n for (const row of rows) {\n const name = String(row.NAME ?? row.name ?? '').trim();\n const checksum = String(row.CHECKSUM ?? row.checksum ?? '').trim();\n if (name) ledger.set(name, checksum);\n }\n return ledger;\n}\n\nasync function upsertLedger(options: AccessiOptions, name: string, checksum: string, reapplied: boolean): Promise<void> {\n if (reapplied) {\n await Orm.execute(\n options.databaseOptions,\n 'UPDATE ACCESSI_CATALOG_SCRIPT SET CHECKSUM = ?, APPLIED_AT = CURRENT_TIMESTAMP, APPLIED_COUNT = APPLIED_COUNT + 1 WHERE SCRIPT_NAME = ?',\n [checksum, name],\n false,\n );\n return;\n }\n await Orm.execute(\n options.databaseOptions,\n 'UPDATE OR INSERT INTO ACCESSI_CATALOG_SCRIPT (SCRIPT_NAME, CHECKSUM, APPLIED_AT, APPLIED_COUNT) VALUES (?, ?, CURRENT_TIMESTAMP, 1) MATCHING (SCRIPT_NAME)',\n [name, checksum],\n false,\n );\n}\n\n/** Elenca gli script non ancora applicati (o con checksum diverso) senza eseguirli. */\nexport async function listPendingCatalogScripts(options: AccessiOptions): Promise<{ applied: string[]; pending: string[]; changed: string[] }> {\n const config = options.catalogScripts;\n if (!config?.folder) throw new Error('AccessiCatalogMigrator: catalogScripts.folder non configurato.');\n if (!(await isLedgerPresent(options))) {\n throw new Error('AccessiCatalogMigrator: tabella ACCESSI_CATALOG_SCRIPT assente. Eseguire prima AccessiDatabaseUpdater.run (db:update:accessi).');\n }\n\n const ledger = await readLedger(options);\n const discovered = discoverCatalogScripts(config);\n const pending: string[] = [];\n const changed: string[] = [];\n\n for (const script of discovered) {\n const checksum = computeCatalogScriptChecksum(readFileSync(script.path, 'utf8'));\n const appliedChecksum = ledger.get(script.name);\n if (appliedChecksum === undefined) pending.push(script.name);\n else if (appliedChecksum !== checksum) changed.push(script.name);\n }\n\n return { applied: [...ledger.keys()].sort(), pending, changed };\n}\n\n/**\n * Applica le catalog migrations presenti nella cartella configurata.\n *\n * Idempotenza:\n * - uno script gia presente nel ledger con lo stesso checksum viene saltato;\n * - uno script gia applicato ma modificato segue `onChecksumMismatch` (`error` default, `warn`, `reapply`);\n * - un errore interrompe il run (default) senza avanzare, lasciando il ledger all'ultimo script completato.\n *\n * Il chiamante deve avere gia riconciliato lo schema (`AccessiDatabaseUpdater.run`): la tabella\n * ledger `ACCESSI_CATALOG_SCRIPT` e creata dall'updater.\n */\nexport async function applyCatalogScripts(options: AccessiOptions): Promise<CatalogMigrationReport> {\n const logger = new Logger(AccessiCatalogMigrator.name);\n const config = options.catalogScripts;\n if (!config?.folder) throw new Error('AccessiCatalogMigrator: catalogScripts.folder non configurato.');\n if (!(await isLedgerPresent(options))) {\n throw new Error('AccessiCatalogMigrator: tabella ACCESSI_CATALOG_SCRIPT assente. Eseguire prima AccessiDatabaseUpdater.run (db:update:accessi).');\n }\n\n const folder = resolve(config.folder);\n const discovered = discoverCatalogScripts(config);\n const ledger = await readLedger(options);\n const stopOnError = config.stopOnError !== false;\n const maxScripts = Number.isInteger(config.maxScriptsPerRun) && (config.maxScriptsPerRun ?? 0) > 0 ? config.maxScriptsPerRun : undefined;\n const report: CatalogMigrationReport = { folder, discovered: discovered.length, applied: [], skipped: [], failed: [] };\n\n logger.info(`Catalog migrations: ${discovered.length} script trovati in ${folder}.`);\n\n for (const script of discovered) {\n if (maxScripts !== undefined && report.applied.length >= maxScripts) {\n logger.warning(`Catalog migrations: limite maxScriptsPerRun=${maxScripts} raggiunto, resto rimandato.`);\n break;\n }\n\n const content = readFileSync(script.path, 'utf8');\n const checksum = computeCatalogScriptChecksum(content);\n const appliedChecksum = ledger.get(script.name);\n\n if (appliedChecksum === checksum) {\n report.skipped.push(script.name);\n continue;\n }\n\n let reapplied = false;\n if (appliedChecksum !== undefined && appliedChecksum !== checksum) {\n const policy = checksumPolicy(config);\n if (policy === 'error') {\n throw new Error(\n `AccessiCatalogMigrator: lo script \"${script.name}\" e gia applicato con un checksum diverso (migrazioni immutabili). ` +\n `Ripristina il file o configura onChecksumMismatch='reapply'/'warn' consapevolmente.`,\n );\n }\n if (policy === 'warn') {\n logger.warning(`Catalog migrations: \"${script.name}\" applicato con checksum diverso, ignorato (policy warn).`);\n report.skipped.push(script.name);\n continue;\n }\n reapplied = true;\n logger.warning(`Catalog migrations: \"${script.name}\" riapplicato (policy reapply).`);\n }\n\n try {\n const statements = splitSqlStatements(content);\n for (const statement of statements) {\n await Orm.execute(options.databaseOptions, statement, [], false);\n }\n await upsertLedger(options, script.name, checksum, reapplied);\n ledger.set(script.name, checksum);\n report.applied.push(script.name);\n logger.info(`Catalog migration applicata: ${script.name} (${statements.length} statement).`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n report.failed.push({ script: script.name, error: message });\n logger.error(`Catalog migration fallita: ${script.name}. ${message}`);\n if (stopOnError) {\n throw new Error(`AccessiCatalogMigrator: script \"${script.name}\" fallito. ${message}`);\n }\n }\n }\n\n return report;\n}\n\n/** Esegue la riconciliazione dello schema non e responsabilita di questa classe: usare l'updater prima. */\nexport class AccessiCatalogMigrator {\n static apply(options: AccessiOptions): Promise<CatalogMigrationReport> {\n return applyCatalogScripts(options);\n }\n\n static listPending(options: AccessiOptions): Promise<{ applied: string[]; pending: string[]; changed: string[] }> {\n return listPendingCatalogScripts(options);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"AccessiCatalogMigrator.js","sourceRoot":"","sources":["../../../src/accessi-module/database-updates/AccessiCatalogMigrator.ts"],"names":[],"mappings":";;;;;;;;;;;;AAiCA,0DAqBC;AAMD,oDAaC;AAQD,oEAEC;AAaD,gDAkFC;AAGD,wDA4BC;AA+CD,8DA4BC;AAaD,kDAgFC;AAzXD,mCAAoC;AACpC,2BAA2D;AAC3D,+BAA6D;AAC7D,mCAAgC;AAChC,yCAAsC;AAoBtC;;;GAGG;AACH,MAAM,0BAA0B,GAAwB,IAAI,GAAG,CAAC;IAC9D,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS;CAC3D,CAAC,CAAC;AAEH,0FAA0F;AAC1F,SAAgB,uBAAuB,CAAC,SAAiB;IACvD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAW,CAAC;QACxC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAAC,KAAK,IAAI,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QAC9C,IAAI,IAAI,KAAK,GAAG,IAAI,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACjD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC/C,IAAI,OAAO,KAAK,CAAC,CAAC;gBAAE,OAAO,EAAE,CAAC;YAC9B,KAAK,GAAG,OAAO,GAAG,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,GAAG,IAAI,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACjD,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAC/C,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,OAAO,EAAE,CAAC;YAC1B,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;YAChB,SAAS;QACX,CAAC;QACD,MAAM;IACR,CAAC;IACD,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1D,OAAO,KAAK,CAAC,CAAC,CAAE,KAAK,CAAC,CAAC,CAAY,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,UAAoB;IACvD,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7C,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YACpE,UAAU,CAAC,IAAI,CACb,6BAA6B,OAAO,mGAAmG,OAAO,GAAG,CAClJ,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,iEAAiE;AACjE,SAAS,cAAc,CAAC,OAA8B;;IACpD,OAAO,MAAA,OAAO,CAAC,kBAAkB,mCAAI,OAAO,CAAC;AAC/C,CAAC;AAED,4FAA4F;AAC5F,SAAgB,4BAA4B,CAAC,OAAe;IAC1D,OAAO,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,kBAAkB,CAAC,GAAW,EAAE,iBAAiB,GAAG,GAAG;;IACrE,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,UAAU,GAAG,iBAAiB,CAAC;IACnC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,IAAI,cAAc,GAAG,KAAK,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,OAAO,IAAI,CAAC,QAAQ,IAAI,CAAC,aAAa,IAAI,CAAC,cAAc,EAAE,CAAC;YAC9D,MAAM,GAAG,GAAG,MAAA,OAAO,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC;YAC7B,UAAU,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,iBAAiB,CAAC;YAC/F,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;QAEtB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,OAAO,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAW,CAAC;YACrC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YAE/B,IAAI,aAAa,EAAE,CAAC;gBAClB,IAAI,IAAI,KAAK,IAAI;oBAAE,aAAa,GAAG,KAAK,CAAC;gBACzC,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YACD,IAAI,cAAc,EAAE,CAAC;gBACnB,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBACjC,cAAc,GAAG,KAAK,CAAC;oBACvB,KAAK,IAAI,CAAC,CAAC;oBACX,SAAS;gBACX,CAAC;gBACD,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YACD,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;oBACjB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;wBACjB,KAAK,IAAI,CAAC,CAAC;wBACX,SAAS;oBACX,CAAC;oBACD,QAAQ,GAAG,KAAK,CAAC;gBACnB,CAAC;gBACD,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YAED,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjB,QAAQ,GAAG,IAAI,CAAC;gBAChB,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YACD,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjC,aAAa,GAAG,IAAI,CAAC;gBACrB,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YACD,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;gBACjC,cAAc,GAAG,IAAI,CAAC;gBACtB,KAAK,IAAI,CAAC,CAAC;gBACX,SAAS;YACX,CAAC;YACD,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC;gBACzC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;gBACpD,IAAI,SAAS;oBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC1C,KAAK,IAAI,UAAU,CAAC,MAAM,CAAC;gBAC3B,KAAK,GAAG,KAAK,CAAC;gBACd,SAAS;YACX,CAAC;YACD,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;QAED,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,QAAQ;QAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,sGAAsG;AACtG,SAAgB,sBAAsB,CAAC,OAA8B;IACnE,MAAM,MAAM,GAAG,IAAA,cAAO,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,IAAA,eAAU,EAAC,MAAM,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,iDAAiD,MAAM,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC3F,MAAM,KAAK,GAAqC,EAAE,CAAC;IAEnD,MAAM,IAAI,GAAG,CAAC,SAAiB,EAAQ,EAAE;QACvC,KAAK,MAAM,KAAK,IAAI,IAAA,gBAAW,EAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACpE,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACf,SAAS;YACX,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;gBAAE,SAAS;YAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CACvC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAA,cAAO,EAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CACrH,CAAC;YACF,IAAI,CAAC,OAAO;gBAAE,SAAS;YACvB,MAAM,IAAI,GAAG,IAAA,eAAQ,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,UAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC7D,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,CAAC;IACb,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,SAAS,eAAe,CAAC,OAAuB;IAC9C,OAAO,SAAG,CAAC,KAAK,CACd,OAAO,CAAC,eAAe,EACvB,sFAAsF,EACtF,EAAE,EACF,KAAK,CACN,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,uDAAuD;AACvD,SAAe,UAAU,CAAC,OAAuB;;;QAC/C,MAAM,IAAI,GAAG,CAAC,MAAM,SAAG,CAAC,KAAK,CAC3B,OAAO,CAAC,eAAe,EACvB,kEAAkE,EAClE,EAAE,EACF,KAAK,CACN,CAAmC,CAAC;QACrC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAA,MAAA,GAAG,CAAC,IAAI,mCAAI,GAAG,CAAC,IAAI,mCAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACvD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAA,MAAA,GAAG,CAAC,QAAQ,mCAAI,GAAG,CAAC,QAAQ,mCAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACnE,IAAI,IAAI;gBAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CAAA;AAED,SAAe,YAAY,CAAC,OAAuB,EAAE,IAAY,EAAE,QAAgB,EAAE,SAAkB;;QACrG,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,SAAG,CAAC,OAAO,CACf,OAAO,CAAC,eAAe,EACvB,yIAAyI,EACzI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAChB,KAAK,CACN,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,SAAG,CAAC,OAAO,CACf,OAAO,CAAC,eAAe,EACvB,4JAA4J,EAC5J,CAAC,IAAI,EAAE,QAAQ,CAAC,EAChB,KAAK,CACN,CAAC;IACJ,CAAC;CAAA;AAED,uFAAuF;AACvF,SAAsB,yBAAyB,CAAC,OAAuB;;QACrE,MAAM,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;QACtC,IAAI,CAAC,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,CAAA;YAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACvG,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,gIAAgI,CAAC,CAAC;QACpJ,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,OAAO,GAA+C,EAAE,CAAC;QAE/D,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAG,4BAA4B,CAAC,OAAO,CAAC,CAAC;YACvD,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;YACrF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;gBAClD,SAAS;YACX,CAAC;YACD,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,eAAe,KAAK,SAAS;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;iBACxD,IAAI,eAAe,KAAK,QAAQ;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAC3E,CAAC;CAAA;AAED;;;;;;;;;;GAUG;AACH,SAAsB,mBAAmB,CAAC,OAAuB;;;QAC/D,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;QACtC,IAAI,CAAC,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,CAAA;YAAE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACvG,IAAI,CAAC,CAAC,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,gIAAgI,CAAC,CAAC;QACpJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,cAAO,EAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,KAAK,KAAK,CAAC;QACjD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC;QAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAA,MAAM,CAAC,gBAAgB,mCAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC;QACzI,MAAM,MAAM,GAA2B,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QAEpI,MAAM,CAAC,IAAI,CAAC,uBAAuB,UAAU,CAAC,MAAM,sBAAsB,MAAM,GAAG,CAAC,CAAC;QAErF,KAAK,MAAM,MAAM,IAAI,UAAU,EAAE,CAAC;YAChC,IAAI,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC;gBACpE,MAAM,CAAC,OAAO,CAAC,+CAA+C,UAAU,8BAA8B,CAAC,CAAC;gBACxG,MAAM;YACR,CAAC;YAED,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAG,4BAA4B,CAAC,OAAO,CAAC,CAAC;YACvD,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAEhD,IAAI,eAAe,KAAK,QAAQ,EAAE,CAAC;gBACjC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACjC,SAAS;YACX,CAAC;YAED,IAAI,SAAS,GAAG,KAAK,CAAC;YACtB,IAAI,eAAe,KAAK,SAAS,IAAI,eAAe,KAAK,QAAQ,EAAE,CAAC;gBAClE,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;gBACtC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;oBACvB,MAAM,IAAI,KAAK,CACb,sCAAsC,MAAM,CAAC,IAAI,qEAAqE;wBACtH,qFAAqF,CACtF,CAAC;gBACJ,CAAC;gBACD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;oBACtB,MAAM,CAAC,OAAO,CAAC,wBAAwB,MAAM,CAAC,IAAI,2DAA2D,CAAC,CAAC;oBAC/G,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBACjC,SAAS;gBACX,CAAC;gBACD,SAAS,GAAG,IAAI,CAAC;gBACjB,MAAM,CAAC,OAAO,CAAC,wBAAwB,MAAM,CAAC,IAAI,iCAAiC,CAAC,CAAC;YACvF,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,UAAU,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;gBAC/C,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;gBACpE,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;oBACzD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;wBACnC,MAAM,CAAC,KAAK,CAAC,mCAAmC,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC,CAAC;oBAC/E,CAAC;oBACD,uFAAuF;oBACvF,SAAS;gBACX,CAAC;gBACD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;oBACnC,MAAM,SAAG,CAAC,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;gBACnE,CAAC;gBACD,MAAM,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;gBAC9D,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;gBAClC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACjC,MAAM,CAAC,IAAI,CAAC,gCAAgC,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,MAAM,cAAc,CAAC,CAAC;YAC/F,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC5D,MAAM,CAAC,KAAK,CAAC,8BAA8B,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;gBACtE,IAAI,WAAW,EAAE,CAAC;oBAChB,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAC,IAAI,cAAc,OAAO,EAAE,CAAC,CAAC;gBACzF,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CAAA;AAED,2GAA2G;AAC3G,MAAa,sBAAsB;IACjC,MAAM,CAAC,KAAK,CAAC,OAAuB;QAClC,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,OAAuB;QACxC,OAAO,yBAAyB,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;CACF;AARD,wDAQC","sourcesContent":["import { createHash } from 'crypto';\nimport { existsSync, readFileSync, readdirSync } from 'fs';\nimport { extname, join, relative, resolve, sep } from 'path';\nimport { Orm } from '../../Orm';\nimport { Logger } from '../../Logger';\nimport type { AccessiOptions, CatalogScriptChecksumPolicy, CatalogScriptsOptions } from '../AccessiModule';\n\nexport interface CatalogScriptMigration {\n name: string;\n applied: boolean;\n skipped: boolean;\n reapplied: boolean;\n error?: string;\n}\n\nexport interface CatalogMigrationReport {\n folder: string;\n discovered: number;\n applied: string[];\n skipped: string[];\n invalid: { script: string; violations: string[] }[];\n failed: { script: string; error: string }[];\n}\n\n/**\n * Le catalog migrations possono modificare SOLO righe (DML). Questa whitelist rende tassativo il\n * vincolo: qualunque altro statement (DDL, trigger, transazioni, GRANT, ...) viene rifiutato.\n */\nconst ALLOWED_STATEMENT_KEYWORDS: ReadonlySet<string> = new Set([\n 'INSERT', 'UPDATE', 'DELETE', 'MERGE', 'SELECT', 'EXECUTE',\n]);\n\n/** Estrae la prima parola chiave di uno statement, saltando spazi e commenti iniziali. */\nexport function leadingStatementKeyword(statement: string): string {\n let index = 0;\n while (index < statement.length) {\n const char = statement[index] as string;\n if (/\\s/.test(char)) { index += 1; continue; }\n if (char === '-' && statement[index + 1] === '-') {\n const newline = statement.indexOf('\\n', index);\n if (newline === -1) return '';\n index = newline + 1;\n continue;\n }\n if (char === '/' && statement[index + 1] === '*') {\n const end = statement.indexOf('*/', index + 2);\n if (end === -1) return '';\n index = end + 2;\n continue;\n }\n break;\n }\n const match = /^([A-Za-z]+)/.exec(statement.slice(index));\n return match ? (match[1] as string).toUpperCase() : '';\n}\n\n/**\n * Valida gli statement di una catalog migration: ritorna la lista delle violazioni (vuota se conforme).\n * Regola tassativa: solo DML. Nessuna modifica a colonne/schema/trigger/permessi.\n */\nexport function analyzeCatalogScript(statements: string[]): string[] {\n const violations: string[] = [];\n for (const statement of statements) {\n const keyword = leadingStatementKeyword(statement);\n if (!keyword) continue;\n if (!ALLOWED_STATEMENT_KEYWORDS.has(keyword)) {\n const preview = statement.replace(/\\s+/g, ' ').trim().slice(0, 120);\n violations.push(\n `Statement non consentito (${keyword}): le catalog migrations possono modificare solo righe (INSERT/UPDATE/DELETE/MERGE). Estratto: \"${preview}\"`,\n );\n }\n }\n return violations;\n}\n\n/** Ritorna la policy di checksum effettiva (default `error`). */\nfunction checksumPolicy(options: CatalogScriptsOptions): CatalogScriptChecksumPolicy {\n return options.onChecksumMismatch ?? 'error';\n}\n\n/** Hash SHA-256 del contenuto dello script, usato per rilevare modifiche non versionate. */\nexport function computeCatalogScriptChecksum(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/**\n * Divide un file SQL in statement eseguibili separatamente.\n *\n * Supporta:\n * - terminator personalizzati con `SET TERM <char>` / `SET TERM <char> ;`\n * - stringhe `'...'` con escape `''`\n * - commenti di riga `--` e di blocco `/* ... * /`\n *\n * Non interpreta la semantica SQL: e volutamente un tokenizer prudente che non spezza\n * mai all'interno di stringhe o commenti.\n */\nexport function splitSqlStatements(sql: string, defaultTerminator = ';'): string[] {\n const statements: string[] = [];\n const lines = sql.replace(/\\r\\n?/g, '\\n').split('\\n');\n let buffer = '';\n let terminator = defaultTerminator;\n let inString = false;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (const line of lines) {\n const setTerm = /^\\s*SET\\s+TERM\\s+(\\S+)/i.exec(line);\n if (setTerm && !inString && !inLineComment && !inBlockComment) {\n const raw = setTerm[1] ?? '';\n terminator = raw.length > 1 && raw.endsWith(';') ? raw.slice(0, -1) : raw || defaultTerminator;\n continue;\n }\n\n buffer += `${line}\\n`;\n\n let start = 0;\n let index = 0;\n while (index < buffer.length) {\n const char = buffer[index] as string;\n const next = buffer[index + 1];\n\n if (inLineComment) {\n if (char === '\\n') inLineComment = false;\n index += 1;\n continue;\n }\n if (inBlockComment) {\n if (char === '*' && next === '/') {\n inBlockComment = false;\n index += 2;\n continue;\n }\n index += 1;\n continue;\n }\n if (inString) {\n if (char === \"'\") {\n if (next === \"'\") {\n index += 2;\n continue;\n }\n inString = false;\n }\n index += 1;\n continue;\n }\n\n if (char === \"'\") {\n inString = true;\n index += 1;\n continue;\n }\n if (char === '-' && next === '-') {\n inLineComment = true;\n index += 2;\n continue;\n }\n if (char === '/' && next === '*') {\n inBlockComment = true;\n index += 2;\n continue;\n }\n if (buffer.startsWith(terminator, index)) {\n const statement = buffer.slice(start, index).trim();\n if (statement) statements.push(statement);\n index += terminator.length;\n start = index;\n continue;\n }\n index += 1;\n }\n\n buffer = buffer.slice(start);\n }\n\n const trailing = buffer.trim();\n if (trailing) statements.push(trailing);\n return statements;\n}\n\n/** Elenca gli script `.sql` della cartella, ordinati per percorso (prefissi numerici consigliati). */\nexport function discoverCatalogScripts(options: CatalogScriptsOptions): { name: string; path: string }[] {\n const folder = resolve(options.folder);\n if (!existsSync(folder)) {\n throw new Error(`AccessiCatalogMigrator: cartella non trovata: ${folder}`);\n }\n\n const include = options.include && options.include.length > 0 ? options.include : ['.sql'];\n const found: { name: string; path: string }[] = [];\n\n const walk = (directory: string): void => {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const absolute = join(directory, entry.name);\n if (entry.isDirectory()) {\n walk(absolute);\n continue;\n }\n if (!entry.isFile()) continue;\n const matches = include.some((pattern) =>\n pattern.startsWith('.') ? extname(entry.name).toLowerCase() === pattern.toLowerCase() : entry.name.includes(pattern),\n );\n if (!matches) continue;\n const name = relative(folder, absolute).split(sep).join('/');\n found.push({ name, path: absolute });\n }\n };\n\n walk(folder);\n return found.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction isLedgerPresent(options: AccessiOptions): Promise<boolean> {\n return Orm.query(\n options.databaseOptions,\n \"SELECT 1 FROM RDB$RELATIONS WHERE TRIM(RDB$RELATION_NAME) = 'ACCESSI_CATALOG_SCRIPT'\",\n [],\n false,\n ).then((rows) => rows.length > 0);\n}\n\n/** Legge il ledger come mappa `script -> checksum`. */\nasync function readLedger(options: AccessiOptions): Promise<Map<string, string>> {\n const rows = (await Orm.query(\n options.databaseOptions,\n 'SELECT SCRIPT_NAME AS NAME, CHECKSUM FROM ACCESSI_CATALOG_SCRIPT',\n [],\n false,\n )) as Array<Record<string, unknown>>;\n const ledger = new Map<string, string>();\n for (const row of rows) {\n const name = String(row.NAME ?? row.name ?? '').trim();\n const checksum = String(row.CHECKSUM ?? row.checksum ?? '').trim();\n if (name) ledger.set(name, checksum);\n }\n return ledger;\n}\n\nasync function upsertLedger(options: AccessiOptions, name: string, checksum: string, reapplied: boolean): Promise<void> {\n if (reapplied) {\n await Orm.execute(\n options.databaseOptions,\n 'UPDATE ACCESSI_CATALOG_SCRIPT SET CHECKSUM = ?, APPLIED_AT = CURRENT_TIMESTAMP, APPLIED_COUNT = APPLIED_COUNT + 1 WHERE SCRIPT_NAME = ?',\n [checksum, name],\n false,\n );\n return;\n }\n await Orm.execute(\n options.databaseOptions,\n 'UPDATE OR INSERT INTO ACCESSI_CATALOG_SCRIPT (SCRIPT_NAME, CHECKSUM, APPLIED_AT, APPLIED_COUNT) VALUES (?, ?, CURRENT_TIMESTAMP, 1) MATCHING (SCRIPT_NAME)',\n [name, checksum],\n false,\n );\n}\n\n/** Elenca gli script non ancora applicati (o con checksum diverso) senza eseguirli. */\nexport async function listPendingCatalogScripts(options: AccessiOptions): Promise<{ applied: string[]; pending: string[]; changed: string[]; invalid: { script: string; violations: string[] }[] }> {\n const config = options.catalogScripts;\n if (!config?.folder) throw new Error('AccessiCatalogMigrator: catalogScripts.folder non configurato.');\n if (!(await isLedgerPresent(options))) {\n throw new Error('AccessiCatalogMigrator: tabella ACCESSI_CATALOG_SCRIPT assente. Eseguire prima AccessiDatabaseUpdater.run (db:update:accessi).');\n }\n\n const allowDdl = config.allowDdl === true;\n const ledger = await readLedger(options);\n const discovered = discoverCatalogScripts(config);\n const pending: string[] = [];\n const changed: string[] = [];\n const invalid: { script: string; violations: string[] }[] = [];\n\n for (const script of discovered) {\n const content = readFileSync(script.path, 'utf8');\n const checksum = computeCatalogScriptChecksum(content);\n const violations = allowDdl ? [] : analyzeCatalogScript(splitSqlStatements(content));\n if (violations.length > 0) {\n invalid.push({ script: script.name, violations });\n continue;\n }\n const appliedChecksum = ledger.get(script.name);\n if (appliedChecksum === undefined) pending.push(script.name);\n else if (appliedChecksum !== checksum) changed.push(script.name);\n }\n\n return { applied: [...ledger.keys()].sort(), pending, changed, invalid };\n}\n\n/**\n * Applica le catalog migrations presenti nella cartella configurata.\n *\n * Idempotenza:\n * - uno script gia presente nel ledger con lo stesso checksum viene saltato;\n * - uno script gia applicato ma modificato segue `onChecksumMismatch` (`error` default, `warn`, `reapply`);\n * - un errore interrompe il run (default) senza avanzare, lasciando il ledger all'ultimo script completato.\n *\n * Il chiamante deve avere gia riconciliato lo schema (`AccessiDatabaseUpdater.run`): la tabella\n * ledger `ACCESSI_CATALOG_SCRIPT` e creata dall'updater.\n */\nexport async function applyCatalogScripts(options: AccessiOptions): Promise<CatalogMigrationReport> {\n const logger = new Logger(AccessiCatalogMigrator.name);\n const config = options.catalogScripts;\n if (!config?.folder) throw new Error('AccessiCatalogMigrator: catalogScripts.folder non configurato.');\n if (!(await isLedgerPresent(options))) {\n throw new Error('AccessiCatalogMigrator: tabella ACCESSI_CATALOG_SCRIPT assente. Eseguire prima AccessiDatabaseUpdater.run (db:update:accessi).');\n }\n\n const folder = resolve(config.folder);\n const discovered = discoverCatalogScripts(config);\n const ledger = await readLedger(options);\n const stopOnError = config.stopOnError !== false;\n const allowDdl = config.allowDdl === true;\n const maxScripts = Number.isInteger(config.maxScriptsPerRun) && (config.maxScriptsPerRun ?? 0) > 0 ? config.maxScriptsPerRun : undefined;\n const report: CatalogMigrationReport = { folder, discovered: discovered.length, applied: [], skipped: [], invalid: [], failed: [] };\n\n logger.info(`Catalog migrations: ${discovered.length} script trovati in ${folder}.`);\n\n for (const script of discovered) {\n if (maxScripts !== undefined && report.applied.length >= maxScripts) {\n logger.warning(`Catalog migrations: limite maxScriptsPerRun=${maxScripts} raggiunto, resto rimandato.`);\n break;\n }\n\n const content = readFileSync(script.path, 'utf8');\n const checksum = computeCatalogScriptChecksum(content);\n const appliedChecksum = ledger.get(script.name);\n\n if (appliedChecksum === checksum) {\n report.skipped.push(script.name);\n continue;\n }\n\n let reapplied = false;\n if (appliedChecksum !== undefined && appliedChecksum !== checksum) {\n const policy = checksumPolicy(config);\n if (policy === 'error') {\n throw new Error(\n `AccessiCatalogMigrator: lo script \"${script.name}\" e gia applicato con un checksum diverso (migrazioni immutabili). ` +\n `Ripristina il file o configura onChecksumMismatch='reapply'/'warn' consapevolmente.`,\n );\n }\n if (policy === 'warn') {\n logger.warning(`Catalog migrations: \"${script.name}\" applicato con checksum diverso, ignorato (policy warn).`);\n report.skipped.push(script.name);\n continue;\n }\n reapplied = true;\n logger.warning(`Catalog migrations: \"${script.name}\" riapplicato (policy reapply).`);\n }\n\n try {\n const statements = splitSqlStatements(content);\n const violations = allowDdl ? [] : analyzeCatalogScript(statements);\n if (violations.length > 0) {\n report.invalid.push({ script: script.name, violations });\n for (const violation of violations) {\n logger.error(`Catalog migration non conforme: ${script.name}. ${violation}`);\n }\n // Il file non viene applicato ne registrato nel ledger; il run prosegue con gli altri.\n continue;\n }\n for (const statement of statements) {\n await Orm.execute(options.databaseOptions, statement, [], false);\n }\n await upsertLedger(options, script.name, checksum, reapplied);\n ledger.set(script.name, checksum);\n report.applied.push(script.name);\n logger.info(`Catalog migration applicata: ${script.name} (${statements.length} statement).`);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n report.failed.push({ script: script.name, error: message });\n logger.error(`Catalog migration fallita: ${script.name}. ${message}`);\n if (stopOnError) {\n throw new Error(`AccessiCatalogMigrator: script \"${script.name}\" fallito. ${message}`);\n }\n }\n }\n\n return report;\n}\n\n/** Esegue la riconciliazione dello schema non e responsabilita di questa classe: usare l'updater prima. */\nexport class AccessiCatalogMigrator {\n static apply(options: AccessiOptions): Promise<CatalogMigrationReport> {\n return applyCatalogScripts(options);\n }\n\n static listPending(options: AccessiOptions): Promise<{ applied: string[]; pending: string[]; changed: string[]; invalid: { script: string; violations: string[] }[] }> {\n return listPendingCatalogScripts(options);\n }\n}\n"]}
|
|
@@ -33,17 +33,29 @@ function main() {
|
|
|
33
33
|
console.log(`[Accessi Catalog] Gia applicati: ${pending.applied.length}`);
|
|
34
34
|
console.log(`[Accessi Catalog] Da applicare: ${pending.pending.length}${pending.pending.length ? ` -> ${pending.pending.join(', ')}` : ''}`);
|
|
35
35
|
console.log(`[Accessi Catalog] Modificati (checksum diverso): ${pending.changed.length}${pending.changed.length ? ` -> ${pending.changed.join(', ')}` : ''}`);
|
|
36
|
+
console.log(`[Accessi Catalog] Non conformi (solo DML): ${pending.invalid.length}`);
|
|
37
|
+
for (const entry of pending.invalid) {
|
|
38
|
+
for (const violation of entry.violations)
|
|
39
|
+
console.error(`[Accessi Catalog] Non conforme: ${entry.script} -> ${violation}`);
|
|
40
|
+
}
|
|
41
|
+
if (pending.invalid.length)
|
|
42
|
+
process.exitCode = 1;
|
|
36
43
|
return;
|
|
37
44
|
}
|
|
38
45
|
const report = yield (0, AccessiCatalogMigrator_1.applyCatalogScripts)(options);
|
|
39
|
-
console.log(`[Accessi Catalog] Scoperti: ${report.discovered} | Applicati: ${report.applied.length} | Saltati: ${report.skipped.length} | Falliti: ${report.failed.length}`);
|
|
46
|
+
console.log(`[Accessi Catalog] Scoperti: ${report.discovered} | Applicati: ${report.applied.length} | Saltati: ${report.skipped.length} | Non conformi: ${report.invalid.length} | Falliti: ${report.failed.length}`);
|
|
40
47
|
if (report.applied.length)
|
|
41
48
|
console.log(`[Accessi Catalog] Applicati: ${report.applied.join(', ')}`);
|
|
49
|
+
for (const entry of report.invalid) {
|
|
50
|
+
for (const violation of entry.violations)
|
|
51
|
+
console.error(`[Accessi Catalog] Non conforme: ${entry.script} -> ${violation}`);
|
|
52
|
+
}
|
|
42
53
|
if (report.failed.length) {
|
|
43
54
|
for (const failure of report.failed)
|
|
44
55
|
console.error(`[Accessi Catalog] Fallito: ${failure.script} -> ${failure.error}`);
|
|
45
|
-
process.exitCode = 1;
|
|
46
56
|
}
|
|
57
|
+
if (report.failed.length || report.invalid.length)
|
|
58
|
+
process.exitCode = 1;
|
|
47
59
|
});
|
|
48
60
|
}
|
|
49
61
|
main()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runAccessiCatalogMigrations.js","sourceRoot":"","sources":["../../../src/accessi-module/database-updates/runAccessiCatalogMigrations.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,qEAAkE;AAClE,qEAA0F;AAC1F,mEAAsE;AACtE,mCAAgC;AAEhC,SAAe,IAAI;;;QACjB,MAAM,OAAO,GAAG,IAAA,mDAA2B,GAAE,CAAC;QAC9C,IAAI,CAAC,CAAA,MAAA,OAAO,CAAC,cAAc,0CAAE,MAAM,CAAA,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,0FAA0F,CAAC,CAAC;QAC9G,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,6BAA6B,OAAO,CAAC,eAAe,CAAC,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC,IAAI,OAAO,OAAO,CAAC,eAAe,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChJ,OAAO,CAAC,GAAG,CAAC,+BAA+B,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;QAE5E,qEAAqE;QACrE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;YAC3D,MAAM,+CAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,MAAM,IAAA,kDAAyB,EAAC,OAAO,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,oCAAoC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAC1E,OAAO,CAAC,GAAG,CAAC,mCAAmC,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC7I,OAAO,CAAC,GAAG,CAAC,oDAAoD,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9J,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAA,4CAAmB,EAAC,OAAO,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,+BAA+B,MAAM,CAAC,UAAU,iBAAiB,MAAM,CAAC,OAAO,CAAC,MAAM,eAAe,MAAM,CAAC,OAAO,CAAC,MAAM,eAAe,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"runAccessiCatalogMigrations.js","sourceRoot":"","sources":["../../../src/accessi-module/database-updates/runAccessiCatalogMigrations.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccessiDatabaseUpdater } from \"./AccessiDatabaseUpdater\";\nimport { applyCatalogScripts, listPendingCatalogScripts } from \"./AccessiCatalogMigrator\";\nimport { createAccessiOptionsFromEnv } from \"./accessiOptionsFromEnv\";\nimport { Orm } from \"../../Orm\";\n\nasync function main(): Promise<void> {\n const options = createAccessiOptionsFromEnv();\n if (!options.catalogScripts?.folder) {\n throw new Error(\"Variabile ambiente mancante: ACCESSI_CATALOG_FOLDER (cartella delle catalog migrations).\");\n }\n\n const checkOnly = process.argv.includes('--check');\n console.log(`[Accessi Catalog] Target: ${options.databaseOptions.host}:${options.databaseOptions.port} -> ${options.databaseOptions.database}`);\n console.log(`[Accessi Catalog] Cartella: ${options.catalogScripts.folder}`);\n\n // Prima lo schema si adegua, poi si eseguono gli script di catalogo.\n if (!checkOnly) {\n console.log('[Accessi Catalog] Riconciliazione schema...');\n await AccessiDatabaseUpdater.run(options);\n }\n\n if (checkOnly) {\n const pending = await listPendingCatalogScripts(options);\n console.log(`[Accessi Catalog] Gia applicati: ${pending.applied.length}`);\n console.log(`[Accessi Catalog] Da applicare: ${pending.pending.length}${pending.pending.length ? ` -> ${pending.pending.join(', ')}` : ''}`);\n console.log(`[Accessi Catalog] Modificati (checksum diverso): ${pending.changed.length}${pending.changed.length ? ` -> ${pending.changed.join(', ')}` : ''}`);\n console.log(`[Accessi Catalog] Non conformi (solo DML): ${pending.invalid.length}`);\n for (const entry of pending.invalid) {\n for (const violation of entry.violations) console.error(`[Accessi Catalog] Non conforme: ${entry.script} -> ${violation}`);\n }\n if (pending.invalid.length) process.exitCode = 1;\n return;\n }\n\n const report = await applyCatalogScripts(options);\n console.log(`[Accessi Catalog] Scoperti: ${report.discovered} | Applicati: ${report.applied.length} | Saltati: ${report.skipped.length} | Non conformi: ${report.invalid.length} | Falliti: ${report.failed.length}`);\n if (report.applied.length) console.log(`[Accessi Catalog] Applicati: ${report.applied.join(', ')}`);\n for (const entry of report.invalid) {\n for (const violation of entry.violations) console.error(`[Accessi Catalog] Non conforme: ${entry.script} -> ${violation}`);\n }\n if (report.failed.length) {\n for (const failure of report.failed) console.error(`[Accessi Catalog] Fallito: ${failure.script} -> ${failure.error}`);\n }\n if (report.failed.length || report.invalid.length) process.exitCode = 1;\n}\n\nmain()\n .then(() => Orm.closePools())\n .then(() => process.exit(process.exitCode ?? 0))\n .catch(async (error) => {\n console.error(\"[Accessi Catalog] Errore durante l'esecuzione:\", error);\n await Orm.closePools().catch(() => undefined);\n process.exit(1);\n });\n"]}
|
|
@@ -17,10 +17,12 @@ export { AccessiDatabaseUpdater } from "./database-updates/AccessiDatabaseUpdate
|
|
|
17
17
|
export type { AccessiOptions, EmailOptions, JwtOptions, ExtensionFieldsOptions, PublicAuthRateLimitOptions, PublicAuthRateLimitRuleOptions } from "./AccessiModule";
|
|
18
18
|
export type { PublicRegistrationOptions, FederatedAuthenticationOptions, ServiceTokenOptions } from "./AccessiModule";
|
|
19
19
|
export type { CatalogScriptsOptions, CatalogScriptChecksumPolicy } from "./AccessiModule";
|
|
20
|
-
export { AccessiCatalogMigrator, applyCatalogScripts, listPendingCatalogScripts, splitSqlStatements, computeCatalogScriptChecksum, discoverCatalogScripts } from "./database-updates/AccessiCatalogMigrator";
|
|
20
|
+
export { AccessiCatalogMigrator, applyCatalogScripts, listPendingCatalogScripts, splitSqlStatements, analyzeCatalogScript, leadingStatementKeyword, computeCatalogScriptChecksum, discoverCatalogScripts } from "./database-updates/AccessiCatalogMigrator";
|
|
21
21
|
export type { CatalogMigrationReport, CatalogScriptMigration } from "./database-updates/AccessiCatalogMigrator";
|
|
22
22
|
export { ServiceTokenService } from './Services/ServiceTokenService/ServiceTokenService';
|
|
23
23
|
export type { ServiceTokenMetadata, IssuedServiceToken, VerifiedServiceToken, IssueServiceTokenInput } from './Services/ServiceTokenService/ServiceTokenService';
|
|
24
|
+
export { SchemaExportService } from './Services/SchemaExportService/SchemaExportService';
|
|
25
|
+
export type { SchemaDdlResult, SchemaDdlSection, SchemaEntitiesResult } from './Services/SchemaExportService/SchemaExportService';
|
|
24
26
|
export { ServiceTokenGuard, RequireServiceTokenScopes, getAccessiServiceToken } from './security/serviceTokenGuard';
|
|
25
27
|
export { assertEmailConfigured, isEmailConfigured, AccessiEmailNotConfiguredError, ACCESSI_EMAIL_NOT_CONFIGURED } from './security/emailConfiguration';
|
|
26
28
|
export { FederatedAuthService } from './federated-auth/FederatedAuthService';
|
|
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = exports.getAccessiServiceToken = exports.RequireServiceTokenScopes = exports.ServiceTokenGuard = exports.ServiceTokenService = exports.discoverCatalogScripts = exports.computeCatalogScriptChecksum = exports.splitSqlStatements = exports.listPendingCatalogScripts = exports.applyCatalogScripts = exports.AccessiCatalogMigrator = exports.AccessiDatabaseUpdater = exports.AccessiModule = void 0;
|
|
29
|
+
exports.ACCESSI_MODULE_SERVICES_LOCALS_KEY = exports.getAccessiModuleServices = exports.registerAccessiModuleServices = exports.accessiRequirement = exports.authenticateGen = exports.authorizeAccessi = exports.FederatedAuthService = exports.ACCESSI_EMAIL_NOT_CONFIGURED = exports.AccessiEmailNotConfiguredError = exports.isEmailConfigured = exports.assertEmailConfigured = exports.getAccessiServiceToken = exports.RequireServiceTokenScopes = exports.ServiceTokenGuard = exports.SchemaExportService = exports.ServiceTokenService = exports.discoverCatalogScripts = exports.computeCatalogScriptChecksum = exports.leadingStatementKeyword = exports.analyzeCatalogScript = exports.splitSqlStatements = exports.listPendingCatalogScripts = exports.applyCatalogScripts = exports.AccessiCatalogMigrator = exports.AccessiDatabaseUpdater = exports.AccessiModule = void 0;
|
|
30
30
|
exports.initializeAccessiModule = initializeAccessiModule;
|
|
31
31
|
const express_1 = __importDefault(require("express"));
|
|
32
32
|
const core_1 = require("@nestjs/core");
|
|
@@ -130,10 +130,14 @@ Object.defineProperty(exports, "AccessiCatalogMigrator", { enumerable: true, get
|
|
|
130
130
|
Object.defineProperty(exports, "applyCatalogScripts", { enumerable: true, get: function () { return AccessiCatalogMigrator_1.applyCatalogScripts; } });
|
|
131
131
|
Object.defineProperty(exports, "listPendingCatalogScripts", { enumerable: true, get: function () { return AccessiCatalogMigrator_1.listPendingCatalogScripts; } });
|
|
132
132
|
Object.defineProperty(exports, "splitSqlStatements", { enumerable: true, get: function () { return AccessiCatalogMigrator_1.splitSqlStatements; } });
|
|
133
|
+
Object.defineProperty(exports, "analyzeCatalogScript", { enumerable: true, get: function () { return AccessiCatalogMigrator_1.analyzeCatalogScript; } });
|
|
134
|
+
Object.defineProperty(exports, "leadingStatementKeyword", { enumerable: true, get: function () { return AccessiCatalogMigrator_1.leadingStatementKeyword; } });
|
|
133
135
|
Object.defineProperty(exports, "computeCatalogScriptChecksum", { enumerable: true, get: function () { return AccessiCatalogMigrator_1.computeCatalogScriptChecksum; } });
|
|
134
136
|
Object.defineProperty(exports, "discoverCatalogScripts", { enumerable: true, get: function () { return AccessiCatalogMigrator_1.discoverCatalogScripts; } });
|
|
135
137
|
var ServiceTokenService_1 = require("./Services/ServiceTokenService/ServiceTokenService");
|
|
136
138
|
Object.defineProperty(exports, "ServiceTokenService", { enumerable: true, get: function () { return ServiceTokenService_1.ServiceTokenService; } });
|
|
139
|
+
var SchemaExportService_1 = require("./Services/SchemaExportService/SchemaExportService");
|
|
140
|
+
Object.defineProperty(exports, "SchemaExportService", { enumerable: true, get: function () { return SchemaExportService_1.SchemaExportService; } });
|
|
137
141
|
var serviceTokenGuard_1 = require("./security/serviceTokenGuard");
|
|
138
142
|
Object.defineProperty(exports, "ServiceTokenGuard", { enumerable: true, get: function () { return serviceTokenGuard_1.ServiceTokenGuard; } });
|
|
139
143
|
Object.defineProperty(exports, "RequireServiceTokenScopes", { enumerable: true, get: function () { return serviceTokenGuard_1.RequireServiceTokenScopes; } });
|