@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.
Files changed (143) hide show
  1. package/LICENSE +544 -0
  2. package/README.md +162 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
  5. package/dist/index.js +105 -0
  6. package/dist/nodefony/command/migrateShared.js +247 -0
  7. package/dist/nodefony/command/orm-generate.js +356 -0
  8. package/dist/nodefony/command/orm-migrate-baseline.js +208 -0
  9. package/dist/nodefony/command/orm-migrate-repair.js +114 -0
  10. package/dist/nodefony/command/orm-migrate-status.js +67 -0
  11. package/dist/nodefony/command/orm-migrate.js +141 -0
  12. package/dist/nodefony/command/orm-reset.js +166 -0
  13. package/dist/nodefony/config/config.js +107 -0
  14. package/dist/nodefony/config/defineModuleConfig.js +63 -0
  15. package/dist/nodefony/entity/auditEventEntity.js +93 -0
  16. package/dist/nodefony/entity/colKit.js +260 -0
  17. package/dist/nodefony/entity/idempotencyEntity.js +74 -0
  18. package/dist/nodefony/entity/sessionEntity.js +75 -0
  19. package/dist/nodefony/entity/tokenEntity.js +198 -0
  20. package/dist/nodefony/entity/totpSecretEntity.js +98 -0
  21. package/dist/nodefony/entity/userTable.js +141 -0
  22. package/dist/nodefony/entity/webAuthnCredentialEntity.js +114 -0
  23. package/dist/nodefony/entity/webhookEndpointEntity.js +106 -0
  24. package/dist/nodefony/interfaces/IDrizzleConfig.js +1 -0
  25. package/dist/nodefony/interfaces/index.js +1 -0
  26. package/dist/nodefony/migrations-schema/mysql.js +48 -0
  27. package/dist/nodefony/migrations-schema/postgres.js +48 -0
  28. package/dist/nodefony/migrations-schema/sqlite.js +48 -0
  29. package/dist/nodefony/registerStores.js +218 -0
  30. package/dist/nodefony/service/DrizzleService.js +282 -0
  31. package/dist/nodefony/src/DrizzleAuditStore.js +203 -0
  32. package/dist/nodefony/src/DrizzleIdempotencyStore.js +278 -0
  33. package/dist/nodefony/src/DrizzleTokenStore.js +244 -0
  34. package/dist/nodefony/src/DrizzleTotpSecretStore.js +151 -0
  35. package/dist/nodefony/src/DrizzleUserRepository.js +217 -0
  36. package/dist/nodefony/src/DrizzleWebAuthnCredentialStore.js +159 -0
  37. package/dist/nodefony/src/DrizzleWebhookStore.js +169 -0
  38. package/dist/nodefony/src/SessionStorage.js +259 -0
  39. package/dist/nodefony/src/connectorTarget.js +59 -0
  40. package/dist/nodefony/src/likeSql.js +50 -0
  41. package/dist/nodefony/src/migrator/DrizzleMigrator.js +775 -0
  42. package/dist/nodefony/src/migrator/adopt.js +553 -0
  43. package/dist/nodefony/src/migrator/appSchema.js +414 -0
  44. package/dist/nodefony/src/migrator/catalog.js +76 -0
  45. package/dist/nodefony/src/migrator/destructive.js +213 -0
  46. package/dist/nodefony/src/migrator/divergence.js +84 -0
  47. package/dist/nodefony/src/migrator/drivers/index.js +39 -0
  48. package/dist/nodefony/src/migrator/drivers/mysqlDriver.js +147 -0
  49. package/dist/nodefony/src/migrator/drivers/postgresDriver.js +151 -0
  50. package/dist/nodefony/src/migrator/drivers/sqliteDriver.js +121 -0
  51. package/dist/nodefony/src/migrator/explain.js +565 -0
  52. package/dist/nodefony/src/migrator/hash.js +47 -0
  53. package/dist/nodefony/src/migrator/history.js +219 -0
  54. package/dist/nodefony/src/migrator/index.js +16 -0
  55. package/dist/nodefony/src/migrator/kit.js +296 -0
  56. package/dist/nodefony/src/migrator/name.js +68 -0
  57. package/dist/nodefony/src/migrator/paths.js +88 -0
  58. package/dist/nodefony/src/migrator/refusals.js +143 -0
  59. package/dist/nodefony/src/migrator/resolve.js +281 -0
  60. package/dist/nodefony/src/migrator/schemaDiff.js +86 -0
  61. package/dist/nodefony/src/migrator/sources.js +419 -0
  62. package/dist/nodefony/src/migrator/status.js +231 -0
  63. package/dist/nodefony/src/migrator/types.js +91 -0
  64. package/dist/nodefony/src/orm-core/DrizzleOrm.js +1154 -0
  65. package/dist/nodefony/src/orm-core/DrizzleRepository.js +610 -0
  66. package/dist/nodefony/src/orm-core/DrizzleTransaction.js +106 -0
  67. package/dist/nodefony/src/orm-core/index.js +4 -0
  68. package/dist/nodefony/src/queryKit.js +318 -0
  69. package/dist/nodefony/src/safeTarget.js +55 -0
  70. package/dist/types/index.d.ts +76 -0
  71. package/dist/types/nodefony/command/migrateShared.d.ts +137 -0
  72. package/dist/types/nodefony/command/orm-generate.d.ts +53 -0
  73. package/dist/types/nodefony/command/orm-migrate-baseline.d.ts +87 -0
  74. package/dist/types/nodefony/command/orm-migrate-repair.d.ts +66 -0
  75. package/dist/types/nodefony/command/orm-migrate-status.d.ts +38 -0
  76. package/dist/types/nodefony/command/orm-migrate.d.ts +65 -0
  77. package/dist/types/nodefony/command/orm-reset.d.ts +55 -0
  78. package/dist/types/nodefony/config/config.d.ts +110 -0
  79. package/dist/types/nodefony/config/defineModuleConfig.d.ts +24 -0
  80. package/dist/types/nodefony/entity/auditEventEntity.d.ts +56 -0
  81. package/dist/types/nodefony/entity/colKit.d.ts +130 -0
  82. package/dist/types/nodefony/entity/idempotencyEntity.d.ts +52 -0
  83. package/dist/types/nodefony/entity/sessionEntity.d.ts +50 -0
  84. package/dist/types/nodefony/entity/tokenEntity.d.ts +53 -0
  85. package/dist/types/nodefony/entity/totpSecretEntity.d.ts +61 -0
  86. package/dist/types/nodefony/entity/userTable.d.ts +65 -0
  87. package/dist/types/nodefony/entity/webAuthnCredentialEntity.d.ts +57 -0
  88. package/dist/types/nodefony/entity/webhookEndpointEntity.d.ts +58 -0
  89. package/dist/types/nodefony/interfaces/IDrizzleConfig.d.ts +17 -0
  90. package/dist/types/nodefony/interfaces/index.d.ts +1 -0
  91. package/dist/types/nodefony/migrations-schema/mysql.d.ts +9 -0
  92. package/dist/types/nodefony/migrations-schema/postgres.d.ts +9 -0
  93. package/dist/types/nodefony/migrations-schema/sqlite.d.ts +9 -0
  94. package/dist/types/nodefony/registerStores.d.ts +52 -0
  95. package/dist/types/nodefony/service/DrizzleService.d.ts +27 -0
  96. package/dist/types/nodefony/src/DrizzleAuditStore.d.ts +65 -0
  97. package/dist/types/nodefony/src/DrizzleIdempotencyStore.d.ts +129 -0
  98. package/dist/types/nodefony/src/DrizzleTokenStore.d.ts +146 -0
  99. package/dist/types/nodefony/src/DrizzleTotpSecretStore.d.ts +60 -0
  100. package/dist/types/nodefony/src/DrizzleUserRepository.d.ts +67 -0
  101. package/dist/types/nodefony/src/DrizzleWebAuthnCredentialStore.d.ts +62 -0
  102. package/dist/types/nodefony/src/DrizzleWebhookStore.d.ts +79 -0
  103. package/dist/types/nodefony/src/SessionStorage.d.ts +72 -0
  104. package/dist/types/nodefony/src/connectorTarget.d.ts +48 -0
  105. package/dist/types/nodefony/src/likeSql.d.ts +29 -0
  106. package/dist/types/nodefony/src/migrator/DrizzleMigrator.d.ts +94 -0
  107. package/dist/types/nodefony/src/migrator/adopt.d.ts +280 -0
  108. package/dist/types/nodefony/src/migrator/appSchema.d.ts +223 -0
  109. package/dist/types/nodefony/src/migrator/catalog.d.ts +100 -0
  110. package/dist/types/nodefony/src/migrator/destructive.d.ts +123 -0
  111. package/dist/types/nodefony/src/migrator/divergence.d.ts +61 -0
  112. package/dist/types/nodefony/src/migrator/drivers/index.d.ts +26 -0
  113. package/dist/types/nodefony/src/migrator/drivers/mysqlDriver.d.ts +83 -0
  114. package/dist/types/nodefony/src/migrator/drivers/postgresDriver.d.ts +81 -0
  115. package/dist/types/nodefony/src/migrator/drivers/sqliteDriver.d.ts +53 -0
  116. package/dist/types/nodefony/src/migrator/explain.d.ts +424 -0
  117. package/dist/types/nodefony/src/migrator/hash.d.ts +39 -0
  118. package/dist/types/nodefony/src/migrator/history.d.ts +139 -0
  119. package/dist/types/nodefony/src/migrator/index.d.ts +20 -0
  120. package/dist/types/nodefony/src/migrator/kit.d.ts +141 -0
  121. package/dist/types/nodefony/src/migrator/name.d.ts +52 -0
  122. package/dist/types/nodefony/src/migrator/paths.d.ts +54 -0
  123. package/dist/types/nodefony/src/migrator/refusals.d.ts +170 -0
  124. package/dist/types/nodefony/src/migrator/resolve.d.ts +201 -0
  125. package/dist/types/nodefony/src/migrator/schemaDiff.d.ts +112 -0
  126. package/dist/types/nodefony/src/migrator/sources.d.ts +119 -0
  127. package/dist/types/nodefony/src/migrator/status.d.ts +132 -0
  128. package/dist/types/nodefony/src/migrator/types.d.ts +273 -0
  129. package/dist/types/nodefony/src/orm-core/DrizzleOrm.d.ts +241 -0
  130. package/dist/types/nodefony/src/orm-core/DrizzleRepository.d.ts +98 -0
  131. package/dist/types/nodefony/src/orm-core/DrizzleTransaction.d.ts +71 -0
  132. package/dist/types/nodefony/src/orm-core/index.d.ts +11 -0
  133. package/dist/types/nodefony/src/queryKit.d.ts +136 -0
  134. package/dist/types/nodefony/src/safeTarget.d.ts +42 -0
  135. package/docs/index.md +954 -0
  136. package/docs/migrations.md +691 -0
  137. package/migrations/mysql/0000_framework_init.sql +137 -0
  138. package/migrations/mysql/meta/_journal.json +13 -0
  139. package/migrations/postgres/0000_framework_init.sql +128 -0
  140. package/migrations/postgres/meta/_journal.json +13 -0
  141. package/migrations/sqlite/0000_framework_init.sql +127 -0
  142. package/migrations/sqlite/meta/_journal.json +13 -0
  143. package/package.json +126 -0
