@noormdev/sdk 1.0.0-alpha.15 → 1.0.0-alpha.17
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/{chunk-ZRZ7AECF.js → chunk-LJDHQEWW.js} +63 -25
- package/dist/chunk-LJDHQEWW.js.map +1 -0
- package/dist/index.d.ts +30 -16
- package/dist/index.js +399 -137
- package/dist/index.js.map +1 -1
- package/dist/mssql-7VB7EHRX.js +81 -0
- package/dist/mssql-7VB7EHRX.js.map +1 -0
- package/dist/{storage-FJP4ED7H.js → storage-NDKBEHIZ.js} +3 -3
- package/dist/{storage-FJP4ED7H.js.map → storage-NDKBEHIZ.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-ZRZ7AECF.js.map +0 -1
- package/dist/mssql-T4M7OGEC.js +0 -46
- package/dist/mssql-T4M7OGEC.js.map +0 -1
|
@@ -17,6 +17,26 @@ var NOORM_TABLES = Object.freeze({
|
|
|
17
17
|
/** Vault secrets table */
|
|
18
18
|
vault: "__noorm_vault__"
|
|
19
19
|
});
|
|
20
|
+
var SCHEMA_TABLES = Object.freeze({
|
|
21
|
+
version: "version",
|
|
22
|
+
change: "change",
|
|
23
|
+
executions: "executions",
|
|
24
|
+
lock: "lock",
|
|
25
|
+
identities: "identities",
|
|
26
|
+
vault: "vault"
|
|
27
|
+
});
|
|
28
|
+
function getNoormTables(dialect) {
|
|
29
|
+
if (dialect === "postgres" || dialect === "mssql") {
|
|
30
|
+
return SCHEMA_TABLES;
|
|
31
|
+
}
|
|
32
|
+
return NOORM_TABLES;
|
|
33
|
+
}
|
|
34
|
+
function noormDb(db, dialect) {
|
|
35
|
+
if (dialect === "postgres" || dialect === "mssql") {
|
|
36
|
+
return db.withSchema("noorm");
|
|
37
|
+
}
|
|
38
|
+
return db;
|
|
39
|
+
}
|
|
20
40
|
function generateVaultKey() {
|
|
21
41
|
return randomBytes(32);
|
|
22
42
|
}
|
|
@@ -116,9 +136,11 @@ function decryptSecret(encrypted, vaultKey) {
|
|
|
116
136
|
}
|
|
117
137
|
|
|
118
138
|
// src/core/vault/storage.ts
|
|
119
|
-
async function initializeVault(db, identityHash, publicKey) {
|
|
139
|
+
async function initializeVault(db, identityHash, publicKey, dialect) {
|
|
140
|
+
const ndb = noormDb(db, dialect);
|
|
141
|
+
const tables = getNoormTables(dialect);
|
|
120
142
|
const [existing, checkErr] = await attempt(async () => {
|
|
121
|
-
return
|
|
143
|
+
return ndb.selectFrom(tables.identities).select("encrypted_vault_key").where("encrypted_vault_key", "is not", null).limit(1).executeTakeFirst();
|
|
122
144
|
});
|
|
123
145
|
if (checkErr) return [null, checkErr];
|
|
124
146
|
if (existing?.encrypted_vault_key) {
|
|
@@ -128,15 +150,17 @@ async function initializeVault(db, identityHash, publicKey) {
|
|
|
128
150
|
const encrypted = encryptVaultKey(vaultKey, publicKey);
|
|
129
151
|
const encryptedJson = JSON.stringify(encrypted);
|
|
130
152
|
const [, updateErr] = await attempt(async () => {
|
|
131
|
-
return
|
|
153
|
+
return ndb.updateTable(tables.identities).set({ encrypted_vault_key: encryptedJson }).where("identity_hash", "=", identityHash).execute();
|
|
132
154
|
});
|
|
133
155
|
if (updateErr) return [null, updateErr];
|
|
134
156
|
observer.emit("vault:initialized", { identityHash });
|
|
135
157
|
return [vaultKey, null];
|
|
136
158
|
}
|
|
137
|
-
async function getVaultKey(db, identityHash, privateKey) {
|
|
159
|
+
async function getVaultKey(db, identityHash, privateKey, dialect) {
|
|
160
|
+
const ndb = noormDb(db, dialect);
|
|
161
|
+
const tables = getNoormTables(dialect);
|
|
138
162
|
const [row, err] = await attempt(async () => {
|
|
139
|
-
return
|
|
163
|
+
return ndb.selectFrom(tables.identities).select("encrypted_vault_key").where("identity_hash", "=", identityHash).executeTakeFirst();
|
|
140
164
|
});
|
|
141
165
|
if (err || !row?.encrypted_vault_key) return null;
|
|
142
166
|
const encryptedValue = row.encrypted_vault_key;
|
|
@@ -146,17 +170,19 @@ async function getVaultKey(db, identityHash, privateKey) {
|
|
|
146
170
|
if (parseErr) return null;
|
|
147
171
|
return decryptVaultKey(parsed, privateKey);
|
|
148
172
|
}
|
|
149
|
-
async function setVaultSecret(db, vaultKey, secretKey, value, setBy) {
|
|
173
|
+
async function setVaultSecret(db, vaultKey, secretKey, value, setBy, dialect) {
|
|
174
|
+
const ndb = noormDb(db, dialect);
|
|
175
|
+
const tables = getNoormTables(dialect);
|
|
150
176
|
const encrypted = encryptSecret(value, vaultKey);
|
|
151
177
|
const encryptedJson = JSON.stringify(encrypted);
|
|
152
178
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
153
179
|
const [existing, checkErr] = await attempt(async () => {
|
|
154
|
-
return
|
|
180
|
+
return ndb.selectFrom(tables.vault).select("id").where("secret_key", "=", secretKey).executeTakeFirst();
|
|
155
181
|
});
|
|
156
182
|
if (checkErr) return [void 0, checkErr];
|
|
157
183
|
if (existing) {
|
|
158
184
|
const [, updateErr] = await attempt(async () => {
|
|
159
|
-
return
|
|
185
|
+
return ndb.updateTable(tables.vault).set({
|
|
160
186
|
encrypted_value: encryptedJson,
|
|
161
187
|
set_by: setBy,
|
|
162
188
|
updated_at: now
|
|
@@ -166,7 +192,7 @@ async function setVaultSecret(db, vaultKey, secretKey, value, setBy) {
|
|
|
166
192
|
observer.emit("vault:secret:updated", { key: secretKey, setBy });
|
|
167
193
|
} else {
|
|
168
194
|
const [, insertErr] = await attempt(async () => {
|
|
169
|
-
return
|
|
195
|
+
return ndb.insertInto(tables.vault).values({
|
|
170
196
|
secret_key: secretKey,
|
|
171
197
|
encrypted_value: encryptedJson,
|
|
172
198
|
set_by: setBy
|
|
@@ -177,9 +203,11 @@ async function setVaultSecret(db, vaultKey, secretKey, value, setBy) {
|
|
|
177
203
|
}
|
|
178
204
|
return [void 0, null];
|
|
179
205
|
}
|
|
180
|
-
async function getVaultSecret(db, vaultKey, secretKey) {
|
|
206
|
+
async function getVaultSecret(db, vaultKey, secretKey, dialect) {
|
|
207
|
+
const ndb = noormDb(db, dialect);
|
|
208
|
+
const tables = getNoormTables(dialect);
|
|
181
209
|
const [row, err] = await attempt(async () => {
|
|
182
|
-
return
|
|
210
|
+
return ndb.selectFrom(tables.vault).select("encrypted_value").where("secret_key", "=", secretKey).executeTakeFirst();
|
|
183
211
|
});
|
|
184
212
|
if (err || !row) return null;
|
|
185
213
|
const [parsed, parseErr] = attemptSync(
|
|
@@ -188,9 +216,11 @@ async function getVaultSecret(db, vaultKey, secretKey) {
|
|
|
188
216
|
if (parseErr) return null;
|
|
189
217
|
return decryptSecret(parsed, vaultKey);
|
|
190
218
|
}
|
|
191
|
-
async function getAllVaultSecrets(db, vaultKey) {
|
|
219
|
+
async function getAllVaultSecrets(db, vaultKey, dialect) {
|
|
220
|
+
const ndb = noormDb(db, dialect);
|
|
221
|
+
const tables = getNoormTables(dialect);
|
|
192
222
|
const [rows, err] = await attempt(async () => {
|
|
193
|
-
return
|
|
223
|
+
return ndb.selectFrom(tables.vault).selectAll().execute();
|
|
194
224
|
});
|
|
195
225
|
if (err || !rows) return {};
|
|
196
226
|
const secrets = {};
|
|
@@ -211,16 +241,20 @@ async function getAllVaultSecrets(db, vaultKey) {
|
|
|
211
241
|
}
|
|
212
242
|
return secrets;
|
|
213
243
|
}
|
|
214
|
-
async function listVaultSecretKeys(db) {
|
|
244
|
+
async function listVaultSecretKeys(db, dialect) {
|
|
245
|
+
const ndb = noormDb(db, dialect);
|
|
246
|
+
const tables = getNoormTables(dialect);
|
|
215
247
|
const [rows, err] = await attempt(async () => {
|
|
216
|
-
return
|
|
248
|
+
return ndb.selectFrom(tables.vault).select("secret_key").orderBy("secret_key", "asc").execute();
|
|
217
249
|
});
|
|
218
250
|
if (err || !rows) return [];
|
|
219
251
|
return rows.map((r) => r.secret_key);
|
|
220
252
|
}
|
|
221
|
-
async function deleteVaultSecret(db, secretKey) {
|
|
253
|
+
async function deleteVaultSecret(db, secretKey, dialect) {
|
|
254
|
+
const ndb = noormDb(db, dialect);
|
|
255
|
+
const tables = getNoormTables(dialect);
|
|
222
256
|
const [result, err] = await attempt(async () => {
|
|
223
|
-
return
|
|
257
|
+
return ndb.deleteFrom(tables.vault).where("secret_key", "=", secretKey).execute();
|
|
224
258
|
});
|
|
225
259
|
if (err || !result) return [false, err ?? new Error("Delete failed")];
|
|
226
260
|
const firstResult = result[0];
|
|
@@ -230,20 +264,24 @@ async function deleteVaultSecret(db, secretKey) {
|
|
|
230
264
|
}
|
|
231
265
|
return [deleted, null];
|
|
232
266
|
}
|
|
233
|
-
async function vaultSecretExists(db, secretKey) {
|
|
267
|
+
async function vaultSecretExists(db, secretKey, dialect) {
|
|
268
|
+
const ndb = noormDb(db, dialect);
|
|
269
|
+
const tables = getNoormTables(dialect);
|
|
234
270
|
const [row, err] = await attempt(async () => {
|
|
235
|
-
return
|
|
271
|
+
return ndb.selectFrom(tables.vault).select("id").where("secret_key", "=", secretKey).executeTakeFirst();
|
|
236
272
|
});
|
|
237
273
|
if (err) return false;
|
|
238
274
|
return !!row;
|
|
239
275
|
}
|
|
240
|
-
async function getVaultStatus(db, identityHash) {
|
|
276
|
+
async function getVaultStatus(db, identityHash, dialect) {
|
|
277
|
+
const ndb = noormDb(db, dialect);
|
|
278
|
+
const tables = getNoormTables(dialect);
|
|
241
279
|
const [secretRows] = await attempt(async () => {
|
|
242
|
-
return
|
|
280
|
+
return ndb.selectFrom(tables.vault).select(ndb.fn.count("id").as("count")).executeTakeFirst();
|
|
243
281
|
});
|
|
244
282
|
const secretCount = secretRows ? Number(secretRows.count) : 0;
|
|
245
283
|
const [identityRows] = await attempt(async () => {
|
|
246
|
-
return
|
|
284
|
+
return ndb.selectFrom(tables.identities).select([
|
|
247
285
|
"identity_hash",
|
|
248
286
|
"encrypted_vault_key"
|
|
249
287
|
]).execute();
|
|
@@ -263,6 +301,6 @@ async function getVaultStatus(db, identityHash) {
|
|
|
263
301
|
};
|
|
264
302
|
}
|
|
265
303
|
|
|
266
|
-
export {
|
|
267
|
-
//# sourceMappingURL=chunk-
|
|
268
|
-
//# sourceMappingURL=chunk-
|
|
304
|
+
export { deleteVaultSecret, encryptVaultKey, getAllVaultSecrets, getNoormTables, getVaultKey, getVaultSecret, getVaultStatus, initializeVault, listVaultSecretKeys, noormDb, setVaultSecret, vaultSecretExists };
|
|
305
|
+
//# sourceMappingURL=chunk-LJDHQEWW.js.map
|
|
306
|
+
//# sourceMappingURL=chunk-LJDHQEWW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/core/shared/tables.ts","../../../src/core/vault/key.ts","../../../src/core/vault/storage.ts"],"names":["attemptSync"],"mappings":"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","file":"chunk-LJDHQEWW.js","sourcesContent":["/**\n * Kysely table types for noorm tracking tables.\n *\n * These types define the shape of the database tables used by noorm\n * to track changes, executions, locks, identities, and versions.\n *\n * For full schema documentation, see plan/datamodel.md\n *\n * WHY: Kysely uses these types to provide type-safe queries.\n * They match the database schema created by migrations.\n */\nimport type { Generated, Insertable, Kysely, Selectable, Updateable } from 'kysely';\n\nimport type { Dialect } from '../connection/types.js';\n\n// ─────────────────────────────────────────────────────────────\n// Table Names\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Noorm tracking table names.\n *\n * Use these constants instead of hardcoding table names.\n *\n * @deprecated Use `getNoormTables(dialect)` instead. This constant maps to prefixed\n * names and will produce incorrect SQL when used with `noormDb()` on pg/mssql.\n *\n * @example\n * ```typescript\n * import { NOORM_TABLES } from './shared'\n *\n * await db.selectFrom(NOORM_TABLES.version).selectAll().execute()\n * ```\n */\nexport const NOORM_TABLES = Object.freeze({\n /** Version tracking table */\n version: '__noorm_version__' as const,\n\n /** Change/operation tracking table */\n change: '__noorm_change__' as const,\n\n /** File execution tracking table */\n executions: '__noorm_executions__' as const,\n\n /** Concurrent operation lock table */\n lock: '__noorm_lock__' as const,\n\n /** Team member identity table */\n identities: '__noorm_identities__' as const,\n\n /** Vault secrets table */\n vault: '__noorm_vault__' as const,\n});\n\n/**\n * Shape returned by getNoormTables().\n */\nexport type NoormTableNames = {\n\n version: string;\n change: string;\n executions: string;\n lock: string;\n identities: string;\n vault: string;\n\n};\n\n/**\n * Schema-qualified table names for pg/mssql.\n *\n * Used with withSchema('noorm') — table names have no prefix.\n */\nconst SCHEMA_TABLES = Object.freeze({\n version: 'version' as const,\n change: 'change' as const,\n executions: 'executions' as const,\n lock: 'lock' as const,\n identities: 'identities' as const,\n vault: 'vault' as const,\n});\n\n/**\n * Get dialect-appropriate noorm table names.\n *\n * pg/mssql: clean names used with withSchema('noorm').\n * sqlite/mysql: prefixed names used directly.\n *\n * Returns the concrete const type so Kysely can narrow table names\n * for type-safe selectFrom() calls.\n *\n * @example\n * ```typescript\n * const tables = getNoormTables('postgres');\n * const ndb = noormDb(db, 'postgres');\n * await ndb.selectFrom(tables.change).selectAll().execute();\n * ```\n */\nexport function getNoormTables(dialect: Dialect): typeof SCHEMA_TABLES | typeof NOORM_TABLES {\n\n if (dialect === 'postgres' || dialect === 'mssql') {\n\n return SCHEMA_TABLES;\n\n }\n\n return NOORM_TABLES;\n\n}\n\n/**\n * Get a Kysely instance scoped to the noorm schema.\n *\n * pg/mssql: wraps with withSchema('noorm') so all table references\n * are prefixed with the noorm schema.\n * sqlite/mysql: returns the db as-is.\n *\n * @example\n * ```typescript\n * const ndb = noormDb(db, 'postgres');\n * await ndb.selectFrom('change').selectAll().execute();\n * // SQL: SELECT * FROM \"noorm\".\"change\"\n * ```\n */\nexport function noormDb(\n db: Kysely<NoormDatabase>,\n dialect: Dialect,\n): Kysely<NoormDatabase> {\n\n if (dialect === 'postgres' || dialect === 'mssql') {\n\n return db.withSchema('noorm') as Kysely<NoormDatabase>;\n\n }\n\n return db;\n\n}\n\n/**\n * Type for prefixed noorm table names (sqlite/mysql).\n *\n * Only includes the `__noorm_*__` prefixed names from NOORM_TABLES.\n * For pg/mssql schema-qualified names, use NoormSchemaTableName.\n */\nexport type NoormTableName = (typeof NOORM_TABLES)[keyof typeof NOORM_TABLES];\n\n/**\n * Type for schema-qualified noorm table names (pg/mssql).\n *\n * Clean names used with withSchema('noorm').\n */\nexport type NoormSchemaTableName = (typeof SCHEMA_TABLES)[keyof typeof SCHEMA_TABLES];\n\n// ─────────────────────────────────────────────────────────────\n// __noorm_version__\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Version tracking table.\n *\n * Tracks noorm CLI version and all internal schema versions for migrations.\n * See: plan/datamodel.md#__noorm_version__\n */\nexport interface NoormVersionTable {\n /** Primary key */\n id: Generated<number>;\n\n /** CLI semver (e.g., \"1.2.3\") */\n cli_version: string;\n\n /** Database tracking tables version */\n noorm_version: number;\n\n /** State file (state.enc) schema version */\n state_version: number;\n\n /** Settings file (settings.yml) schema version */\n settings_version: number;\n\n /** First installation timestamp */\n installed_at: Generated<Date>;\n\n /** Last upgrade timestamp */\n upgraded_at: Generated<Date>;\n}\n\nexport type NoormVersion = Selectable<NoormVersionTable>;\nexport type NewNoormVersion = Insertable<NoormVersionTable>;\nexport type NoormVersionUpdate = Updateable<NoormVersionTable>;\n\n// ─────────────────────────────────────────────────────────────\n// __noorm_change__\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Operation status values.\n *\n * - pending: Operation started but not finished\n * - success: Operation completed successfully\n * - failed: Operation failed with error\n * - reverted: Operation was reverted\n * - stale: Operation's schema objects were torn down (needs re-run)\n */\nexport type OperationStatus = 'pending' | 'success' | 'failed' | 'reverted' | 'stale';\n\n/**\n * Change type values.\n */\nexport type ChangeType = 'build' | 'run' | 'change';\n\n/**\n * Direction values.\n */\nexport type Direction = 'change' | 'revert';\n\n/**\n * Change tracking table.\n *\n * Tracks all operation batches—changes, builds, and ad-hoc runs.\n * See: plan/datamodel.md#__noorm_change__\n */\nexport interface NoormChangeTable {\n /** Primary key */\n id: Generated<number>;\n\n /** Operation identifier */\n name: string;\n\n /** 'build', 'run', or 'change' */\n change_type: ChangeType;\n\n /** 'change' or 'revert' */\n direction: Direction;\n\n /** SHA-256 of sorted file checksums */\n checksum: Generated<string>;\n\n /** When executed */\n executed_at: Generated<Date>;\n\n /** Identity string */\n executed_by: Generated<string>;\n\n /** Which config was used */\n config_name: Generated<string>;\n\n /** noorm version */\n cli_version: Generated<string>;\n\n /** 'pending', 'success', 'failed', 'reverted' */\n status: OperationStatus;\n\n /** Error details (empty = no error) */\n error_message: Generated<string>;\n\n /** Execution time (0 = never ran) */\n duration_ms: Generated<number>;\n}\n\nexport type NoormChange = Selectable<NoormChangeTable>;\nexport type NewNoormChange = Insertable<NoormChangeTable>;\nexport type NoormChangeUpdate = Updateable<NoormChangeTable>;\n\n// ─────────────────────────────────────────────────────────────\n// __noorm_executions__\n// ─────────────────────────────────────────────────────────────\n\n/**\n * File execution status values.\n */\nexport type ExecutionStatus = 'pending' | 'success' | 'failed' | 'skipped';\n\n/**\n * File type values.\n */\nexport type FileType = 'sql' | 'txt';\n\n/**\n * Executions tracking table.\n *\n * Tracks individual file executions within an operation.\n * See: plan/datamodel.md#__noorm_executions__\n */\nexport interface NoormExecutionsTable {\n /** Primary key */\n id: Generated<number>;\n\n /** Parent operation (FK to __noorm_change__) */\n change_id: number;\n\n /** File that was executed */\n filepath: string;\n\n /** 'sql' or 'txt' */\n file_type: FileType;\n\n /** SHA-256 of file contents */\n checksum: Generated<string>;\n\n /** noorm version */\n cli_version: Generated<string>;\n\n /** 'pending', 'success', 'failed', 'skipped' */\n status: ExecutionStatus;\n\n /** Error details (empty = no error) */\n error_message: Generated<string>;\n\n /** 'unchanged', 'already-run', 'change failed' */\n skip_reason: Generated<string>;\n\n /** Execution time (0 = never ran) */\n duration_ms: Generated<number>;\n}\n\nexport type NoormExecution = Selectable<NoormExecutionsTable>;\nexport type NewNoormExecution = Insertable<NoormExecutionsTable>;\nexport type NoormExecutionUpdate = Updateable<NoormExecutionsTable>;\n\n// ─────────────────────────────────────────────────────────────\n// __noorm_lock__\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Lock table.\n *\n * Prevents concurrent operations on the same database.\n * See: plan/datamodel.md#__noorm_lock__\n */\nexport interface NoormLockTable {\n /** Primary key */\n id: Generated<number>;\n\n /** Lock scope (config name) */\n config_name: string;\n\n /** Identity of holder */\n locked_by: string;\n\n /** When acquired */\n locked_at: Generated<Date>;\n\n /** Auto-expiry time */\n expires_at: Date;\n\n /** Lock reason (empty = none) */\n reason: Generated<string>;\n}\n\nexport type NoormLock = Selectable<NoormLockTable>;\nexport type NewNoormLock = Insertable<NoormLockTable>;\nexport type NoormLockUpdate = Updateable<NoormLockTable>;\n\n// ─────────────────────────────────────────────────────────────\n// __noorm_identities__\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Identities table.\n *\n * Stores user identities for team discovery.\n * Auto-populated on first connect when identity is set up.\n * See: plan/datamodel.md#__noorm_identities__\n */\nexport interface NoormIdentitiesTable {\n /** Primary key */\n id: Generated<number>;\n\n /** SHA-256(email + name + machine + os) */\n identity_hash: string;\n\n /** User email */\n email: string;\n\n /** Display name */\n name: string;\n\n /** Machine hostname */\n machine: string;\n\n /** OS platform and version */\n os: string;\n\n /** X25519 public key (hex) */\n public_key: string;\n\n /** First registration */\n registered_at: Generated<Date>;\n\n /** Last activity */\n last_seen_at: Generated<Date>;\n\n /** Vault key encrypted with user's public key (nullable for users without vault access) */\n encrypted_vault_key: string | null;\n}\n\nexport type NoormIdentity = Selectable<NoormIdentitiesTable>;\nexport type NewNoormIdentity = Insertable<NoormIdentitiesTable>;\nexport type NoormIdentityUpdate = Updateable<NoormIdentitiesTable>;\n\n// ─────────────────────────────────────────────────────────────\n// __noorm_vault__\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Vault secrets table.\n *\n * Stores encrypted secrets shared across the team.\n * Secrets are encrypted with a vault key that is distributed\n * to team members via their public keys.\n */\nexport interface NoormVaultTable {\n /** Primary key */\n id: Generated<number>;\n\n /** Secret key name (e.g., 'API_KEY', 'DB_PASSWORD') */\n secret_key: string;\n\n /** AES-256-GCM encrypted value (JSON: {iv, authTag, ciphertext}) */\n encrypted_value: string;\n\n /** Identity who set this secret */\n set_by: string;\n\n /** When created */\n created_at: Generated<Date>;\n\n /** When last updated */\n updated_at: Generated<Date>;\n}\n\nexport type NoormVault = Selectable<NoormVaultTable>;\nexport type NewNoormVault = Insertable<NoormVaultTable>;\nexport type NoormVaultUpdate = Updateable<NoormVaultTable>;\n\n// ─────────────────────────────────────────────────────────────\n// Combined Database Interface\n// ─────────────────────────────────────────────────────────────\n\n/**\n * Schema-qualified database interface for pg/mssql.\n *\n * Used with db.withSchema('noorm') — table names have no prefix.\n */\nexport interface NoormSchemaDb {\n\n version: NoormVersionTable;\n change: NoormChangeTable;\n executions: NoormExecutionsTable;\n lock: NoormLockTable;\n identities: NoormIdentitiesTable;\n vault: NoormVaultTable;\n\n}\n\n/**\n * Prefixed database interface for sqlite/mysql.\n *\n * Used directly — table names have __noorm_ prefix.\n */\nexport interface NoormPrefixDb {\n\n __noorm_version__: NoormVersionTable;\n __noorm_change__: NoormChangeTable;\n __noorm_executions__: NoormExecutionsTable;\n __noorm_lock__: NoormLockTable;\n __noorm_identities__: NoormIdentitiesTable;\n __noorm_vault__: NoormVaultTable;\n\n}\n\n/**\n * Combined database interface for all noorm tracking tables.\n *\n * Intersection of schema-qualified (pg/mssql) and prefixed (sqlite/mysql)\n * interfaces. Both key sets are valid — use getNoormTables(dialect) to get\n * the correct keys for your dialect.\n *\n * @example\n * ```typescript\n * const tables = getNoormTables(dialect);\n * const ndb = noormDb(db, dialect);\n * await ndb.selectFrom(tables.change).selectAll().execute();\n * ```\n */\nexport type NoormDatabase = NoormSchemaDb & NoormPrefixDb;\n","/**\n * Vault key management.\n *\n * Generates, encrypts, and decrypts the vault key.\n * The vault key is a 256-bit symmetric key used to encrypt vault secrets.\n * Each user's copy is encrypted with their public key.\n */\nimport {\n randomBytes,\n createCipheriv,\n createDecipheriv,\n createPrivateKey,\n createPublicKey,\n diffieHellman,\n generateKeyPairSync,\n hkdfSync,\n} from 'crypto';\n\nimport { attemptSync } from '@logosdx/utils';\n\nimport type { EncryptedVaultKey } from './types.js';\n\n/**\n * Generate a new 256-bit vault key.\n *\n * Called once during vault initialization by the first user.\n *\n * @example\n * ```typescript\n * const vaultKey = generateVaultKey();\n * // vaultKey is 32 bytes of cryptographically secure random data\n * ```\n */\nexport function generateVaultKey(): Buffer {\n\n return randomBytes(32);\n\n}\n\n/**\n * Derive shared secret from private key and public key using X25519 ECDH.\n */\nfunction deriveSharedSecret(privateKeyHex: string, publicKeyHex: string): Buffer {\n\n const privateKey = createPrivateKey({\n key: Buffer.from(privateKeyHex, 'hex'),\n format: 'der',\n type: 'pkcs8',\n });\n\n const publicKey = createPublicKey({\n key: Buffer.from(publicKeyHex, 'hex'),\n format: 'der',\n type: 'spki',\n });\n\n return diffieHellman({\n privateKey,\n publicKey,\n });\n\n}\n\n/**\n * Derive encryption key from shared secret using HKDF.\n */\nfunction deriveEncryptionKey(sharedSecret: Buffer, info: string): Buffer {\n\n return Buffer.from(\n hkdfSync(\n 'sha256',\n sharedSecret,\n Buffer.alloc(0),\n info,\n 32,\n ),\n );\n\n}\n\n/**\n * Encrypt vault key for a recipient using their public key.\n *\n * Uses the ephemeral keypair pattern:\n * 1. Generate ephemeral X25519 keypair\n * 2. ECDH with recipient's public key\n * 3. HKDF to derive encryption key\n * 4. AES-256-GCM encryption\n *\n * @param vaultKey - The 32-byte vault key to encrypt\n * @param recipientPubKey - Recipient's X25519 public key (hex)\n *\n * @example\n * ```typescript\n * const encrypted = encryptVaultKey(vaultKey, userPublicKey);\n * // Store encrypted in user's encrypted_vault_key column\n * ```\n */\nexport function encryptVaultKey(vaultKey: Buffer, recipientPubKey: string): EncryptedVaultKey {\n\n // Generate ephemeral keypair for this encryption\n const { publicKey, privateKey } = generateKeyPairSync('x25519', {\n publicKeyEncoding: { type: 'spki', format: 'der' },\n privateKeyEncoding: { type: 'pkcs8', format: 'der' },\n });\n\n const ephemeralPrivateHex = privateKey.toString('hex');\n const ephemeralPublicHex = publicKey.toString('hex');\n\n // Derive shared secret via ECDH\n const sharedSecret = deriveSharedSecret(ephemeralPrivateHex, recipientPubKey);\n\n // Derive encryption key\n const encKey = deriveEncryptionKey(sharedSecret, 'noorm-vault-key');\n\n // Generate random IV\n const iv = randomBytes(16);\n\n // Encrypt with AES-256-GCM\n const cipher = createCipheriv('aes-256-gcm', encKey, iv);\n const ciphertext = Buffer.concat([cipher.update(vaultKey), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n return {\n ephemeralPubKey: ephemeralPublicHex,\n iv: iv.toString('hex'),\n authTag: authTag.toString('hex'),\n ciphertext: ciphertext.toString('hex'),\n };\n\n}\n\n/**\n * Decrypt vault key using the user's private key.\n *\n * Reverses the ephemeral keypair pattern:\n * 1. ECDH with ephemeral public key and user's private key\n * 2. HKDF to derive decryption key\n * 3. AES-256-GCM decryption\n *\n * @param encrypted - The encrypted vault key payload\n * @param privateKey - User's X25519 private key (hex)\n * @returns The decrypted vault key, or null if decryption fails\n *\n * @example\n * ```typescript\n * const vaultKey = decryptVaultKey(encrypted, userPrivateKey);\n * if (!vaultKey) {\n * console.error('Failed to decrypt vault key');\n * }\n * ```\n */\nexport function decryptVaultKey(\n encrypted: EncryptedVaultKey,\n privateKey: string,\n): Buffer | null {\n\n const [result, err] = attemptSync(() => {\n\n // Derive shared secret from ephemeral pub + user's private\n const sharedSecret = deriveSharedSecret(privateKey, encrypted.ephemeralPubKey);\n\n // Derive decryption key\n const decKey = deriveEncryptionKey(sharedSecret, 'noorm-vault-key');\n\n // Decrypt\n const decipher = createDecipheriv(\n 'aes-256-gcm',\n decKey,\n Buffer.from(encrypted.iv, 'hex'),\n );\n decipher.setAuthTag(Buffer.from(encrypted.authTag, 'hex'));\n\n const vaultKey = Buffer.concat([\n decipher.update(Buffer.from(encrypted.ciphertext, 'hex')),\n decipher.final(),\n ]);\n\n return vaultKey;\n\n });\n\n if (err) return null;\n\n return result;\n\n}\n\n/**\n * Encrypt a secret value with the vault key.\n *\n * Uses AES-256-GCM for authenticated encryption.\n *\n * @param value - The plaintext secret value\n * @param vaultKey - The 32-byte vault key\n *\n * @example\n * ```typescript\n * const encrypted = encryptSecret('my-api-key', vaultKey);\n * // Store JSON.stringify(encrypted) in encrypted_value column\n * ```\n */\nexport function encryptSecret(\n value: string,\n vaultKey: Buffer,\n): { iv: string; authTag: string; ciphertext: string } {\n\n const iv = randomBytes(16);\n const cipher = createCipheriv('aes-256-gcm', vaultKey, iv);\n const ciphertext = Buffer.concat([cipher.update(value, 'utf8'), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n return {\n iv: iv.toString('hex'),\n authTag: authTag.toString('hex'),\n ciphertext: ciphertext.toString('hex'),\n };\n\n}\n\n/**\n * Decrypt a secret value with the vault key.\n *\n * @param encrypted - The encrypted secret payload\n * @param vaultKey - The 32-byte vault key\n * @returns The decrypted value, or null if decryption fails\n *\n * @example\n * ```typescript\n * const value = decryptSecret(encrypted, vaultKey);\n * if (!value) {\n * console.error('Failed to decrypt secret');\n * }\n * ```\n */\nexport function decryptSecret(\n encrypted: { iv: string; authTag: string; ciphertext: string },\n vaultKey: Buffer,\n): string | null {\n\n const [result, err] = attemptSync(() => {\n\n const decipher = createDecipheriv(\n 'aes-256-gcm',\n vaultKey,\n Buffer.from(encrypted.iv, 'hex'),\n );\n decipher.setAuthTag(Buffer.from(encrypted.authTag, 'hex'));\n\n const plaintext = Buffer.concat([\n decipher.update(Buffer.from(encrypted.ciphertext, 'hex')),\n decipher.final(),\n ]);\n\n return plaintext.toString('utf8');\n\n });\n\n if (err) return null;\n\n return result;\n\n}\n","/**\n * Vault storage operations.\n *\n * Database CRUD operations for the vault table and vault key management.\n * All operations use Kysely for type-safe queries.\n */\nimport type { Kysely } from 'kysely';\n\nimport { attempt, attemptSync } from '@logosdx/utils';\n\nimport type { NoormDatabase } from '../shared/tables.js';\nimport { getNoormTables, noormDb } from '../shared/tables.js';\nimport type { Dialect } from '../connection/types.js';\nimport { observer } from '../observer.js';\n\nimport type { EncryptedVaultKey, VaultSecret, VaultStatus } from './types.js';\nimport {\n generateVaultKey,\n encryptVaultKey,\n decryptVaultKey,\n encryptSecret,\n decryptSecret,\n} from './key.js';\n\n/**\n * Initialize the vault for a database.\n *\n * Generates a new vault key and stores it encrypted for the current user.\n * Only the first user to initialize gets the vault key.\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param identityHash - Current user's identity hash\n * @param publicKey - Current user's public key (hex)\n * @param dialect - Database dialect for table name resolution\n *\n * @example\n * ```typescript\n * const [, err] = await initializeVault(db, identity.identityHash, identity.publicKey, 'postgres');\n * if (err) console.error('Failed to initialize vault');\n * ```\n */\nexport async function initializeVault(\n db: Kysely<NoormDatabase>,\n identityHash: string,\n publicKey: string,\n dialect: Dialect,\n): Promise<[Buffer | null, Error | null]> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n // Check if vault is already initialized (any user has a vault key)\n const [existing, checkErr] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.identities as keyof NoormDatabase)\n .select('encrypted_vault_key')\n .where('encrypted_vault_key', 'is not', null)\n .limit(1)\n .executeTakeFirst();\n\n });\n\n if (checkErr) return [null, checkErr];\n\n if (existing?.encrypted_vault_key) {\n\n return [null, new Error('Vault already initialized')];\n\n }\n\n // Generate new vault key\n const vaultKey = generateVaultKey();\n\n // Encrypt for current user\n const encrypted = encryptVaultKey(vaultKey, publicKey);\n const encryptedJson = JSON.stringify(encrypted);\n\n // Update user's identity row\n const [, updateErr] = await attempt(async () => {\n\n return ndb\n .updateTable(tables.identities as keyof NoormDatabase)\n .set({ encrypted_vault_key: encryptedJson })\n .where('identity_hash', '=', identityHash)\n .execute();\n\n });\n\n if (updateErr) return [null, updateErr];\n\n observer.emit('vault:initialized', { identityHash });\n\n return [vaultKey, null];\n\n}\n\n/**\n * Get the vault key for the current user.\n *\n * Fetches and decrypts the vault key from the user's identity row.\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param identityHash - Current user's identity hash\n * @param privateKey - Current user's private key (hex)\n * @param dialect - Database dialect for table name resolution\n * @returns The decrypted vault key, or null if not found/accessible\n *\n * @example\n * ```typescript\n * const vaultKey = await getVaultKey(db, identity.identityHash, privateKey, 'postgres');\n * if (!vaultKey) {\n * console.log('No vault access - vault not initialized or not propagated');\n * }\n * ```\n */\nexport async function getVaultKey(\n db: Kysely<NoormDatabase>,\n identityHash: string,\n privateKey: string,\n dialect: Dialect,\n): Promise<Buffer | null> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n const [row, err] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.identities as keyof NoormDatabase)\n .select('encrypted_vault_key')\n .where('identity_hash', '=', identityHash)\n .executeTakeFirst();\n\n });\n\n if (err || !row?.encrypted_vault_key) return null;\n\n const encryptedValue = row.encrypted_vault_key;\n\n const [parsed, parseErr] = attemptSync(() =>\n JSON.parse(encryptedValue) as EncryptedVaultKey,\n );\n\n if (parseErr) return null;\n\n return decryptVaultKey(parsed, privateKey);\n\n}\n\n/**\n * Set a vault secret.\n *\n * Encrypts and stores a secret in the vault table.\n * Upserts - creates if new, updates if exists.\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param vaultKey - The decrypted vault key\n * @param secretKey - The secret's key name\n * @param value - The plaintext secret value\n * @param setBy - Identity string of who set this secret\n * @param dialect - Database dialect for table name resolution\n *\n * @example\n * ```typescript\n * await setVaultSecret(db, vaultKey, 'API_KEY', 'sk-live-...', 'alice@example.com', 'postgres');\n * ```\n */\nexport async function setVaultSecret(\n db: Kysely<NoormDatabase>,\n vaultKey: Buffer,\n secretKey: string,\n value: string,\n setBy: string,\n dialect: Dialect,\n): Promise<[void, Error | null]> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n // Encrypt the value\n const encrypted = encryptSecret(value, vaultKey);\n const encryptedJson = JSON.stringify(encrypted);\n const now = new Date().toISOString();\n\n // Check if exists\n const [existing, checkErr] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.vault as keyof NoormDatabase)\n .select('id')\n .where('secret_key', '=', secretKey)\n .executeTakeFirst();\n\n });\n\n if (checkErr) return [undefined, checkErr];\n\n if (existing) {\n\n // Update existing\n const [, updateErr] = await attempt(async () => {\n\n return ndb\n .updateTable(tables.vault as keyof NoormDatabase)\n .set({\n encrypted_value: encryptedJson,\n set_by: setBy,\n updated_at: now as unknown as Date,\n })\n .where('secret_key', '=', secretKey)\n .execute();\n\n });\n\n if (updateErr) return [undefined, updateErr];\n\n observer.emit('vault:secret:updated', { key: secretKey, setBy });\n\n }\n else {\n\n // Insert new\n const [, insertErr] = await attempt(async () => {\n\n return ndb\n .insertInto(tables.vault as keyof NoormDatabase)\n .values({\n secret_key: secretKey,\n encrypted_value: encryptedJson,\n set_by: setBy,\n } as never)\n .execute();\n\n });\n\n if (insertErr) return [undefined, insertErr];\n\n observer.emit('vault:secret:created', { key: secretKey, setBy });\n\n }\n\n return [undefined, null];\n\n}\n\n/**\n * Get a vault secret by key.\n *\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param vaultKey - The decrypted vault key\n * @param secretKey - The secret's key name\n * @param dialect - Database dialect for table name resolution\n * @returns The decrypted secret value, or null if not found\n *\n * @example\n * ```typescript\n * const value = await getVaultSecret(db, vaultKey, 'API_KEY', 'postgres');\n * if (value) {\n * console.log('Secret found:', value);\n * }\n * ```\n */\nexport async function getVaultSecret(\n db: Kysely<NoormDatabase>,\n vaultKey: Buffer,\n secretKey: string,\n dialect: Dialect,\n): Promise<string | null> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n const [row, err] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.vault as keyof NoormDatabase)\n .select('encrypted_value')\n .where('secret_key', '=', secretKey)\n .executeTakeFirst();\n\n });\n\n if (err || !row) return null;\n\n const [parsed, parseErr] = attemptSync(() =>\n JSON.parse(row.encrypted_value) as { iv: string; authTag: string; ciphertext: string },\n );\n\n if (parseErr) return null;\n\n return decryptSecret(parsed, vaultKey);\n\n}\n\n/**\n * Get all vault secrets.\n *\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param vaultKey - The decrypted vault key\n * @param dialect - Database dialect for table name resolution\n * @returns Map of secret key to VaultSecret\n *\n * @example\n * ```typescript\n * const secrets = await getAllVaultSecrets(db, vaultKey, 'postgres');\n * for (const [key, secret] of Object.entries(secrets)) {\n * console.log(key, secret.value);\n * }\n * ```\n */\nexport async function getAllVaultSecrets(\n db: Kysely<NoormDatabase>,\n vaultKey: Buffer,\n dialect: Dialect,\n): Promise<Record<string, VaultSecret>> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n const [rows, err] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.vault as keyof NoormDatabase)\n .selectAll()\n .execute();\n\n });\n\n if (err || !rows) return {};\n\n const secrets: Record<string, VaultSecret> = {};\n\n for (const row of rows) {\n\n const [parsed, parseErr] = attemptSync(() =>\n JSON.parse(row.encrypted_value) as { iv: string; authTag: string; ciphertext: string },\n );\n\n if (parseErr) continue;\n\n const value = decryptSecret(parsed, vaultKey);\n if (!value) continue;\n\n secrets[row.secret_key] = {\n key: row.secret_key,\n value,\n setBy: row.set_by,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n };\n\n }\n\n return secrets;\n\n}\n\n/**\n * List all vault secret keys (without decrypting values).\n *\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param dialect - Database dialect for table name resolution\n * @returns Array of secret key names\n *\n * @example\n * ```typescript\n * const keys = await listVaultSecretKeys(db, 'postgres');\n * console.log('Vault contains:', keys);\n * ```\n */\nexport async function listVaultSecretKeys(\n db: Kysely<NoormDatabase>,\n dialect: Dialect,\n): Promise<string[]> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n const [rows, err] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.vault as keyof NoormDatabase)\n .select('secret_key')\n .orderBy('secret_key', 'asc')\n .execute();\n\n });\n\n if (err || !rows) return [];\n\n return rows.map((r) => r.secret_key);\n\n}\n\n/**\n * Delete a vault secret.\n *\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param secretKey - The secret's key name\n * @param dialect - Database dialect for table name resolution\n *\n * @example\n * ```typescript\n * await deleteVaultSecret(db, 'OLD_API_KEY', 'postgres');\n * ```\n */\nexport async function deleteVaultSecret(\n db: Kysely<NoormDatabase>,\n secretKey: string,\n dialect: Dialect,\n): Promise<[boolean, Error | null]> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n const [result, err] = await attempt(async () => {\n\n return ndb\n .deleteFrom(tables.vault as keyof NoormDatabase)\n .where('secret_key', '=', secretKey)\n .execute();\n\n });\n\n if (err || !result) return [false, err ?? new Error('Delete failed')];\n\n const firstResult = result[0];\n const deleted = !!firstResult && Number(firstResult.numDeletedRows) > 0;\n\n if (deleted) {\n\n observer.emit('vault:secret:deleted', { key: secretKey });\n\n }\n\n return [deleted, null];\n\n}\n\n/**\n * Check if a vault secret exists.\n *\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param secretKey - The secret's key name\n * @param dialect - Database dialect for table name resolution\n * @returns True if the secret exists\n */\nexport async function vaultSecretExists(\n db: Kysely<NoormDatabase>,\n secretKey: string,\n dialect: Dialect,\n): Promise<boolean> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n const [row, err] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.vault as keyof NoormDatabase)\n .select('id')\n .where('secret_key', '=', secretKey)\n .executeTakeFirst();\n\n });\n\n if (err) return false;\n\n return !!row;\n\n}\n\n/**\n * Get vault status.\n *\n * Uses dialect-aware table names to support both legacy prefixed and\n * schema-qualified table locations.\n *\n * @param db - Kysely database instance\n * @param identityHash - Current user's identity hash\n * @param dialect - Database dialect for table name resolution\n *\n * @example\n * ```typescript\n * const status = await getVaultStatus(db, identity.identityHash, 'postgres');\n * console.log('Vault initialized:', status.isInitialized);\n * console.log('Has access:', status.hasAccess);\n * ```\n */\nexport async function getVaultStatus(\n db: Kysely<NoormDatabase>,\n identityHash: string,\n dialect: Dialect,\n): Promise<VaultStatus> {\n\n const ndb = noormDb(db, dialect);\n const tables = getNoormTables(dialect);\n\n // Count secrets\n const [secretRows] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.vault as keyof NoormDatabase)\n .select(ndb.fn.count('id').as('count'))\n .executeTakeFirst();\n\n });\n\n const secretCount = secretRows ? Number(secretRows.count) : 0;\n\n // Count users with/without access\n const [identityRows] = await attempt(async () => {\n\n return ndb\n .selectFrom(tables.identities as keyof NoormDatabase)\n .select([\n 'identity_hash',\n 'encrypted_vault_key',\n ])\n .execute();\n\n });\n\n const identities = identityRows ?? [];\n const usersWithAccess = identities.filter((i) => i.encrypted_vault_key !== null).length;\n const usersWithoutAccess = identities.filter((i) => i.encrypted_vault_key === null).length;\n const isInitialized = usersWithAccess > 0;\n\n // Check if current user has access\n const currentUser = identities.find((i) => i.identity_hash === identityHash);\n const hasAccess = currentUser?.encrypted_vault_key !== null;\n\n return {\n isInitialized,\n hasAccess,\n secretCount,\n usersWithAccess,\n usersWithoutAccess,\n };\n\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -556,25 +556,24 @@ export interface NoormVaultTable {
|
|
|
556
556
|
updated_at: Generated<Date>;
|
|
557
557
|
}
|
|
558
558
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
* Use this with Kysely<NoormDatabase> for type-safe queries.
|
|
562
|
-
*
|
|
563
|
-
* @example
|
|
564
|
-
* ```typescript
|
|
565
|
-
* import { NoormDatabase, NOORM_TABLES } from './shared'
|
|
559
|
+
* Schema-qualified database interface for pg/mssql.
|
|
566
560
|
*
|
|
567
|
-
*
|
|
561
|
+
* Used with db.withSchema('noorm') — table names have no prefix.
|
|
562
|
+
*/
|
|
563
|
+
export interface NoormSchemaDb {
|
|
564
|
+
version: NoormVersionTable;
|
|
565
|
+
change: NoormChangeTable;
|
|
566
|
+
executions: NoormExecutionsTable;
|
|
567
|
+
lock: NoormLockTable;
|
|
568
|
+
identities: NoormIdentitiesTable;
|
|
569
|
+
vault: NoormVaultTable;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Prefixed database interface for sqlite/mysql.
|
|
568
573
|
*
|
|
569
|
-
*
|
|
570
|
-
* .selectFrom(NOORM_TABLES.version)
|
|
571
|
-
* .selectAll()
|
|
572
|
-
* .orderBy('id', 'desc')
|
|
573
|
-
* .limit(1)
|
|
574
|
-
* .executeTakeFirst()
|
|
575
|
-
* ```
|
|
574
|
+
* Used directly — table names have __noorm_ prefix.
|
|
576
575
|
*/
|
|
577
|
-
export interface
|
|
576
|
+
export interface NoormPrefixDb {
|
|
578
577
|
__noorm_version__: NoormVersionTable;
|
|
579
578
|
__noorm_change__: NoormChangeTable;
|
|
580
579
|
__noorm_executions__: NoormExecutionsTable;
|
|
@@ -582,6 +581,21 @@ export interface NoormDatabase {
|
|
|
582
581
|
__noorm_identities__: NoormIdentitiesTable;
|
|
583
582
|
__noorm_vault__: NoormVaultTable;
|
|
584
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* Combined database interface for all noorm tracking tables.
|
|
586
|
+
*
|
|
587
|
+
* Intersection of schema-qualified (pg/mssql) and prefixed (sqlite/mysql)
|
|
588
|
+
* interfaces. Both key sets are valid — use getNoormTables(dialect) to get
|
|
589
|
+
* the correct keys for your dialect.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* ```typescript
|
|
593
|
+
* const tables = getNoormTables(dialect);
|
|
594
|
+
* const ndb = noormDb(db, dialect);
|
|
595
|
+
* await ndb.selectFrom(tables.change).selectAll().execute();
|
|
596
|
+
* ```
|
|
597
|
+
*/
|
|
598
|
+
export type NoormDatabase = NoormSchemaDb & NoormPrefixDb;
|
|
585
599
|
/**
|
|
586
600
|
* Identity types.
|
|
587
601
|
*
|