@nodefony/drizzle 10.0.0-alpha.1
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/LICENSE +544 -0
- package/README.md +162 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
- package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
- package/dist/index.js +105 -0
- package/dist/nodefony/command/migrateShared.js +247 -0
- package/dist/nodefony/command/orm-generate.js +356 -0
- package/dist/nodefony/command/orm-migrate-baseline.js +208 -0
- package/dist/nodefony/command/orm-migrate-repair.js +114 -0
- package/dist/nodefony/command/orm-migrate-status.js +67 -0
- package/dist/nodefony/command/orm-migrate.js +141 -0
- package/dist/nodefony/command/orm-reset.js +166 -0
- package/dist/nodefony/config/config.js +107 -0
- package/dist/nodefony/config/defineModuleConfig.js +63 -0
- package/dist/nodefony/entity/auditEventEntity.js +93 -0
- package/dist/nodefony/entity/colKit.js +260 -0
- package/dist/nodefony/entity/idempotencyEntity.js +74 -0
- package/dist/nodefony/entity/sessionEntity.js +75 -0
- package/dist/nodefony/entity/tokenEntity.js +198 -0
- package/dist/nodefony/entity/totpSecretEntity.js +98 -0
- package/dist/nodefony/entity/userTable.js +141 -0
- package/dist/nodefony/entity/webAuthnCredentialEntity.js +114 -0
- package/dist/nodefony/entity/webhookEndpointEntity.js +106 -0
- package/dist/nodefony/interfaces/IDrizzleConfig.js +1 -0
- package/dist/nodefony/interfaces/index.js +1 -0
- package/dist/nodefony/migrations-schema/mysql.js +48 -0
- package/dist/nodefony/migrations-schema/postgres.js +48 -0
- package/dist/nodefony/migrations-schema/sqlite.js +48 -0
- package/dist/nodefony/registerStores.js +218 -0
- package/dist/nodefony/service/DrizzleService.js +282 -0
- package/dist/nodefony/src/DrizzleAuditStore.js +203 -0
- package/dist/nodefony/src/DrizzleIdempotencyStore.js +278 -0
- package/dist/nodefony/src/DrizzleTokenStore.js +244 -0
- package/dist/nodefony/src/DrizzleTotpSecretStore.js +151 -0
- package/dist/nodefony/src/DrizzleUserRepository.js +217 -0
- package/dist/nodefony/src/DrizzleWebAuthnCredentialStore.js +159 -0
- package/dist/nodefony/src/DrizzleWebhookStore.js +169 -0
- package/dist/nodefony/src/SessionStorage.js +259 -0
- package/dist/nodefony/src/connectorTarget.js +59 -0
- package/dist/nodefony/src/likeSql.js +50 -0
- package/dist/nodefony/src/migrator/DrizzleMigrator.js +775 -0
- package/dist/nodefony/src/migrator/adopt.js +553 -0
- package/dist/nodefony/src/migrator/appSchema.js +414 -0
- package/dist/nodefony/src/migrator/catalog.js +76 -0
- package/dist/nodefony/src/migrator/destructive.js +213 -0
- package/dist/nodefony/src/migrator/divergence.js +84 -0
- package/dist/nodefony/src/migrator/drivers/index.js +39 -0
- package/dist/nodefony/src/migrator/drivers/mysqlDriver.js +147 -0
- package/dist/nodefony/src/migrator/drivers/postgresDriver.js +151 -0
- package/dist/nodefony/src/migrator/drivers/sqliteDriver.js +121 -0
- package/dist/nodefony/src/migrator/explain.js +565 -0
- package/dist/nodefony/src/migrator/hash.js +47 -0
- package/dist/nodefony/src/migrator/history.js +219 -0
- package/dist/nodefony/src/migrator/index.js +16 -0
- package/dist/nodefony/src/migrator/kit.js +296 -0
- package/dist/nodefony/src/migrator/name.js +68 -0
- package/dist/nodefony/src/migrator/paths.js +88 -0
- package/dist/nodefony/src/migrator/refusals.js +143 -0
- package/dist/nodefony/src/migrator/resolve.js +281 -0
- package/dist/nodefony/src/migrator/schemaDiff.js +86 -0
- package/dist/nodefony/src/migrator/sources.js +419 -0
- package/dist/nodefony/src/migrator/status.js +231 -0
- package/dist/nodefony/src/migrator/types.js +91 -0
- package/dist/nodefony/src/orm-core/DrizzleOrm.js +1154 -0
- package/dist/nodefony/src/orm-core/DrizzleRepository.js +610 -0
- package/dist/nodefony/src/orm-core/DrizzleTransaction.js +106 -0
- package/dist/nodefony/src/orm-core/index.js +4 -0
- package/dist/nodefony/src/queryKit.js +318 -0
- package/dist/nodefony/src/safeTarget.js +55 -0
- package/dist/types/index.d.ts +76 -0
- package/dist/types/nodefony/command/migrateShared.d.ts +137 -0
- package/dist/types/nodefony/command/orm-generate.d.ts +53 -0
- package/dist/types/nodefony/command/orm-migrate-baseline.d.ts +87 -0
- package/dist/types/nodefony/command/orm-migrate-repair.d.ts +66 -0
- package/dist/types/nodefony/command/orm-migrate-status.d.ts +38 -0
- package/dist/types/nodefony/command/orm-migrate.d.ts +65 -0
- package/dist/types/nodefony/command/orm-reset.d.ts +55 -0
- package/dist/types/nodefony/config/config.d.ts +110 -0
- package/dist/types/nodefony/config/defineModuleConfig.d.ts +24 -0
- package/dist/types/nodefony/entity/auditEventEntity.d.ts +56 -0
- package/dist/types/nodefony/entity/colKit.d.ts +130 -0
- package/dist/types/nodefony/entity/idempotencyEntity.d.ts +52 -0
- package/dist/types/nodefony/entity/sessionEntity.d.ts +50 -0
- package/dist/types/nodefony/entity/tokenEntity.d.ts +53 -0
- package/dist/types/nodefony/entity/totpSecretEntity.d.ts +61 -0
- package/dist/types/nodefony/entity/userTable.d.ts +65 -0
- package/dist/types/nodefony/entity/webAuthnCredentialEntity.d.ts +57 -0
- package/dist/types/nodefony/entity/webhookEndpointEntity.d.ts +58 -0
- package/dist/types/nodefony/interfaces/IDrizzleConfig.d.ts +17 -0
- package/dist/types/nodefony/interfaces/index.d.ts +1 -0
- package/dist/types/nodefony/migrations-schema/mysql.d.ts +9 -0
- package/dist/types/nodefony/migrations-schema/postgres.d.ts +9 -0
- package/dist/types/nodefony/migrations-schema/sqlite.d.ts +9 -0
- package/dist/types/nodefony/registerStores.d.ts +52 -0
- package/dist/types/nodefony/service/DrizzleService.d.ts +27 -0
- package/dist/types/nodefony/src/DrizzleAuditStore.d.ts +65 -0
- package/dist/types/nodefony/src/DrizzleIdempotencyStore.d.ts +129 -0
- package/dist/types/nodefony/src/DrizzleTokenStore.d.ts +146 -0
- package/dist/types/nodefony/src/DrizzleTotpSecretStore.d.ts +60 -0
- package/dist/types/nodefony/src/DrizzleUserRepository.d.ts +67 -0
- package/dist/types/nodefony/src/DrizzleWebAuthnCredentialStore.d.ts +62 -0
- package/dist/types/nodefony/src/DrizzleWebhookStore.d.ts +79 -0
- package/dist/types/nodefony/src/SessionStorage.d.ts +72 -0
- package/dist/types/nodefony/src/connectorTarget.d.ts +48 -0
- package/dist/types/nodefony/src/likeSql.d.ts +29 -0
- package/dist/types/nodefony/src/migrator/DrizzleMigrator.d.ts +94 -0
- package/dist/types/nodefony/src/migrator/adopt.d.ts +280 -0
- package/dist/types/nodefony/src/migrator/appSchema.d.ts +223 -0
- package/dist/types/nodefony/src/migrator/catalog.d.ts +100 -0
- package/dist/types/nodefony/src/migrator/destructive.d.ts +123 -0
- package/dist/types/nodefony/src/migrator/divergence.d.ts +61 -0
- package/dist/types/nodefony/src/migrator/drivers/index.d.ts +26 -0
- package/dist/types/nodefony/src/migrator/drivers/mysqlDriver.d.ts +83 -0
- package/dist/types/nodefony/src/migrator/drivers/postgresDriver.d.ts +81 -0
- package/dist/types/nodefony/src/migrator/drivers/sqliteDriver.d.ts +53 -0
- package/dist/types/nodefony/src/migrator/explain.d.ts +424 -0
- package/dist/types/nodefony/src/migrator/hash.d.ts +39 -0
- package/dist/types/nodefony/src/migrator/history.d.ts +139 -0
- package/dist/types/nodefony/src/migrator/index.d.ts +20 -0
- package/dist/types/nodefony/src/migrator/kit.d.ts +141 -0
- package/dist/types/nodefony/src/migrator/name.d.ts +52 -0
- package/dist/types/nodefony/src/migrator/paths.d.ts +54 -0
- package/dist/types/nodefony/src/migrator/refusals.d.ts +170 -0
- package/dist/types/nodefony/src/migrator/resolve.d.ts +201 -0
- package/dist/types/nodefony/src/migrator/schemaDiff.d.ts +112 -0
- package/dist/types/nodefony/src/migrator/sources.d.ts +119 -0
- package/dist/types/nodefony/src/migrator/status.d.ts +132 -0
- package/dist/types/nodefony/src/migrator/types.d.ts +273 -0
- package/dist/types/nodefony/src/orm-core/DrizzleOrm.d.ts +241 -0
- package/dist/types/nodefony/src/orm-core/DrizzleRepository.d.ts +98 -0
- package/dist/types/nodefony/src/orm-core/DrizzleTransaction.d.ts +71 -0
- package/dist/types/nodefony/src/orm-core/index.d.ts +11 -0
- package/dist/types/nodefony/src/queryKit.d.ts +136 -0
- package/dist/types/nodefony/src/safeTarget.d.ts +42 -0
- package/docs/index.md +954 -0
- package/docs/migrations.md +691 -0
- package/migrations/mysql/0000_framework_init.sql +137 -0
- package/migrations/mysql/meta/_journal.json +13 -0
- package/migrations/postgres/0000_framework_init.sql +128 -0
- package/migrations/postgres/meta/_journal.json +13 -0
- package/migrations/sqlite/0000_framework_init.sql +127 -0
- package/migrations/sqlite/meta/_journal.json +13 -0
- package/package.json +126 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorate.js
|
|
2
|
+
function __decorate(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
|
+
//#endregion
|
|
9
|
+
export { __decorate as default };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorateMetadata.js
|
|
2
|
+
function __decorateMetadata(k, v) {
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4
|
+
}
|
|
5
|
+
//#endregion
|
|
6
|
+
export { __decorateMetadata as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import config, { DDL_MODES, DIVERGENCE_MODES, MIGRATION_CHECK_MODES, drizzleConfigSchema } from "./nodefony/config/config.js";
|
|
2
|
+
import { defineDrizzleConfig, drizzleConfigJsonSchema } from "./nodefony/config/defineModuleConfig.js";
|
|
3
|
+
import { FORMAT_MARKER, HISTORY_TABLE, MIGRATE_URL_ENV, MigrationVerdictError } from "./nodefony/src/migrator/types.js";
|
|
4
|
+
import { EXIT, MIGRATION_FORMAT_VERSION, action, buildReport, exitCodeOf, meaningOf, renderRefusal, renderStatus, styleFor, verdictOf } from "./nodefony/src/migrator/explain.js";
|
|
5
|
+
import { MYSQL_LOCK_NAME_SQL } from "./nodefony/src/migrator/drivers/mysqlDriver.js";
|
|
6
|
+
import { PG_LOCK_KEY } from "./nodefony/src/migrator/drivers/postgresDriver.js";
|
|
7
|
+
import { openMigrationDriver } from "./nodefony/src/migrator/drivers/index.js";
|
|
8
|
+
import { APP_RANK, APP_SOURCE, FRAMEWORK_RANK, FRAMEWORK_SOURCE, defaultMigrationSources, frameworkMigrationsDir } from "./nodefony/src/migrator/paths.js";
|
|
9
|
+
import { migrationHash } from "./nodefony/src/migrator/hash.js";
|
|
10
|
+
import { loadSources, orderSources } from "./nodefony/src/migrator/sources.js";
|
|
11
|
+
import { DEFAULT_LOCK_TIMEOUT_MS, DrizzleMigrator } from "./nodefony/src/migrator/DrizzleMigrator.js";
|
|
12
|
+
import { appMigrationsDir, buildMigrator, knownConnectors, readMigrationEnv, resetAllowed, resolveCheckMode, resolveConnector, resolveDdlMode, resolveDivergenceMode } from "./nodefony/src/migrator/resolve.js";
|
|
13
|
+
import { DrizzleRepository } from "./nodefony/src/orm-core/DrizzleRepository.js";
|
|
14
|
+
import { DrizzleTransaction } from "./nodefony/src/orm-core/DrizzleTransaction.js";
|
|
15
|
+
import { DrizzleOrm } from "./nodefony/src/orm-core/DrizzleOrm.js";
|
|
16
|
+
import "./nodefony/src/orm-core/index.js";
|
|
17
|
+
import DrizzleService from "./nodefony/service/DrizzleService.js";
|
|
18
|
+
import { TOKEN_ENTITY_NAMES, accessTokenTable, createAccessTokenTable, createDeniedJtiTable, createSubjectRevocationTable, createTokenEntities, deniedJtiTable, registerTokenEntities, subjectRevocationTable } from "./nodefony/entity/tokenEntity.js";
|
|
19
|
+
import { AUDIT_ENTITY_NAMES, auditEventTable, createAuditEntities, createAuditEventTable, registerAuditEntities } from "./nodefony/entity/auditEventEntity.js";
|
|
20
|
+
import { WEBAUTHN_CREDENTIAL_ENTITY, createWebAuthnCredentialEntity, createWebAuthnCredentialTable, registerWebAuthnCredentialEntity, webAuthnCredentialTable } from "./nodefony/entity/webAuthnCredentialEntity.js";
|
|
21
|
+
import { TOTP_SECRET_ENTITY, createTotpSecretEntity, createTotpSecretTable, registerTotpSecretEntity, totpSecretTable } from "./nodefony/entity/totpSecretEntity.js";
|
|
22
|
+
import { WEBHOOK_ENDPOINT_ENTITY, createWebhookEndpointEntity, createWebhookEndpointTable, registerWebhookEndpointEntity, webhookEndpointTable } from "./nodefony/entity/webhookEndpointEntity.js";
|
|
23
|
+
import { IDEMPOTENCY_ENTITY_NAME, createIdempotencyEntities, createIdempotencyTable, idempotencyKeyTable, registerIdempotencyEntities } from "./nodefony/entity/idempotencyEntity.js";
|
|
24
|
+
import { SESSION_CONNECTOR, SESSION_ENTITY_NAME, createSessionEntity, createSessionTable, registerSessionEntity, sessionTable } from "./nodefony/entity/sessionEntity.js";
|
|
25
|
+
import { createUserEntity, createUserTable, registerUserEntity, userTable } from "./nodefony/entity/userTable.js";
|
|
26
|
+
import { DrizzleTokenStore } from "./nodefony/src/DrizzleTokenStore.js";
|
|
27
|
+
import { DrizzleAuditStore } from "./nodefony/src/DrizzleAuditStore.js";
|
|
28
|
+
import { DrizzleWebAuthnCredentialStore } from "./nodefony/src/DrizzleWebAuthnCredentialStore.js";
|
|
29
|
+
import { DrizzleTotpSecretStore } from "./nodefony/src/DrizzleTotpSecretStore.js";
|
|
30
|
+
import { DrizzleWebhookStore } from "./nodefony/src/DrizzleWebhookStore.js";
|
|
31
|
+
import { DrizzleIdempotencyStore } from "./nodefony/src/DrizzleIdempotencyStore.js";
|
|
32
|
+
import { FRAMEWORK_CONNECTOR, isFrameworkFallbackEntity, registerDrizzleFrameworkStores } from "./nodefony/registerStores.js";
|
|
33
|
+
import OrmGenerate from "./nodefony/command/orm-generate.js";
|
|
34
|
+
import OrmMigrate from "./nodefony/command/orm-migrate.js";
|
|
35
|
+
import OrmMigrateStatus from "./nodefony/command/orm-migrate-status.js";
|
|
36
|
+
import OrmMigrateBaseline from "./nodefony/command/orm-migrate-baseline.js";
|
|
37
|
+
import OrmMigrateRepair from "./nodefony/command/orm-migrate-repair.js";
|
|
38
|
+
import OrmReset from "./nodefony/command/orm-reset.js";
|
|
39
|
+
import __decorateMetadata from "./_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
|
|
40
|
+
import __decorate from "./_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
|
|
41
|
+
import SessionStorage from "./nodefony/src/SessionStorage.js";
|
|
42
|
+
import "./nodefony/src/migrator/index.js";
|
|
43
|
+
import { DrizzleUserRepository } from "./nodefony/src/DrizzleUserRepository.js";
|
|
44
|
+
import { Kernel, Module, services } from "nodefony";
|
|
45
|
+
import { wireOrmAdminPlane } from "@nodefony/orm-core";
|
|
46
|
+
import { registerUserStore } from "@nodefony/user";
|
|
47
|
+
//#region index.ts
|
|
48
|
+
/**
|
|
49
|
+
* `@nodefony/drizzle` — module Drizzle ORM (driver `better-sqlite3`) sur
|
|
50
|
+
* `@nodefony/orm-core`.
|
|
51
|
+
*
|
|
52
|
+
* **Module bootable** : enregistré dans `@modules()`, son {@link DrizzleService}
|
|
53
|
+
* connecte au boot un {@link DrizzleOrm} par connecteur configuré (ORM par défaut
|
|
54
|
+
* SQL recommandé). Expose aussi les **classes adapter** (orm-core) pour un usage
|
|
55
|
+
* direct/banc-test. driver concret du socle multi-ORM (avec Mongoose) ; type-safe-first (a figé la forme des opérateurs riches, ADR-0003 #3).
|
|
56
|
+
*/
|
|
57
|
+
let Drizzle = class Drizzle extends Module {
|
|
58
|
+
constructor(kernel) {
|
|
59
|
+
super("drizzle", kernel, import.meta.url, config);
|
|
60
|
+
this.addCommand(OrmGenerate);
|
|
61
|
+
this.addCommand(OrmMigrate);
|
|
62
|
+
this.addCommand(OrmMigrateStatus);
|
|
63
|
+
this.addCommand(OrmMigrateBaseline);
|
|
64
|
+
this.addCommand(OrmMigrateRepair);
|
|
65
|
+
this.addCommand(OrmReset);
|
|
66
|
+
}
|
|
67
|
+
/** JSON Schema de la config drizzle → data plane admin (config riche Studio). */
|
|
68
|
+
configSchema() {
|
|
69
|
+
return drizzleConfigJsonSchema();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Valide la config (défauts + `module.options` + surcharge env) au boot via
|
|
73
|
+
* `defineDrizzleConfig`, et l'expose au container sous `drizzleConfig` pour que
|
|
74
|
+
* le `DrizzleService` la consomme. Plante propre si la config est invalide
|
|
75
|
+
* (convention Zod, alignée sur `@nodefony/mongoose` — audit config ORM 2026-06).
|
|
76
|
+
*/
|
|
77
|
+
async onKernelRegister() {
|
|
78
|
+
const validated = defineDrizzleConfig(this.options ?? {});
|
|
79
|
+
this.options = validated;
|
|
80
|
+
registerUserStore("drizzle");
|
|
81
|
+
if (validated.frameworkEntities !== false) {
|
|
82
|
+
const dialect = validated.connectors?.default?.dialect ?? "sqlite";
|
|
83
|
+
const report = registerDrizzleFrameworkStores(dialect);
|
|
84
|
+
if (report.unported.length) this.log(`schéma framework : entités non portées sur "${dialect}" → stores drizzle indisponibles pour [${report.unported.join(", ")}] (chantier multi-dialecte Ph.2.1)`, "WARNING");
|
|
85
|
+
if (report.appOwned.length) this.log(`schéma framework : entités déjà enregistrées par l'app [${report.appOwned.join(", ")}] — auto-register respecte l'app`, "DEBUG");
|
|
86
|
+
if (report.registered.length) this.log(`schéma framework déclaré sur "${FRAMEWORK_CONNECTOR}" (${dialect}) : [${report.registered.join(", ")}]`, "DEBUG");
|
|
87
|
+
}
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Monte le data plane ORM (`/nodefony/orm/api/*` + providers santé/flux pour la
|
|
92
|
+
* sonde cluster et le drill Studio) via {@link wireOrmAdminPlane}. Branchement
|
|
93
|
+
* GLOBAL (couvre tous les ORM) et idempotent — factorisé en orm-core (C5), chaque
|
|
94
|
+
* driver l'invoque à l'identique. orm-core étant une lib pure, c'est un module
|
|
95
|
+
* driver qui le déclenche (avant le `mountAll` de framework à `onKernelReady`).
|
|
96
|
+
*/
|
|
97
|
+
async onKernelBoot() {
|
|
98
|
+
wireOrmAdminPlane(this.kernel);
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
Drizzle = __decorate([services([DrizzleService]), __decorateMetadata("design:paramtypes", [typeof Kernel === "undefined" ? Object : Kernel])], Drizzle);
|
|
103
|
+
var drizzle_default = Drizzle;
|
|
104
|
+
//#endregion
|
|
105
|
+
export { APP_RANK, APP_SOURCE, AUDIT_ENTITY_NAMES, DDL_MODES, DEFAULT_LOCK_TIMEOUT_MS, DIVERGENCE_MODES, DrizzleAuditStore, DrizzleIdempotencyStore, DrizzleMigrator, DrizzleOrm, DrizzleRepository, DrizzleService, DrizzleTokenStore, DrizzleTotpSecretStore, DrizzleTransaction, DrizzleUserRepository, DrizzleWebAuthnCredentialStore, DrizzleWebhookStore, EXIT, FORMAT_MARKER, FRAMEWORK_CONNECTOR, FRAMEWORK_RANK, FRAMEWORK_SOURCE, HISTORY_TABLE, IDEMPOTENCY_ENTITY_NAME, MIGRATE_URL_ENV, MIGRATION_CHECK_MODES, MIGRATION_FORMAT_VERSION, MYSQL_LOCK_NAME_SQL, MigrationVerdictError, PG_LOCK_KEY, SESSION_CONNECTOR, SESSION_ENTITY_NAME, SessionStorage, TOKEN_ENTITY_NAMES, TOTP_SECRET_ENTITY, WEBAUTHN_CREDENTIAL_ENTITY, WEBHOOK_ENDPOINT_ENTITY, accessTokenTable, action, appMigrationsDir, auditEventTable, buildMigrator, buildReport, createAccessTokenTable, createAuditEntities, createAuditEventTable, createDeniedJtiTable, createIdempotencyEntities, createIdempotencyTable, createSessionEntity, createSessionTable, createSubjectRevocationTable, createTokenEntities, createTotpSecretEntity, createTotpSecretTable, createUserEntity, createUserTable, createWebAuthnCredentialEntity, createWebAuthnCredentialTable, createWebhookEndpointEntity, createWebhookEndpointTable, drizzle_default as default, defaultMigrationSources, defineDrizzleConfig, deniedJtiTable, drizzleConfigJsonSchema, drizzleConfigSchema, exitCodeOf, frameworkMigrationsDir, idempotencyKeyTable, isFrameworkFallbackEntity, knownConnectors, loadSources, meaningOf, migrationHash, openMigrationDriver, orderSources, readMigrationEnv, registerAuditEntities, registerDrizzleFrameworkStores, registerIdempotencyEntities, registerSessionEntity, registerTokenEntities, registerTotpSecretEntity, registerUserEntity, registerWebAuthnCredentialEntity, registerWebhookEndpointEntity, renderRefusal, renderStatus, resetAllowed, resolveCheckMode, resolveConnector, resolveDdlMode, resolveDivergenceMode, sessionTable, styleFor, subjectRevocationTable, totpSecretTable, userTable, verdictOf, webAuthnCredentialTable, webhookEndpointTable };
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { HISTORY_TABLE, MigrationVerdictError } from "../src/migrator/types.js";
|
|
2
|
+
import { EXIT, action, describeDiscovery, refusalInMode, renderRefusal, styleFor } from "../src/migrator/explain.js";
|
|
3
|
+
import { missingHistoryColumn } from "../src/migrator/history.js";
|
|
4
|
+
import { buildMigrator, readMigrationEnv, resolveConnector } from "../src/migrator/resolve.js";
|
|
5
|
+
import { MigrationToolError, describeResolutionRefusal, moduleAbsent } from "../src/migrator/refusals.js";
|
|
6
|
+
import { composeReport } from "../src/migrator/status.js";
|
|
7
|
+
import { Command, resolveColorEnabled } from "nodefony";
|
|
8
|
+
//#region nodefony/command/migrateShared.ts
|
|
9
|
+
/**
|
|
10
|
+
* Socle commun des commandes `orm:*` — ce qui garantit qu'aucune d'elles ne
|
|
11
|
+
* laisse l'utilisateur, humain ou agent, devant une sortie muette.
|
|
12
|
+
*
|
|
13
|
+
* ## Les quatre garanties, et pourquoi elles vivent ICI
|
|
14
|
+
*
|
|
15
|
+
* 1. **Toute sortie porte un geste.** Succès, attente, refus ou panne : la
|
|
16
|
+
* commande écrit le fait, ce qu'il signifie, et la ligne exacte à copier.
|
|
17
|
+
* Écrites dans chaque commande, ces trois parties finiraient par manquer
|
|
18
|
+
* dans celle qu'on écrit un jour de fatigue — c'est justement celle qu'on
|
|
19
|
+
* rencontre en incident.
|
|
20
|
+
* 2. **`--json` est un flux PUR.** La sortie standard n'appartient qu'aux
|
|
21
|
+
* données : un objet, une ligne, rien d'autre. Y compris en échec — un agent
|
|
22
|
+
* qui a demandé du JSON doit pouvoir lire l'échec comme il lit le succès. Le
|
|
23
|
+
* journal du démarrage, lui, est déjà écarté vers la sortie d'erreur par le
|
|
24
|
+
* cœur, qui reconnaît `--json` dans les arguments avant même de brancher le
|
|
25
|
+
* journal.
|
|
26
|
+
* 3. **Aucune exception ne remonte nue.** Une pile d'appels n'est pas un
|
|
27
|
+
* message : elle ne dit ni ce qui s'est passé, ni quoi faire. Tout est
|
|
28
|
+
* rattrapé et traduit.
|
|
29
|
+
* 4. **La grille des codes de sortie est tenue en un seul endroit** — `0` à
|
|
30
|
+
* jour ou appliqué, `1` action requise, `2` la commande n'a pas pu faire son
|
|
31
|
+
* travail. Cette grille part chez l'utilisateur dans des passes
|
|
32
|
+
* d'intégration continue et des travaux de déploiement : la réaffecter plus
|
|
33
|
+
* tard casserait des contrôles qu'on ne voit pas.
|
|
34
|
+
*/
|
|
35
|
+
/** Nom du module qui porte la configuration des connecteurs SQL. */
|
|
36
|
+
const MODULE_NAME = "drizzle";
|
|
37
|
+
/**
|
|
38
|
+
* Classe de base des commandes `orm:*`.
|
|
39
|
+
*
|
|
40
|
+
* Elle n'impose rien du verbe : chaque commande écrit son `generate`. Elle
|
|
41
|
+
* impose la FORME de ce qui sort, parce que c'est cette forme qui fait la
|
|
42
|
+
* différence entre un outil qu'on sait utiliser et un outil qu'on subit.
|
|
43
|
+
*/
|
|
44
|
+
var OrmMigrateCommand = class extends Command {
|
|
45
|
+
/**
|
|
46
|
+
* Faut-il colorer la sortie ?
|
|
47
|
+
*
|
|
48
|
+
* 🔴 La question n'est PAS « est-ce un terminal ? », et la confondre avec ça
|
|
49
|
+
* a deux conséquences que personne ne signale :
|
|
50
|
+
*
|
|
51
|
+
* - **`NO_COLOR` est ignoré.** C'est une convention publique
|
|
52
|
+
* (no-color.org) qu'un utilisateur pose une fois pour toutes ses commandes ;
|
|
53
|
+
* la manquer rend une sortie illisible sur un terminal à palette
|
|
54
|
+
* inhabituelle, et le framework passe pour cassé.
|
|
55
|
+
* - **`FORCE_COLOR` est ignoré.** Sans lui, aucune sortie colorée n'est
|
|
56
|
+
* CAPTURABLE : ni dans un fichier, ni dans une passe d'intégration continue
|
|
57
|
+
* qui sait rendre les couleurs, ni dans un rapport de validation. On ne peut
|
|
58
|
+
* alors pas relire ce que l'exploitant voit vraiment.
|
|
59
|
+
*
|
|
60
|
+
* La règle vit au CŒUR (`resolveColorEnabled`), qui sert déjà les journaux :
|
|
61
|
+
* la réécrire ici en ferait une SECONDE implémentation, et les deux
|
|
62
|
+
* divergeraient — le journal obéirait à `NO_COLOR`, la commande non.
|
|
63
|
+
*/
|
|
64
|
+
get tty() {
|
|
65
|
+
return resolveColorEnabled(process.stdout.isTTY === true);
|
|
66
|
+
}
|
|
67
|
+
/** Mise en forme, neutralisée hors terminal. */
|
|
68
|
+
get style() {
|
|
69
|
+
return styleFor(this.tty);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Configuration validée du module qui porte les connecteurs SQL.
|
|
73
|
+
*
|
|
74
|
+
* @returns la configuration, ou `null` si le module n'est pas chargé.
|
|
75
|
+
*/
|
|
76
|
+
drizzleConfig() {
|
|
77
|
+
const mod = (this.kernel?.modules)?.[MODULE_NAME];
|
|
78
|
+
return mod ? mod.config : null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Écrit une charge utile sur la sortie standard et pose le code de sortie.
|
|
82
|
+
*
|
|
83
|
+
* `process.exitCode` et jamais `process.exit()` : couper le processus laisse
|
|
84
|
+
* la sortie standard non vidée, et un `| jq` reçoit alors un objet tronqué —
|
|
85
|
+
* un échec qui ressemble à un défaut de la commande.
|
|
86
|
+
*
|
|
87
|
+
* @param payload - l'objet, en mode machine.
|
|
88
|
+
* @param human - le texte, en mode humain.
|
|
89
|
+
* @param exitCode - `0`, `1` ou `2`.
|
|
90
|
+
* @param json - la commande a-t-elle reçu `--json` ?
|
|
91
|
+
*/
|
|
92
|
+
respond(payload, human, exitCode, json) {
|
|
93
|
+
if (json === true) process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
94
|
+
else process.stdout.write(human.endsWith("\n") ? human : `${human}\n`);
|
|
95
|
+
if (exitCode !== 0) process.exitCode = exitCode;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Arrête la commande en disant le fait, la cause et le geste.
|
|
99
|
+
*
|
|
100
|
+
* @param connector - connecteur concerné (ou le nom demandé).
|
|
101
|
+
* @param code - code d'arrêt stable, lu par les machines.
|
|
102
|
+
* @param summary - le fait, en français.
|
|
103
|
+
* @param meaning - ce que ça veut dire.
|
|
104
|
+
* @param actions - les commandes exactes à copier.
|
|
105
|
+
* @param json - la commande a-t-elle reçu `--json` ?
|
|
106
|
+
* @param exitCode - `2` par défaut : la commande n'a pas pu travailler.
|
|
107
|
+
* @param discovery - ce que la découverte des entités a vu, quand le refus
|
|
108
|
+
* peut avoir pour cause un schéma déclaré amputé.
|
|
109
|
+
*/
|
|
110
|
+
fail(connector, code, summary, meaning, actions, json, exitCode = EXIT.error, discovery) {
|
|
111
|
+
const style = this.style;
|
|
112
|
+
const payload = {
|
|
113
|
+
formatVersion: 1,
|
|
114
|
+
connector,
|
|
115
|
+
exitCode,
|
|
116
|
+
error: {
|
|
117
|
+
code,
|
|
118
|
+
summary,
|
|
119
|
+
meaning,
|
|
120
|
+
nextActions: actions,
|
|
121
|
+
...discovery ? { discovery } : {}
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
let human = `${style.red(style.bold("Impossible"))} ${style.dim(`[${code}]`)}\n\n${summary}\n`;
|
|
125
|
+
if (meaning) human += `\n${style.dim(meaning)}\n`;
|
|
126
|
+
if (discovery) human += describeDiscovery(discovery, style);
|
|
127
|
+
if (actions.length > 0) {
|
|
128
|
+
human += `\n${style.bold("À faire :")}\n`;
|
|
129
|
+
for (const a of actions) human += ` ${style.green(a.command)}\n`;
|
|
130
|
+
}
|
|
131
|
+
if (json === true) process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
132
|
+
else process.stderr.write(human);
|
|
133
|
+
process.exitCode = exitCode;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Résout le connecteur demandé, ou ARRÊTE la commande en le disant.
|
|
137
|
+
*
|
|
138
|
+
* Les **trois** réponses sont un contrat public, et elles restent distinctes :
|
|
139
|
+
* un connecteur inconnu, un connecteur porté par un ORM sans migrations, un
|
|
140
|
+
* connecteur prêt. Le jour où un second ORM apporte ses propres migrations,
|
|
141
|
+
* seule la deuxième cesse de sortir pour ses connecteurs — répondre « ne
|
|
142
|
+
* porte pas de migrations » à un connecteur qui en porte serait un message
|
|
143
|
+
* FAUX, et un message faux publié est appris par les scripts qui le lisent.
|
|
144
|
+
*
|
|
145
|
+
* @param opts - options de la commande (connecteur, mode machine).
|
|
146
|
+
* @param allowMigrateUrl - la commande honore-t-elle {@link MIGRATE_URL_ENV} ?
|
|
147
|
+
* @returns le connecteur prêt, ou `null` si la commande est déjà arrêtée.
|
|
148
|
+
*/
|
|
149
|
+
resolveOrFail(opts, allowMigrateUrl) {
|
|
150
|
+
const wanted = opts.connector ?? "default";
|
|
151
|
+
const config = this.drizzleConfig();
|
|
152
|
+
if (!config) {
|
|
153
|
+
const refusal = moduleAbsent();
|
|
154
|
+
this.fail(wanted, refusal.code, refusal.summary, refusal.meaning, refusal.nextActions, opts.json, refusal.exitCode);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const resolution = resolveConnector(wanted, config, readMigrationEnv(this.kernel), this.kernel, { allowMigrateUrl });
|
|
158
|
+
if (resolution.kind !== "ready") {
|
|
159
|
+
const refusal = describeResolutionRefusal(wanted, resolution, config);
|
|
160
|
+
this.fail(wanted, refusal.code, refusal.summary, refusal.meaning, refusal.nextActions, opts.json, refusal.exitCode);
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
resolution,
|
|
165
|
+
config
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Construit l'applicateur d'un connecteur résolu.
|
|
170
|
+
*
|
|
171
|
+
* @param resolution - connecteur prêt.
|
|
172
|
+
* @param config - configuration validée.
|
|
173
|
+
* @returns l'applicateur, sources chargées.
|
|
174
|
+
*/
|
|
175
|
+
async migrator(resolution, config) {
|
|
176
|
+
return buildMigrator(resolution, config, this.kernel);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Compose la charge utile d'un état.
|
|
180
|
+
*
|
|
181
|
+
* L'assemblage lui-même vit dans `migrator/status.ts` : le plan
|
|
182
|
+
* d'administration publie le MÊME objet, et deux assemblages divergeaient
|
|
183
|
+
* d'un champ à l'autre sans qu'aucun test ne le voie.
|
|
184
|
+
*
|
|
185
|
+
* @param plan - plan calculé par l'applicateur, en lecture seule.
|
|
186
|
+
* @param resolution - connecteur prêt (porte le mode de schéma effectif).
|
|
187
|
+
* @param config - configuration validée du module.
|
|
188
|
+
* @returns la charge utile, prête pour `--json` comme pour l'écran.
|
|
189
|
+
*/
|
|
190
|
+
async report(plan, resolution, config) {
|
|
191
|
+
return composeReport(plan, resolution, config, this.kernel);
|
|
192
|
+
}
|
|
193
|
+
failFrom(e, connector, json, ddl) {
|
|
194
|
+
if (e instanceof MigrationVerdictError) {
|
|
195
|
+
const style = this.style;
|
|
196
|
+
const enMode = ddl ? refusalInMode(e.verdict.code, ddl, connector) : null;
|
|
197
|
+
const payload = {
|
|
198
|
+
formatVersion: 1,
|
|
199
|
+
connector,
|
|
200
|
+
exitCode: e.verdict.code === "NF_MIGRATE_LOCK_TIMEOUT" ? EXIT.error : EXIT.actionRequired,
|
|
201
|
+
error: {
|
|
202
|
+
code: e.verdict.code,
|
|
203
|
+
summary: e.message,
|
|
204
|
+
meaning: enMode?.meaning ?? "",
|
|
205
|
+
nextActions: enMode?.actions ?? [...e.verdict.nextActions]
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
if (json === true) process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
209
|
+
else process.stderr.write(renderRefusal(e.verdict, e.message, style, ddl));
|
|
210
|
+
process.exitCode = payload.exitCode;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (e instanceof MigrationToolError) {
|
|
214
|
+
const { code, summary, meaning, nextActions, exitCode } = e.refusal;
|
|
215
|
+
this.fail(connector, code, summary, meaning, nextActions, json, exitCode);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const cause = e instanceof Error ? e.message : String(e);
|
|
219
|
+
const column = missingHistoryColumn(cause);
|
|
220
|
+
if (column !== null) {
|
|
221
|
+
this.fail(connector, "NF_MIGRATE_HISTORY_FOREIGN", `La table « ${HISTORY_TABLE} » de cette base n'est pas celle du framework : la colonne « ${column} » y manque. Rien n'a été appliqué.`, `Une table de ce nom existe déjà, avec d'autres colonnes — le framework ne la remplace jamais, et ne peut pas la lire. Deux provenances, deux gestes. Base d'ESSAI fabriquée à la main : ne pas écrire l'historique soi-même, mais COPIER la base d'origine (le fichier en sqlite, un export « pg_dump » / « mysqldump » ailleurs) — c'est cette copie qui porte déjà le bon historique. Base RÉELLE venue d'un autre outil de migration : la table porte le même nom par coïncidence ; la renommer, ou faire porter le framework sur une autre base. Dans tous les cas la base n'est PAS en cause : elle a répondu, et ce n'est pas une question de droits.`, [action("nodefony orm:migrate:status --json"), action("nodefony inspect config --json")], json, EXIT.actionRequired);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
this.fail(connector, "NF_MIGRATE_UNAVAILABLE", `La commande n'a pas pu travailler sur le connecteur « ${connector} » : ${cause}`, "La commande s'est arrêtée sans avoir pu nommer la cause. Les deux explications les plus fréquentes : la base n'a pas répondu, ou le compte utilisé n'a pas les droits nécessaires — celui qui migre a besoin de pouvoir créer et modifier des tables, ce que le compte qui sert le trafic n'a normalement pas. Avant de reprendre, CONSTATER l'état : `orm:migrate:status` dit ce que la base porte et ce que l'historique en dit.", [action("nodefony orm:migrate:status --json"), action("nodefony inspect config --json")], json);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Écrit un état lu et pose son code de sortie.
|
|
228
|
+
*
|
|
229
|
+
* @param report - charge utile complète.
|
|
230
|
+
* @param human - rendu humain déjà composé.
|
|
231
|
+
* @param json - la commande a-t-elle reçu `--json` ?
|
|
232
|
+
*/
|
|
233
|
+
emitReport(report, human, json) {
|
|
234
|
+
this.respond(report, human, report.exitCode, json);
|
|
235
|
+
}
|
|
236
|
+
/** Déclare les deux options que toutes les commandes de migration portent. */
|
|
237
|
+
addSharedOptions() {
|
|
238
|
+
this.addOption("-c, --connector <nom>", "connecteur SQL visé (défaut : default) — c'est une clé de `connectors` dans la configuration");
|
|
239
|
+
this.addOption("-j, --json", "sortie machine : un objet sur la sortie standard, le journal sur la sortie d'erreur (`| jq` sûr)");
|
|
240
|
+
}
|
|
241
|
+
/** Le CLI courant, typé — utilisé pour les réglages de boot silencieux. */
|
|
242
|
+
get cliKernel() {
|
|
243
|
+
return this.cli;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
//#endregion
|
|
247
|
+
export { OrmMigrateCommand };
|