@@ -0,0 +1,98 @@
1
+ import { createFrameworkTableFactory } from "./colKit.js";
2
+ import { entityRegistry } from "@nodefony/orm-core";
3
+ /**
4
+ * Factory de la table de secrets TOTP pour un dialecte donné (mémoïsée — une
5
+ * instance par dialecte). **Les trois dialectes sont portés** (`TOTP_PORTED =
6
+ * ALL_DIALECTS`, `registerStores.ts:92`) : sqlite, postgres et mysql.
7
+ */
8
+ const createTotpSecretTable = createFrameworkTableFactory({
9
+ name: "totp_secret",
10
+ columns: {
11
+ /** Propriétaire du secret (clé naturelle — un seul secret par utilisateur). */
12
+ userId: {
13
+ kind: "text",
14
+ primaryKey: true
15
+ },
16
+ /** Secret partagé `K` **chiffré** (blob opaque `iv.tag.ciphertext` base64url). */
17
+ secretEnc: {
18
+ kind: "text",
19
+ notNull: true
20
+ },
21
+ /** Fonction HMAC du code (`SHA1`|`SHA256`|`SHA512`). */
22
+ algorithm: {
23
+ kind: "text",
24
+ notNull: true
25
+ },
26
+ /** Nombre de chiffres du code. */
27
+ digits: {
28
+ kind: "int",
29
+ notNull: true
30
+ },
31
+ /** Période d'un code en secondes. */
32
+ period: {
33
+ kind: "int",
34
+ notNull: true
35
+ },
36
+ /** Condensats `sha256` des codes de récupération non encore consommés. */
37
+ recoveryCodes: {
38
+ kind: "json",
39
+ notNull: true,
40
+ defaultFn: () => []
41
+ },
42
+ /** Confirmation de l'enrôlement (epoch ms) ou `null` (anti-lock-out). */
43
+ confirmedAt: { kind: "epochMs" },
44
+ /**
45
+ * Dernière tranche `T` validée (RFC 6238 §5.2, anti-rejeu) ou `null`.
46
+ *
47
+ * `int64` : `T = floor(epochSeconds / period)`, et `period` n'a pas de
48
+ * borne basse (schéma Zod : `positive()`). À `period` = 1 la tranche vaut
49
+ * l'horodatage Unix lui-même, qui dépasse l'entier 32 bits signé en 2038 —
50
+ * l'anti-rejeu cesserait alors de retenir, en silence.
51
+ */
52
+ lastUsedStep: { kind: "int64" },
53
+ /** Création (epoch ms). */
54
+ createdAt: {
55
+ kind: "epochMs",
56
+ notNull: true
57
+ },
58
+ /** Dernier usage réussi (epoch ms) ou `null`. */
59
+ lastUsedAt: { kind: "epochMs" }
60
+ }
61
+ });
62
+ /**
63
+ * Variante SQLite de la table de secrets TOTP (dialecte par défaut) — export
64
+ * conservé pour l'usage direct/banc-test.
65
+ */
66
+ const totpSecretTable = createTotpSecretTable("sqlite");
67
+ /** Nom logique de l'entité (clé de lookup `getRepository`). */
68
+ const TOTP_SECRET_ENTITY = "totp_secret";
69
+ /**
70
+ * Construit le descripteur d'entité du store de secrets TOTP pour un ORM nommé.
71
+ * Le `connector` est **dynamique** (nom du connecteur de l'app) et la variante de table
72
+ * suit le dialecte du connecteur (auto-register `registerStores.ts`). À enregistrer
73
+ * **avant** `orm.connect()`. `module: "security"` → regroupé sous @nodefony/security
74
+ * dans l'ERD Studio.
75
+ *
76
+ * @param orm - clé de l'ORM cible dans le `ormRegistry`.
77
+ * @param dialect - dialecte SQL du connecteur (sélectionne la variante de table).
78
+ */
79
+ function createTotpSecretEntity(connector, dialect = "sqlite") {
80
+ return {
81
+ connector,
82
+ name: TOTP_SECRET_ENTITY,
83
+ module: "security",
84
+ schema: createTotpSecretTable(dialect)
85
+ };
86
+ }
87
+ /**
88
+ * Enregistre l'entité du store de secrets TOTP dans le `entityRegistry` pour un ORM
89
+ * donné. À appeler **avant** `orm.connect()` (l'adapter crée la table au connect).
90
+ *
91
+ * @param connector - nom de la connexion cible (clé du registre).
92
+ * @param dialect - dialecte SQL du connecteur (variante de table — défaut `sqlite`).
93
+ */
94
+ function registerTotpSecretEntity(connector, dialect = "sqlite") {
95
+ entityRegistry.register(createTotpSecretEntity(connector, dialect));
96
+ }
97
+ //#endregion
98
+ export { TOTP_SECRET_ENTITY, createTotpSecretEntity, createTotpSecretTable, registerTotpSecretEntity, totpSecretTable };
@@ -0,0 +1,141 @@
1
+ import { createFrameworkTableFactory } from "./colKit.js";
2
+ import { entityRegistry } from "@nodefony/orm-core";
3
+ import { USER_COLUMNS, USER_TABLE_NAME } from "@nodefony/user";
4
+ import { getTableConfig } from "drizzle-orm/sqlite-core";
5
+ import { getTableConfig as getTableConfig$1 } from "drizzle-orm/pg-core";
6
+ import { getTableConfig as getTableConfig$2 } from "drizzle-orm/mysql-core";
7
+ import { randomUUID } from "node:crypto";
8
+ //#region nodefony/entity/userTable.ts
9
+ /**
10
+ * Traduction d'un type LOGIQUE du contrat utilisateur vers le type du colKit.
11
+ *
12
+ * C'est le seul endroit du module SQL qui connaisse ce vocabulaire : le contrat
13
+ * dit ce que la donnée EST, le colKit dit comment chaque dialecte la range.
14
+ */
15
+ const KIND_BY_TYPE = {
16
+ uuid: "text",
17
+ string: "text",
18
+ "string[]": "json",
19
+ boolean: "bool",
20
+ object: "json",
21
+ "object[]": "json",
22
+ date: "dateMs"
23
+ };
24
+ /**
25
+ * Construit la spec colKit d'une colonne du contrat utilisateur.
26
+ *
27
+ * Les trois origines ne se déclarent pas pareil en SQL : la clé primaire reçoit
28
+ * l'UUID applicatif, un horodatage reçoit l'heure courante (et se régénère si le
29
+ * contrat le dit), une colonne ordinaire reçoit son défaut déclaré.
30
+ *
31
+ * ⚠️ Les défauts restent **JS-level** (`$defaultFn`) : le DDL dérivé n'émet pas
32
+ * de `DEFAULT` SQL (règle du colKit). Une valeur absente à l'insertion est donc
33
+ * comblée par le pilote, pas par le serveur.
34
+ */
35
+ function toColSpec(column) {
36
+ const kind = KIND_BY_TYPE[column.type];
37
+ switch (column.origin) {
38
+ case "identity": return {
39
+ kind,
40
+ primaryKey: true,
41
+ defaultFn: () => randomUUID()
42
+ };
43
+ case "audit": return {
44
+ kind,
45
+ notNull: true,
46
+ defaultFn: () => /* @__PURE__ */ new Date(),
47
+ ...column.refreshedOnWrite ? { onUpdateFn: () => /* @__PURE__ */ new Date() } : {}
48
+ };
49
+ case "column": return {
50
+ kind,
51
+ ...column.nullable ? {} : { notNull: true },
52
+ ...column.unique ? { unique: true } : {},
53
+ ...column.makeDefault ? { defaultFn: column.makeDefault } : {}
54
+ };
55
+ }
56
+ }
57
+ /**
58
+ * Entité de l'utilisateur Nodefony (schema-as-code) — implémentation SQL
59
+ * **par défaut** du contrat `@nodefony/user`, **dérivée** de `USER_COLUMNS` et
60
+ * déclinée par le `colKit` : une spec logique, la table du dialecte du
61
+ * connecteur.
62
+ *
63
+ * Rien n'est recopié : les noms, les types logiques, les défauts et les
64
+ * contraintes viennent du contrat. Ce fichier ne décide que de la traduction
65
+ * vers SQL — ce qui est exactement ce qu'un adaptateur doit savoir, et rien de
66
+ * plus. Une colonne ajoutée au contrat apparaît donc ici sans qu'on y touche,
67
+ * et `tests/unit/userContractParity.test.ts` refuse le contraire.
68
+ *
69
+ * Les horodatages sont des colonnes EXPLICITES (kind `dateMs`, exposé `Date`) —
70
+ * à la différence de Mongoose, qui les gère au niveau du schéma.
71
+ */
72
+ const USER_TABLE_SPEC = {
73
+ name: USER_TABLE_NAME,
74
+ columns: Object.fromEntries(USER_COLUMNS.map((column) => [column.name, toColSpec(column)]))
75
+ };
76
+ /**
77
+ * Factory de la table `User` pour un dialecte donné (mémoïsée — une instance
78
+ * par dialecte). Les trois dialectes sont portés (`sqlite` par défaut).
79
+ */
80
+ const createUserTable = createFrameworkTableFactory(USER_TABLE_SPEC);
81
+ /**
82
+ * Variante SQLite de la table `User` (dialecte par défaut) — export conservé
83
+ * pour l'usage direct/banc-test (ex. module mediasoup).
84
+ */
85
+ const userTable = createUserTable("sqlite");
86
+ /**
87
+ * Construit le descripteur d'entité `User` Drizzle pour un ORM nommé.
88
+ *
89
+ * Le `connector` est **dynamique** (nom du connecteur de l'app, ex. `"default"`) et la
90
+ * variante de table suit le dialecte du connecteur (auto-register
91
+ * `registerStores.ts` à `onKernelRegister`). À enregistrer dans `entityRegistry`
92
+ * **avant** `orm.connect()` (cf {@link registerUserEntity}).
93
+ *
94
+ * @param orm - clé de l'ORM cible dans le `ormRegistry`.
95
+ * @param dialect - dialecte SQL du connecteur (sélectionne la variante de table).
96
+ * @returns descripteur {@link IEntity} (`name: "User"`).
97
+ */
98
+ function createUserEntity(connector, dialect = "sqlite") {
99
+ return {
100
+ connector,
101
+ name: "User",
102
+ module: "user",
103
+ schema: createUserTable(dialect)
104
+ };
105
+ }
106
+ /**
107
+ * Enregistre l'entité `User` Drizzle dans le `entityRegistry` pour un ORM donné.
108
+ * À appeler **avant** `orm.connect()` (l'adapter compile/crée les tables au connect).
109
+ *
110
+ * @param connector - nom de la connexion cible (clé du registre).
111
+ * @param dialect - dialecte SQL du connecteur (variante de table — défaut `sqlite`).
112
+ */
113
+ function registerUserEntity(connector, dialect = "sqlite") {
114
+ entityRegistry.register(createUserEntity(connector, dialect));
115
+ }
116
+ /**
117
+ * Colonnes d'une table Drizzle, lues dans la GRAMMAIRE de son dialecte.
118
+ *
119
+ * L'extraction n'a rien d'anodin : `getTableConfig` n'est pas la même fonction
120
+ * selon le dialecte, et la mauvaise appliquée à une table LÈVE un
121
+ * `TypeError: Cannot convert undefined or null to object` — mesuré sur les six
122
+ * croisements, aucun ne rend un objet vide ni un résultat partiel. La
123
+ * conséquence est la même dans les deux lectures qu'on pourrait en faire : un
124
+ * appelant qui ne route pas par dialecte n'obtient RIEN d'exploitable. D'où un
125
+ * seul point de lecture, partagé par le contrôle de démarrage et par le banc de
126
+ * parité — et un dialecte qui doit suivre l'entité jusqu'ici.
127
+ *
128
+ * @param table - la table Drizzle, telle que l'entité la rend (`schema`).
129
+ * @param dialect - dialecte du connecteur qui la porte.
130
+ * @returns les colonnes indexées par nom SQL.
131
+ */
132
+ function userTableColumns(table, dialect) {
133
+ const columns = dialect === "postgres" ? getTableConfig$1(table).columns : dialect === "mysql" ? getTableConfig$2(table).columns : getTableConfig(table).columns;
134
+ return new Map(columns.map((column) => [column.name, {
135
+ notNull: column.notNull,
136
+ isUnique: column.isUnique ?? false,
137
+ primary: column.primary
138
+ }]));
139
+ }
140
+ //#endregion
141
+ export { createUserEntity, createUserTable, registerUserEntity, userTable, userTableColumns };
@@ -0,0 +1,114 @@
1
+ import { createFrameworkTableFactory } from "./colKit.js";
2
+ import { entityRegistry } from "@nodefony/orm-core";
3
+ /**
4
+ * Factory de la table de credentials pour un dialecte donné (mémoïsée — une
5
+ * instance par dialecte). `sqlite` (défaut) et `postgres` sont portés ;
6
+ * `mysql` jette (S4).
7
+ */
8
+ const createWebAuthnCredentialTable = createFrameworkTableFactory({
9
+ name: "webauthn_credential",
10
+ columns: {
11
+ /** Identifiant du credential (base64url) — clé fournie par l'authenticator. */
12
+ id: {
13
+ kind: "text",
14
+ primaryKey: true
15
+ },
16
+ /** Propriétaire (sub / userHandle applicatif). */
17
+ userId: {
18
+ kind: "text",
19
+ notNull: true
20
+ },
21
+ /** Clé publique COSE encodée base64url. */
22
+ publicKey: {
23
+ kind: "text",
24
+ notNull: true
25
+ },
26
+ /**
27
+ * Compteur de signatures (anti-clone, §6.1.1).
28
+ *
29
+ * `int64` et non `int` : WebAuthn définit ce compteur comme un **uint32**
30
+ * (jusqu'à 4 294 967 295), qui déborde l'entier 32 bits SIGNÉ des trois
31
+ * dialectes. Un authenticator réel n'y arrivera pas, mais la valeur est
32
+ * fournie par le périphérique et rien ne la borne côté serveur.
33
+ */
34
+ signCount: {
35
+ kind: "int64",
36
+ notNull: true
37
+ },
38
+ /** Transports annoncés (`usb`|`nfc`|`ble`|`internal`|`hybrid`). */
39
+ transports: {
40
+ kind: "json",
41
+ notNull: true,
42
+ defaultFn: () => []
43
+ },
44
+ /** BE flag (Backup Eligibility) — fixé à l'enregistrement. */
45
+ backupEligible: {
46
+ kind: "bool",
47
+ notNull: true
48
+ },
49
+ /** BS flag (Backup State) — peut évoluer. */
50
+ backupState: {
51
+ kind: "bool",
52
+ notNull: true
53
+ },
54
+ /** UV réalisée au moins une fois (base du step-up MFA). */
55
+ uvInitialized: {
56
+ kind: "bool",
57
+ notNull: true
58
+ },
59
+ /** Surnom choisi par l'utilisateur ; `null` = aucun. */
60
+ nickname: { kind: "text" },
61
+ /** Création (epoch ms). */
62
+ createdAt: {
63
+ kind: "epochMs",
64
+ notNull: true
65
+ },
66
+ /** Dernière authentification réussie (epoch ms) ou `null`. */
67
+ lastUsedAt: { kind: "epochMs" }
68
+ },
69
+ indexes: [{
70
+ name: "webauthn_credential_userId_idx",
71
+ on: ["userId"]
72
+ }]
73
+ });
74
+ /**
75
+ * Variante SQLite de la table de credentials (dialecte par défaut) — export
76
+ * conservé pour l'usage direct/banc-test.
77
+ */
78
+ const webAuthnCredentialTable = createWebAuthnCredentialTable("sqlite");
79
+ /** Nom logique de l'entité (clé de lookup `getRepository`). */
80
+ const WEBAUTHN_CREDENTIAL_ENTITY = "webauthn_credential";
81
+ /**
82
+ * Construit le descripteur d'entité du store de credentials pour un ORM nommé.
83
+ *
84
+ * Le `connector` est **dynamique** (nom du connecteur de l'app, ex. `"default"`) et la
85
+ * variante de table suit le dialecte du connecteur (auto-register
86
+ * `registerStores.ts` à `onKernelRegister`). À enregistrer **avant**
87
+ * `orm.connect()` (cf {@link registerWebAuthnCredentialEntity}).
88
+ *
89
+ * `module: "security"` → la table est regroupée sous @nodefony/security dans l'ERD
90
+ * Studio (le store est une feature security, hébergée par l'ORM de l'app).
91
+ *
92
+ * @param orm - clé de l'ORM cible dans le `ormRegistry`.
93
+ * @param dialect - dialecte SQL du connecteur (sélectionne la variante de table).
94
+ */
95
+ function createWebAuthnCredentialEntity(connector, dialect = "sqlite") {
96
+ return {
97
+ connector,
98
+ name: WEBAUTHN_CREDENTIAL_ENTITY,
99
+ module: "security",
100
+ schema: createWebAuthnCredentialTable(dialect)
101
+ };
102
+ }
103
+ /**
104
+ * Enregistre l'entité du store de credentials dans le `entityRegistry` pour un
105
+ * ORM donné. À appeler **avant** `orm.connect()` (l'adapter crée la table au connect).
106
+ *
107
+ * @param connector - nom de la connexion cible (clé du registre).
108
+ * @param dialect - dialecte SQL du connecteur (variante de table — défaut `sqlite`).
109
+ */
110
+ function registerWebAuthnCredentialEntity(connector, dialect = "sqlite") {
111
+ entityRegistry.register(createWebAuthnCredentialEntity(connector, dialect));
112
+ }
113
+ //#endregion
114
+ export { WEBAUTHN_CREDENTIAL_ENTITY, createWebAuthnCredentialEntity, createWebAuthnCredentialTable, registerWebAuthnCredentialEntity, webAuthnCredentialTable };
@@ -0,0 +1,106 @@
1
+ import { createFrameworkTableFactory } from "./colKit.js";
2
+ import { entityRegistry } from "@nodefony/orm-core";
3
+ /** Factory de la table des endpoints (mémoïsée — une instance par dialecte). */
4
+ const createWebhookEndpointTable = createFrameworkTableFactory({
5
+ name: "webhook_endpoint",
6
+ columns: {
7
+ /** Identifiant public stable (`wh_<random>`). */
8
+ id: {
9
+ kind: "text",
10
+ primaryKey: true
11
+ },
12
+ /** URL de destination (validée anti-SSRF à l'enregistrement). */
13
+ url: {
14
+ kind: "text",
15
+ notNull: true
16
+ },
17
+ /** Secret de signature **chiffré** au repos (blob `gcm1.…`). Jamais en clair. */
18
+ secretEnc: {
19
+ kind: "text",
20
+ notNull: true
21
+ },
22
+ /** Actions d'audit souscrites (`"*"` = toutes). */
23
+ events: {
24
+ kind: "json",
25
+ notNull: true,
26
+ defaultFn: () => []
27
+ },
28
+ /** Endpoint actif ? (désactivé = aucune livraison). */
29
+ enabled: {
30
+ kind: "bool",
31
+ notNull: true
32
+ },
33
+ /** Libellé humain optionnel (console admin) ; `null` = aucun. */
34
+ description: { kind: "text" },
35
+ /** Slot multi-tenant (réservé P17) — `null` = global. */
36
+ tenantId: { kind: "text" },
37
+ /** Identité de l'admin créateur (soft ref, traçabilité) ; `null` = inconnu. */
38
+ createdBy: { kind: "text" },
39
+ createdAt: {
40
+ kind: "epochMs",
41
+ notNull: true
42
+ },
43
+ updatedAt: {
44
+ kind: "epochMs",
45
+ notNull: true
46
+ },
47
+ /** Dernière tentative de livraison (epoch ms) ou `null`. */
48
+ lastDeliveryAt: { kind: "epochMs" },
49
+ /** Code HTTP de la dernière livraison, ou `null`. */
50
+ lastDeliveryStatus: { kind: "int" },
51
+ /** Message d'erreur de la dernière livraison, ou `null`. */
52
+ lastDeliveryError: { kind: "text" },
53
+ /** Échecs consécutifs (auto-désactivation au-delà d'un seuil). */
54
+ failureCount: {
55
+ kind: "int",
56
+ notNull: true
57
+ },
58
+ /** Métadonnées extensibles (jamais de secret). */
59
+ metadata: {
60
+ kind: "json",
61
+ notNull: true,
62
+ defaultFn: () => ({})
63
+ }
64
+ }
65
+ });
66
+ /**
67
+ * Variante SQLite de la table (dialecte par défaut) — export conservé pour
68
+ * l'usage direct/banc-test.
69
+ */
70
+ const webhookEndpointTable = createWebhookEndpointTable("sqlite");
71
+ /** Nom logique de l'entité (clé de lookup `getRepository`). */
72
+ const WEBHOOK_ENDPOINT_ENTITY = "webhook_endpoint";
73
+ /**
74
+ * Construit le descripteur d'entité du store webhook pour un ORM nommé.
75
+ *
76
+ * Le `connector` est **dynamique** (nom du connecteur de l'app, ex. `"default"`) et la
77
+ * variante de table suit le dialecte du connecteur (auto-register
78
+ * `registerStores.ts` à `onKernelRegister`). À enregistrer **avant**
79
+ * `orm.connect()`.
80
+ *
81
+ * `module: "security"` → la table est regroupée sous @nodefony/security dans
82
+ * l'ERD Studio (le store est une feature security, hébergée par l'ORM de l'app).
83
+ *
84
+ * @param orm - clé de l'ORM cible dans le `ormRegistry`.
85
+ * @param dialect - dialecte SQL du connecteur (sélectionne la variante de table).
86
+ */
87
+ function createWebhookEndpointEntity(connector, dialect = "sqlite") {
88
+ return {
89
+ connector,
90
+ name: WEBHOOK_ENDPOINT_ENTITY,
91
+ module: "security",
92
+ schema: createWebhookEndpointTable(dialect)
93
+ };
94
+ }
95
+ /**
96
+ * Enregistre l'entité du store webhook dans le `entityRegistry` pour un ORM
97
+ * donné. À appeler **avant** `orm.connect()` (l'adapter crée la table au connect).
98
+ *
99
+ * @param connector - nom de la connexion cible (clé du registre).
100
+ * @param dialect - dialecte SQL du connecteur (variante de table — défaut `sqlite`).
101
+ */
102
+ function registerWebhookEndpointEntity(connector, dialect = "sqlite") {
103
+ entityRegistry.register(createWebhookEndpointEntity(connector, dialect));
104
+ }
105
+ //#endregion
106
+ export { WEBHOOK_ENDPOINT_ENTITY, createWebhookEndpointEntity, createWebhookEndpointTable, registerWebhookEndpointEntity, webhookEndpointTable };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,48 @@
1
+ import { createAccessTokenTable, createDeniedJtiTable, createSubjectRevocationTable } from "../entity/tokenEntity.js";
2
+ import { createAuditEventTable } from "../entity/auditEventEntity.js";
3
+ import { createWebAuthnCredentialTable } from "../entity/webAuthnCredentialEntity.js";
4
+ import { createTotpSecretTable } from "../entity/totpSecretEntity.js";
5
+ import { createWebhookEndpointTable } from "../entity/webhookEndpointEntity.js";
6
+ import { createIdempotencyTable } from "../entity/idempotencyEntity.js";
7
+ import { createSessionTable } from "../entity/sessionEntity.js";
8
+ //#region nodefony/migrations-schema/mysql.ts
9
+ /**
10
+ * Schéma **matérialisé** des tables du framework pour le dialecte `mysql` — la
11
+ * seule entrée que `drizzle-kit` sait lire pour produire les migrations.
12
+ *
13
+ * ⚠️ **Trois contraintes de forme, mesurées, qu'une « factorisation » casserait
14
+ * en silence** :
15
+ *
16
+ * 1. **Un fichier PAR dialecte.** Le dialecte est figé dans la configuration de
17
+ * `drizzle-kit`, pas passé en argument : il ne peut pas y avoir de fichier
18
+ * unique paramétré.
19
+ * 2. **Des ré-exports PLATS.** `drizzle-kit` ne collecte que les tables exportées
20
+ * directement ; une table nichée dans un objet exporté est **ignorée sans un
21
+ * mot** (vérifié : un fichier exportant une table plate et une table nichée
22
+ * rend « 1 tables »). Regrouper ces dix constantes dans un objet ferait donc
23
+ * une migration VIDE, verte.
24
+ * 3. **Rien d'autre que ces exports.** Toute constante supplémentaire de type
25
+ * table entrerait dans la migration.
26
+ *
27
+ * ⚠️ **`User` n'y figure pas, et c'est une décision.** L'identité est du DOMAINE :
28
+ * la table appartient à l'APPLICATION, qui y ajoute ses champs et en porte les
29
+ * migrations. La livrer ici la rendrait « table du framework » — donc exclue du
30
+ * diff que l'application génère, en silence.
31
+ *
32
+ * Les trois fichiers sont volontairement identiques au dialecte près : ils ne
33
+ * portent aucune décision, seulement l'application des fabriques du `colKit`.
34
+ * La source de vérité reste la spécification de chaque entité — c'est elle qu'on
35
+ * modifie, jamais ce fichier, et le contrôle de dérive le vérifie.
36
+ */
37
+ const DIALECT = "mysql";
38
+ const accessToken = createAccessTokenTable(DIALECT);
39
+ const deniedJti = createDeniedJtiTable(DIALECT);
40
+ const subjectRevocation = createSubjectRevocationTable(DIALECT);
41
+ const session = createSessionTable(DIALECT);
42
+ const idempotencyKey = createIdempotencyTable(DIALECT);
43
+ const auditEvent = createAuditEventTable(DIALECT);
44
+ const totpSecret = createTotpSecretTable(DIALECT);
45
+ const webAuthnCredential = createWebAuthnCredentialTable(DIALECT);
46
+ const webhookEndpoint = createWebhookEndpointTable(DIALECT);
47
+ //#endregion
48
+ export { accessToken, auditEvent, deniedJti, idempotencyKey, session, subjectRevocation, totpSecret, webAuthnCredential, webhookEndpoint };
@@ -0,0 +1,48 @@
1
+ import { createAccessTokenTable, createDeniedJtiTable, createSubjectRevocationTable } from "../entity/tokenEntity.js";
2
+ import { createAuditEventTable } from "../entity/auditEventEntity.js";
3
+ import { createWebAuthnCredentialTable } from "../entity/webAuthnCredentialEntity.js";
4
+ import { createTotpSecretTable } from "../entity/totpSecretEntity.js";
5
+ import { createWebhookEndpointTable } from "../entity/webhookEndpointEntity.js";
6
+ import { createIdempotencyTable } from "../entity/idempotencyEntity.js";
7
+ import { createSessionTable } from "../entity/sessionEntity.js";
8
+ //#region nodefony/migrations-schema/postgres.ts
9
+ /**
10
+ * Schéma **matérialisé** des tables du framework pour le dialecte `postgres` — la
11
+ * seule entrée que `drizzle-kit` sait lire pour produire les migrations.
12
+ *
13
+ * ⚠️ **Trois contraintes de forme, mesurées, qu'une « factorisation » casserait
14
+ * en silence** :
15
+ *
16
+ * 1. **Un fichier PAR dialecte.** Le dialecte est figé dans la configuration de
17
+ * `drizzle-kit`, pas passé en argument : il ne peut pas y avoir de fichier
18
+ * unique paramétré.
19
+ * 2. **Des ré-exports PLATS.** `drizzle-kit` ne collecte que les tables exportées
20
+ * directement ; une table nichée dans un objet exporté est **ignorée sans un
21
+ * mot** (vérifié : un fichier exportant une table plate et une table nichée
22
+ * rend « 1 tables »). Regrouper ces dix constantes dans un objet ferait donc
23
+ * une migration VIDE, verte.
24
+ * 3. **Rien d'autre que ces exports.** Toute constante supplémentaire de type
25
+ * table entrerait dans la migration.
26
+ *
27
+ * ⚠️ **`User` n'y figure pas, et c'est une décision.** L'identité est du DOMAINE :
28
+ * la table appartient à l'APPLICATION, qui y ajoute ses champs et en porte les
29
+ * migrations. La livrer ici la rendrait « table du framework » — donc exclue du
30
+ * diff que l'application génère, en silence.
31
+ *
32
+ * Les trois fichiers sont volontairement identiques au dialecte près : ils ne
33
+ * portent aucune décision, seulement l'application des fabriques du `colKit`.
34
+ * La source de vérité reste la spécification de chaque entité — c'est elle qu'on
35
+ * modifie, jamais ce fichier, et le contrôle de dérive le vérifie.
36
+ */
37
+ const DIALECT = "postgres";
38
+ const accessToken = createAccessTokenTable(DIALECT);
39
+ const deniedJti = createDeniedJtiTable(DIALECT);
40
+ const subjectRevocation = createSubjectRevocationTable(DIALECT);
41
+ const session = createSessionTable(DIALECT);
42
+ const idempotencyKey = createIdempotencyTable(DIALECT);
43
+ const auditEvent = createAuditEventTable(DIALECT);
44
+ const totpSecret = createTotpSecretTable(DIALECT);
45
+ const webAuthnCredential = createWebAuthnCredentialTable(DIALECT);
46
+ const webhookEndpoint = createWebhookEndpointTable(DIALECT);
47
+ //#endregion
48
+ export { accessToken, auditEvent, deniedJti, idempotencyKey, session, subjectRevocation, totpSecret, webAuthnCredential, webhookEndpoint };
@@ -0,0 +1,48 @@
1
+ import { createAccessTokenTable, createDeniedJtiTable, createSubjectRevocationTable } from "../entity/tokenEntity.js";
2
+ import { createAuditEventTable } from "../entity/auditEventEntity.js";
3
+ import { createWebAuthnCredentialTable } from "../entity/webAuthnCredentialEntity.js";
4
+ import { createTotpSecretTable } from "../entity/totpSecretEntity.js";
5
+ import { createWebhookEndpointTable } from "../entity/webhookEndpointEntity.js";
6
+ import { createIdempotencyTable } from "../entity/idempotencyEntity.js";
7
+ import { createSessionTable } from "../entity/sessionEntity.js";
8
+ //#region nodefony/migrations-schema/sqlite.ts
9
+ /**
10
+ * Schéma **matérialisé** des tables du framework pour le dialecte `sqlite` — la
11
+ * seule entrée que `drizzle-kit` sait lire pour produire les migrations.
12
+ *
13
+ * ⚠️ **Trois contraintes de forme, mesurées, qu'une « factorisation » casserait
14
+ * en silence** :
15
+ *
16
+ * 1. **Un fichier PAR dialecte.** Le dialecte est figé dans la configuration de
17
+ * `drizzle-kit`, pas passé en argument : il ne peut pas y avoir de fichier
18
+ * unique paramétré.
19
+ * 2. **Des ré-exports PLATS.** `drizzle-kit` ne collecte que les tables exportées
20
+ * directement ; une table nichée dans un objet exporté est **ignorée sans un
21
+ * mot** (vérifié : un fichier exportant une table plate et une table nichée
22
+ * rend « 1 tables »). Regrouper ces dix constantes dans un objet ferait donc
23
+ * une migration VIDE, verte.
24
+ * 3. **Rien d'autre que ces exports.** Toute constante supplémentaire de type
25
+ * table entrerait dans la migration.
26
+ *
27
+ * ⚠️ **`User` n'y figure pas, et c'est une décision.** L'identité est du DOMAINE :
28
+ * la table appartient à l'APPLICATION, qui y ajoute ses champs et en porte les
29
+ * migrations. La livrer ici la rendrait « table du framework » — donc exclue du
30
+ * diff que l'application génère, en silence.
31
+ *
32
+ * Les trois fichiers sont volontairement identiques au dialecte près : ils ne
33
+ * portent aucune décision, seulement l'application des fabriques du `colKit`.
34
+ * La source de vérité reste la spécification de chaque entité — c'est elle qu'on
35
+ * modifie, jamais ce fichier, et le contrôle de dérive le vérifie.
36
+ */
37
+ const DIALECT = "sqlite";
38
+ const accessToken = createAccessTokenTable(DIALECT);
39
+ const deniedJti = createDeniedJtiTable(DIALECT);
40
+ const subjectRevocation = createSubjectRevocationTable(DIALECT);
41
+ const session = createSessionTable(DIALECT);
42
+ const idempotencyKey = createIdempotencyTable(DIALECT);
43
+ const auditEvent = createAuditEventTable(DIALECT);
44
+ const totpSecret = createTotpSecretTable(DIALECT);
45
+ const webAuthnCredential = createWebAuthnCredentialTable(DIALECT);
46
+ const webhookEndpoint = createWebhookEndpointTable(DIALECT);
47
+ //#endregion
48
+ export { accessToken, auditEvent, deniedJti, idempotencyKey, session, subjectRevocation, totpSecret, webAuthnCredential, webhookEndpoint };