@vibesdotdev/localdb 0.0.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/README.md +121 -0
- package/SPEC.md +119 -0
- package/dist/cli/commands/_shared.consumer.d.ts +5 -0
- package/dist/cli/commands/_shared.consumer.d.ts.map +1 -0
- package/dist/cli/commands/_shared.consumer.js +17 -0
- package/dist/cli/commands/_shared.consumer.js.map +1 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.d.ts +19 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.js +19 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.d.ts +5 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.d.ts.map +1 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.js +80 -0
- package/dist/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.js.map +1 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.d.ts +19 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.js +16 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.d.ts +5 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.js +33 -0
- package/dist/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.d.ts +15 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.js +15 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.d.ts +5 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.d.ts.map +1 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.js +28 -0
- package/dist/cli/commands/pools/dev.localdb.pools.cli-command.impl.js.map +1 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.descriptor.d.ts +24 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.descriptor.js +20 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.d.ts +5 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.d.ts.map +1 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.js +63 -0
- package/dist/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.js.map +1 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.descriptor.d.ts +19 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.descriptor.d.ts.map +1 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.descriptor.js +19 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.descriptor.js.map +1 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.d.ts +5 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.d.ts.map +1 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.js +73 -0
- package/dist/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.js.map +1 -0
- package/dist/core/connection-pool.d.ts +84 -0
- package/dist/core/connection-pool.d.ts.map +1 -0
- package/dist/core/connection-pool.js +191 -0
- package/dist/core/connection-pool.js.map +1 -0
- package/dist/core/database.d.ts +137 -0
- package/dist/core/database.d.ts.map +1 -0
- package/dist/core/database.js +347 -0
- package/dist/core/database.js.map +1 -0
- package/dist/core/error-context.d.ts +2 -0
- package/dist/core/error-context.d.ts.map +1 -0
- package/dist/core/error-context.js +17 -0
- package/dist/core/error-context.js.map +1 -0
- package/dist/core/migration-registry.d.ts +89 -0
- package/dist/core/migration-registry.d.ts.map +1 -0
- package/dist/core/migration-registry.js +226 -0
- package/dist/core/migration-registry.js.map +1 -0
- package/dist/core/runtime.d.ts +3 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +17 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/dev.localdb.cli-group.descriptor.d.ts +9 -0
- package/dist/dev.localdb.cli-group.descriptor.d.ts.map +1 -0
- package/dist/dev.localdb.cli-group.descriptor.js +17 -0
- package/dist/dev.localdb.cli-group.descriptor.js.map +1 -0
- package/dist/dev.localdb.context.descriptor.d.ts +21 -0
- package/dist/dev.localdb.context.descriptor.d.ts.map +1 -0
- package/dist/dev.localdb.context.descriptor.js +12 -0
- package/dist/dev.localdb.context.descriptor.js.map +1 -0
- package/dist/dev.localdb.context.impl.consumer.d.ts +9 -0
- package/dist/dev.localdb.context.impl.consumer.d.ts.map +1 -0
- package/dist/dev.localdb.context.impl.consumer.js +10 -0
- package/dist/dev.localdb.context.impl.consumer.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/localdb.cloud.plugin.d.ts +17 -0
- package/dist/localdb.cloud.plugin.d.ts.map +1 -0
- package/dist/localdb.cloud.plugin.js +23 -0
- package/dist/localdb.cloud.plugin.js.map +1 -0
- package/dist/localdb.plugin.d.ts +8 -0
- package/dist/localdb.plugin.d.ts.map +1 -0
- package/dist/localdb.plugin.js +38 -0
- package/dist/localdb.plugin.js.map +1 -0
- package/dist/migrations/load-sql.d.ts +45 -0
- package/dist/migrations/load-sql.d.ts.map +1 -0
- package/dist/migrations/load-sql.js +117 -0
- package/dist/migrations/load-sql.js.map +1 -0
- package/dist/schemas/api.d.ts +82 -0
- package/dist/schemas/api.d.ts.map +1 -0
- package/dist/schemas/api.js +2 -0
- package/dist/schemas/api.js.map +1 -0
- package/package.json +146 -0
- package/src/cli/commands/_shared.consumer.ts +20 -0
- package/src/cli/commands/migrate/dev.localdb.migrate.cli-command.descriptor.ts +20 -0
- package/src/cli/commands/migrate/dev.localdb.migrate.cli-command.impl.consumer.ts +97 -0
- package/src/cli/commands/namespaces/dev.localdb.namespaces.cli-command.descriptor.ts +17 -0
- package/src/cli/commands/namespaces/dev.localdb.namespaces.cli-command.impl.ts +46 -0
- package/src/cli/commands/pools/dev.localdb.pools.cli-command.descriptor.ts +16 -0
- package/src/cli/commands/pools/dev.localdb.pools.cli-command.impl.ts +37 -0
- package/src/cli/commands/query/dev.localdb.query.cli-command.descriptor.ts +21 -0
- package/src/cli/commands/query/dev.localdb.query.cli-command.impl.consumer.ts +69 -0
- package/src/cli/commands/status/dev.localdb.status.cli-command.descriptor.ts +20 -0
- package/src/cli/commands/status/dev.localdb.status.cli-command.impl.consumer.ts +93 -0
- package/src/core/connection-pool.ts +240 -0
- package/src/core/database.ts +419 -0
- package/src/core/error-context.ts +19 -0
- package/src/core/migration-registry.ts +321 -0
- package/src/core/runtime.ts +17 -0
- package/src/dev.localdb.cli-group.descriptor.ts +20 -0
- package/src/dev.localdb.context.descriptor.ts +13 -0
- package/src/dev.localdb.context.impl.consumer.ts +12 -0
- package/src/index.ts +28 -0
- package/src/localdb.cloud.plugin.ts +24 -0
- package/src/localdb.plugin.ts +43 -0
- package/src/migrations/atlas/001-initial-schema.sql +173 -0
- package/src/migrations/atlas/002-lang-server-fields.sql +12 -0
- package/src/migrations/atlas/003-config-id-dedup.sql +31 -0
- package/src/migrations/atlas/004-fix-on-conflict-constraints.sql +25 -0
- package/src/migrations/atlas/005-diagnostics.sql +66 -0
- package/src/migrations/atlas/006-diagnostic-summaries.sql +65 -0
- package/src/migrations/atlas/007-diagnostic-slice.sql +83 -0
- package/src/migrations/load-sql.ts +133 -0
- package/src/schemas/api.ts +92 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Database Manager
|
|
3
|
+
*
|
|
4
|
+
* High-level API for managing local SQLite databases in vibes dev.
|
|
5
|
+
* Provides connection pooling, migration management, and consistent configuration.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const db = localdb.getDatabase('atlas', '.vibes/atlas/project.db');
|
|
9
|
+
* // db is ready to use with WAL mode, busy timeout, and migrations applied
|
|
10
|
+
*/
|
|
11
|
+
import { Database } from 'bun:sqlite';
|
|
12
|
+
import { type Migration } from './migration-registry.ts';
|
|
13
|
+
export interface DatabaseOptions {
|
|
14
|
+
/** Namespace for migrations (e.g., 'atlas', 'session') */
|
|
15
|
+
namespace: string;
|
|
16
|
+
/** Path to database file */
|
|
17
|
+
dbPath: string;
|
|
18
|
+
/** Consumer identifier for debugging */
|
|
19
|
+
consumer?: string;
|
|
20
|
+
/** Skip migration check/run on initialization */
|
|
21
|
+
skipMigrations?: boolean;
|
|
22
|
+
/** Use connection pool (default: true) */
|
|
23
|
+
usePool?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare class LocalDatabase {
|
|
26
|
+
private db;
|
|
27
|
+
private options;
|
|
28
|
+
private initialized;
|
|
29
|
+
constructor(options: DatabaseOptions);
|
|
30
|
+
/**
|
|
31
|
+
* Initialize the database connection
|
|
32
|
+
* - Creates directory if needed
|
|
33
|
+
* - Gets/creates pooled connection
|
|
34
|
+
* - Runs pending migrations
|
|
35
|
+
*/
|
|
36
|
+
initialize(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Establish initial connection
|
|
39
|
+
*/
|
|
40
|
+
private establishConnection;
|
|
41
|
+
/**
|
|
42
|
+
* Perform recovery from migration failure
|
|
43
|
+
* 1. Close connection
|
|
44
|
+
* 2. Backup corrupted DB
|
|
45
|
+
* 3. Delete corrupted DB
|
|
46
|
+
* 4. Re-initialize fresh DB
|
|
47
|
+
* 5. Re-run migrations
|
|
48
|
+
*/
|
|
49
|
+
private performRecovery;
|
|
50
|
+
private pruneBackupFiles;
|
|
51
|
+
/**
|
|
52
|
+
* Configure database with optimal settings (for non-pooled connections)
|
|
53
|
+
*/
|
|
54
|
+
private configureDatabase;
|
|
55
|
+
/**
|
|
56
|
+
* Get the underlying Database instance
|
|
57
|
+
*/
|
|
58
|
+
getDatabase(): Database;
|
|
59
|
+
/**
|
|
60
|
+
* Close the database connection
|
|
61
|
+
*/
|
|
62
|
+
close(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Check if database is healthy
|
|
65
|
+
*/
|
|
66
|
+
healthCheck(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Get migration status for this database
|
|
69
|
+
*/
|
|
70
|
+
getMigrationStatus(): {
|
|
71
|
+
namespace: string;
|
|
72
|
+
currentVersion: number;
|
|
73
|
+
targetVersion: number;
|
|
74
|
+
pendingMigrations: number;
|
|
75
|
+
migrations: Array<{
|
|
76
|
+
version: number;
|
|
77
|
+
name: string;
|
|
78
|
+
applied: boolean;
|
|
79
|
+
}>;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* LocalDB Manager
|
|
84
|
+
* Main entry point for accessing local databases
|
|
85
|
+
*/
|
|
86
|
+
declare class LocalDBManager {
|
|
87
|
+
private databases;
|
|
88
|
+
private dbPathLocks;
|
|
89
|
+
private withDbPathLock;
|
|
90
|
+
/**
|
|
91
|
+
* Register migrations for a namespace
|
|
92
|
+
* Must be called before getDatabase() for that namespace
|
|
93
|
+
*/
|
|
94
|
+
registerMigrations(namespace: string, migrations: Migration[]): void;
|
|
95
|
+
/**
|
|
96
|
+
* Get or create a database instance
|
|
97
|
+
*
|
|
98
|
+
* @param namespace Migration namespace (e.g., 'atlas', 'session')
|
|
99
|
+
* @param dbPath Path to database file
|
|
100
|
+
* @param consumer Consumer identifier for debugging
|
|
101
|
+
* @returns Initialized database instance
|
|
102
|
+
*/
|
|
103
|
+
getDatabase(namespace: string, dbPath: string, consumer?: string): Promise<LocalDatabase>;
|
|
104
|
+
/**
|
|
105
|
+
* Get a raw Database instance (auto-configured with WAL, etc.)
|
|
106
|
+
* For when you don't need migration management
|
|
107
|
+
*/
|
|
108
|
+
getRawDatabase(dbPath: string, consumer?: string): Database;
|
|
109
|
+
/**
|
|
110
|
+
* Release a database instance
|
|
111
|
+
*/
|
|
112
|
+
releaseDatabase(namespace: string, dbPath: string): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Get connection pool statistics
|
|
115
|
+
*/
|
|
116
|
+
getPoolStats(): import("./connection-pool.ts").ConnectionStats;
|
|
117
|
+
/**
|
|
118
|
+
* Get migration registry status
|
|
119
|
+
*/
|
|
120
|
+
getMigrationStatus(): {
|
|
121
|
+
namespace: string;
|
|
122
|
+
currentVersion: number;
|
|
123
|
+
targetVersion: number;
|
|
124
|
+
pendingMigrations: number;
|
|
125
|
+
}[];
|
|
126
|
+
/**
|
|
127
|
+
* List all registered migration namespaces
|
|
128
|
+
*/
|
|
129
|
+
listNamespaces(): string[];
|
|
130
|
+
/**
|
|
131
|
+
* Close all database connections
|
|
132
|
+
*/
|
|
133
|
+
closeAll(): Promise<void>;
|
|
134
|
+
}
|
|
135
|
+
export declare const localdb: LocalDBManager;
|
|
136
|
+
export {};
|
|
137
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAqB5E,MAAM,WAAW,eAAe;IAC/B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAElB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IAEf,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,iDAAiD;IACjD,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAWD,qBAAa,aAAa;IACzB,OAAO,CAAC,EAAE,CAAY;IACtB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,eAAe;IASpC;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAqCjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAU3B;;;;;;;OAOG;YACW,eAAe;YA4Df,gBAAgB;IAoB9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACH,WAAW,IAAI,QAAQ;IAOvB;;OAEG;IACH,KAAK,IAAI,IAAI;IAcb;;OAEG;IACH,WAAW,IAAI,OAAO;IAWtB;;OAEG;IACH,kBAAkB;;;;;;;;;;;CAOlB;AAED;;;GAGG;AACH,cAAM,cAAc;IACnB,OAAO,CAAC,SAAS,CAMb;IACJ,OAAO,CAAC,WAAW,CAAoC;YAEzC,cAAc;IAmB5B;;;OAGG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI;IAIpE;;;;;;;OAOG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IA2BzF;;;OAGG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,QAAQ;IAI1D;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcvE;;OAEG;IACH,YAAY;IAIZ;;OAEG;IACH,kBAAkB;;;;;;IAIlB;;OAEG;IACH,cAAc,IAAI,MAAM,EAAE;IAI1B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAO/B;AAGD,eAAO,MAAM,OAAO,gBAAuB,CAAC"}
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Database Manager
|
|
3
|
+
*
|
|
4
|
+
* High-level API for managing local SQLite databases in vibes dev.
|
|
5
|
+
* Provides connection pooling, migration management, and consistent configuration.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const db = localdb.getDatabase('atlas', '.vibes/atlas/project.db');
|
|
9
|
+
* // db is ready to use with WAL mode, busy timeout, and migrations applied
|
|
10
|
+
*/
|
|
11
|
+
import { Database } from 'bun:sqlite';
|
|
12
|
+
import { getLogger } from '@vibesdotdev/logging';
|
|
13
|
+
import { connectionPool } from "./connection-pool.js";
|
|
14
|
+
import { migrationRegistry } from "./migration-registry.js";
|
|
15
|
+
import { toErrorContext } from './error-context.js';
|
|
16
|
+
import { isLocaldbServerRuntime } from "./runtime.js";
|
|
17
|
+
const logger = getLogger('localdb:database');
|
|
18
|
+
let mkdir;
|
|
19
|
+
let copyFile;
|
|
20
|
+
let unlink;
|
|
21
|
+
let readdir;
|
|
22
|
+
let dirname;
|
|
23
|
+
let basename;
|
|
24
|
+
const BACKUP_RETENTION_COUNT = 12;
|
|
25
|
+
const isServerRuntime = isLocaldbServerRuntime();
|
|
26
|
+
if (isServerRuntime) {
|
|
27
|
+
({ mkdir, copyFile, unlink, readdir } = await import('node:fs/promises'));
|
|
28
|
+
({ dirname, basename } = await import('node:path'));
|
|
29
|
+
}
|
|
30
|
+
function isFileMissingError(error) {
|
|
31
|
+
if (!error || typeof error !== 'object')
|
|
32
|
+
return false;
|
|
33
|
+
return error.code === 'ENOENT';
|
|
34
|
+
}
|
|
35
|
+
export class LocalDatabase {
|
|
36
|
+
db;
|
|
37
|
+
options;
|
|
38
|
+
initialized = false;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.options = {
|
|
41
|
+
consumer: 'unknown',
|
|
42
|
+
skipMigrations: false,
|
|
43
|
+
usePool: true,
|
|
44
|
+
...options
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Initialize the database connection
|
|
49
|
+
* - Creates directory if needed
|
|
50
|
+
* - Gets/creates pooled connection
|
|
51
|
+
* - Runs pending migrations
|
|
52
|
+
*/
|
|
53
|
+
async initialize() {
|
|
54
|
+
if (this.initialized)
|
|
55
|
+
return;
|
|
56
|
+
// Ensure directory exists
|
|
57
|
+
if (!isServerRuntime) {
|
|
58
|
+
throw new Error('LocalDatabase is not available in browser builds');
|
|
59
|
+
}
|
|
60
|
+
await mkdir(dirname(this.options.dbPath), { recursive: true });
|
|
61
|
+
// Get connection (pooled or direct)
|
|
62
|
+
this.establishConnection();
|
|
63
|
+
// Run migrations if needed
|
|
64
|
+
if (!this.options.skipMigrations) {
|
|
65
|
+
try {
|
|
66
|
+
// Check for incompatible database from old migration system
|
|
67
|
+
if (migrationRegistry.isIncompatibleDatabase(this.db, this.options.namespace)) {
|
|
68
|
+
logger.error(`[LocalDB] Detected incompatible database for ${this.options.namespace} (from legacy migration system). Initiating recovery...`);
|
|
69
|
+
await this.performRecovery();
|
|
70
|
+
}
|
|
71
|
+
else if (migrationRegistry.needsMigration(this.db, this.options.namespace)) {
|
|
72
|
+
await migrationRegistry.runMigrations(this.db, this.options.namespace);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
logger.error(`[LocalDB] Migration failed for ${this.options.namespace}. Initiating automatic recovery/trapdoor...`, toErrorContext(error));
|
|
77
|
+
await this.performRecovery();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
this.initialized = true;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Establish initial connection
|
|
84
|
+
*/
|
|
85
|
+
establishConnection() {
|
|
86
|
+
if (this.options.usePool) {
|
|
87
|
+
this.db = connectionPool.getConnection(this.options.dbPath, this.options.consumer);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Direct connection (for special cases)
|
|
91
|
+
this.db = new Database(this.options.dbPath);
|
|
92
|
+
this.configureDatabase(this.db);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Perform recovery from migration failure
|
|
97
|
+
* 1. Close connection
|
|
98
|
+
* 2. Backup corrupted DB
|
|
99
|
+
* 3. Delete corrupted DB
|
|
100
|
+
* 4. Re-initialize fresh DB
|
|
101
|
+
* 5. Re-run migrations
|
|
102
|
+
*/
|
|
103
|
+
async performRecovery() {
|
|
104
|
+
// 1. Close the broken database
|
|
105
|
+
if (this.options.usePool) {
|
|
106
|
+
connectionPool.closeConnection(this.options.dbPath, true);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
this.db.close();
|
|
110
|
+
}
|
|
111
|
+
// 2. Backup the broken file
|
|
112
|
+
const backupPath = `${this.options.dbPath}.bak-${Date.now()}`;
|
|
113
|
+
try {
|
|
114
|
+
await copyFile(this.options.dbPath, backupPath);
|
|
115
|
+
logger.info(`[LocalDB] Backed up corrupted database to: ${backupPath}`);
|
|
116
|
+
await this.pruneBackupFiles();
|
|
117
|
+
}
|
|
118
|
+
catch (backupError) {
|
|
119
|
+
logger.error('[LocalDB] Failed to backup corrupted database:', toErrorContext(backupError));
|
|
120
|
+
}
|
|
121
|
+
// 3. Delete the broken file and WAL artifacts
|
|
122
|
+
try {
|
|
123
|
+
await unlink(this.options.dbPath);
|
|
124
|
+
await unlink(`${this.options.dbPath}-wal`).catch(() => { });
|
|
125
|
+
await unlink(`${this.options.dbPath}-shm`).catch(() => { });
|
|
126
|
+
logger.info('[LocalDB] Deleted corrupted database file.');
|
|
127
|
+
}
|
|
128
|
+
catch (deleteError) {
|
|
129
|
+
if (isFileMissingError(deleteError)) {
|
|
130
|
+
logger.info('[LocalDB] Corrupted database file already removed during recovery. Continuing...');
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
logger.error('[LocalDB] Failed to delete corrupted database:', toErrorContext(deleteError));
|
|
134
|
+
throw deleteError; // If we can't delete, we can't recover.
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// 4. Re-establish connection (creates new DB file)
|
|
138
|
+
logger.info('[LocalDB] Re-initializing fresh database...');
|
|
139
|
+
this.establishConnection();
|
|
140
|
+
// 5. Re-run migrations on fresh DB
|
|
141
|
+
try {
|
|
142
|
+
if (migrationRegistry.needsMigration(this.db, this.options.namespace)) {
|
|
143
|
+
await migrationRegistry.runMigrations(this.db, this.options.namespace);
|
|
144
|
+
}
|
|
145
|
+
logger.info('[LocalDB] Recovery successful. Database reset.');
|
|
146
|
+
}
|
|
147
|
+
catch (retryError) {
|
|
148
|
+
logger.error('[LocalDB] Recovery failed. Fresh database migration failed:', toErrorContext(retryError));
|
|
149
|
+
throw retryError;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async pruneBackupFiles() {
|
|
153
|
+
const directory = dirname(this.options.dbPath);
|
|
154
|
+
const filename = basename(this.options.dbPath);
|
|
155
|
+
const backupPrefix = `${filename}.bak-`;
|
|
156
|
+
const files = await readdir(directory).catch(() => []);
|
|
157
|
+
const backups = files
|
|
158
|
+
.filter((entry) => entry.startsWith(backupPrefix))
|
|
159
|
+
.map((entry) => ({ entry, timestamp: Number(entry.slice(backupPrefix.length)) }))
|
|
160
|
+
.sort((a, b) => {
|
|
161
|
+
if (Number.isNaN(a.timestamp) || Number.isNaN(b.timestamp)) {
|
|
162
|
+
return b.entry.localeCompare(a.entry);
|
|
163
|
+
}
|
|
164
|
+
return b.timestamp - a.timestamp;
|
|
165
|
+
});
|
|
166
|
+
for (const backup of backups.slice(BACKUP_RETENTION_COUNT)) {
|
|
167
|
+
await unlink(`${directory}/${backup.entry}`).catch(() => { });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Configure database with optimal settings (for non-pooled connections)
|
|
172
|
+
*/
|
|
173
|
+
configureDatabase(db) {
|
|
174
|
+
db.exec('PRAGMA journal_mode = WAL;');
|
|
175
|
+
db.exec('PRAGMA busy_timeout = 5000;');
|
|
176
|
+
db.exec('PRAGMA foreign_keys = ON;');
|
|
177
|
+
db.exec('PRAGMA synchronous = NORMAL;');
|
|
178
|
+
db.exec('PRAGMA temp_store = MEMORY;');
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get the underlying Database instance
|
|
182
|
+
*/
|
|
183
|
+
getDatabase() {
|
|
184
|
+
if (!this.initialized) {
|
|
185
|
+
throw new Error('Database not initialized. Call initialize() first.');
|
|
186
|
+
}
|
|
187
|
+
return this.db;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Close the database connection
|
|
191
|
+
*/
|
|
192
|
+
close() {
|
|
193
|
+
if (!this.initialized)
|
|
194
|
+
return;
|
|
195
|
+
if (this.options.usePool) {
|
|
196
|
+
// Release back to pool
|
|
197
|
+
connectionPool.releaseConnection(this.options.dbPath);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
// Direct close
|
|
201
|
+
this.db.close();
|
|
202
|
+
}
|
|
203
|
+
this.initialized = false;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Check if database is healthy
|
|
207
|
+
*/
|
|
208
|
+
healthCheck() {
|
|
209
|
+
if (!this.initialized)
|
|
210
|
+
return false;
|
|
211
|
+
try {
|
|
212
|
+
const result = this.db.query('SELECT 1').get();
|
|
213
|
+
return result !== null;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get migration status for this database
|
|
221
|
+
*/
|
|
222
|
+
getMigrationStatus() {
|
|
223
|
+
if (!this.initialized) {
|
|
224
|
+
throw new Error('Database not initialized');
|
|
225
|
+
}
|
|
226
|
+
return migrationRegistry.getDatabaseStatus(this.db, this.options.namespace);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* LocalDB Manager
|
|
231
|
+
* Main entry point for accessing local databases
|
|
232
|
+
*/
|
|
233
|
+
class LocalDBManager {
|
|
234
|
+
databases = new Map();
|
|
235
|
+
dbPathLocks = new Map();
|
|
236
|
+
async withDbPathLock(dbPath, task) {
|
|
237
|
+
const prior = this.dbPathLocks.get(dbPath) ?? Promise.resolve();
|
|
238
|
+
let release;
|
|
239
|
+
const current = new Promise((resolve) => {
|
|
240
|
+
release = resolve;
|
|
241
|
+
});
|
|
242
|
+
const queued = prior.then(() => current);
|
|
243
|
+
this.dbPathLocks.set(dbPath, queued);
|
|
244
|
+
await prior;
|
|
245
|
+
try {
|
|
246
|
+
return await task();
|
|
247
|
+
}
|
|
248
|
+
finally {
|
|
249
|
+
release?.();
|
|
250
|
+
if (this.dbPathLocks.get(dbPath) === queued) {
|
|
251
|
+
this.dbPathLocks.delete(dbPath);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Register migrations for a namespace
|
|
257
|
+
* Must be called before getDatabase() for that namespace
|
|
258
|
+
*/
|
|
259
|
+
registerMigrations(namespace, migrations) {
|
|
260
|
+
migrationRegistry.register(namespace, migrations);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get or create a database instance
|
|
264
|
+
*
|
|
265
|
+
* @param namespace Migration namespace (e.g., 'atlas', 'session')
|
|
266
|
+
* @param dbPath Path to database file
|
|
267
|
+
* @param consumer Consumer identifier for debugging
|
|
268
|
+
* @returns Initialized database instance
|
|
269
|
+
*/
|
|
270
|
+
getDatabase(namespace, dbPath, consumer) {
|
|
271
|
+
const key = `${namespace}:${dbPath}`;
|
|
272
|
+
return this.withDbPathLock(dbPath, async () => {
|
|
273
|
+
const existing = this.databases.get(key);
|
|
274
|
+
if (existing) {
|
|
275
|
+
existing.references += 1;
|
|
276
|
+
return existing.database;
|
|
277
|
+
}
|
|
278
|
+
if (!this.databases.has(key)) {
|
|
279
|
+
const db = new LocalDatabase({
|
|
280
|
+
namespace,
|
|
281
|
+
dbPath,
|
|
282
|
+
consumer
|
|
283
|
+
});
|
|
284
|
+
await db.initialize();
|
|
285
|
+
this.databases.set(key, {
|
|
286
|
+
database: db,
|
|
287
|
+
references: 1
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return this.databases.get(key).database;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get a raw Database instance (auto-configured with WAL, etc.)
|
|
295
|
+
* For when you don't need migration management
|
|
296
|
+
*/
|
|
297
|
+
getRawDatabase(dbPath, consumer = 'raw') {
|
|
298
|
+
return connectionPool.getConnection(dbPath, consumer);
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Release a database instance
|
|
302
|
+
*/
|
|
303
|
+
async releaseDatabase(namespace, dbPath) {
|
|
304
|
+
const key = `${namespace}:${dbPath}`;
|
|
305
|
+
await this.withDbPathLock(dbPath, async () => {
|
|
306
|
+
const entry = this.databases.get(key);
|
|
307
|
+
if (!entry)
|
|
308
|
+
return;
|
|
309
|
+
entry.references = Math.max(0, entry.references - 1);
|
|
310
|
+
if (entry.references === 0) {
|
|
311
|
+
await entry.database.close();
|
|
312
|
+
this.databases.delete(key);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get connection pool statistics
|
|
318
|
+
*/
|
|
319
|
+
getPoolStats() {
|
|
320
|
+
return connectionPool.getStats();
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get migration registry status
|
|
324
|
+
*/
|
|
325
|
+
getMigrationStatus() {
|
|
326
|
+
return migrationRegistry.getStatus();
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* List all registered migration namespaces
|
|
330
|
+
*/
|
|
331
|
+
listNamespaces() {
|
|
332
|
+
return migrationRegistry.listNamespaces();
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Close all database connections
|
|
336
|
+
*/
|
|
337
|
+
async closeAll() {
|
|
338
|
+
for (const entry of this.databases.values()) {
|
|
339
|
+
await entry.database.close();
|
|
340
|
+
}
|
|
341
|
+
this.databases.clear();
|
|
342
|
+
connectionPool.closeAll();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// Singleton instance
|
|
346
|
+
export const localdb = new LocalDBManager();
|
|
347
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/core/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-context.d.ts","sourceRoot":"","sources":["../../src/core/error-context.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAkBlF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function toErrorContext(error) {
|
|
2
|
+
if (error instanceof Error) {
|
|
3
|
+
return {
|
|
4
|
+
error: error.message,
|
|
5
|
+
name: error.name,
|
|
6
|
+
stack: error.stack
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
if (typeof error === 'object' && error !== null && !Array.isArray(error)) {
|
|
10
|
+
return error;
|
|
11
|
+
}
|
|
12
|
+
if (error === undefined) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
return { error: String(error) };
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=error-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-context.js","sourceRoot":"","sources":["../../src/core/error-context.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAAC,KAAc;IAC5C,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC5B,OAAO;YACN,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,KAAK,EAAE,KAAK,CAAC,KAAK;SAClB,CAAC;IACH,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1E,OAAO,KAAgC,CAAC;IACzC,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration Registry
|
|
3
|
+
*
|
|
4
|
+
* Centralized registration and execution of database migrations.
|
|
5
|
+
* Consumers register their migrations with the registry, which ensures
|
|
6
|
+
* they run in order with proper error handling and version tracking.
|
|
7
|
+
*/
|
|
8
|
+
import type { Database } from 'bun:sqlite';
|
|
9
|
+
export interface MigrationFunction {
|
|
10
|
+
(db: Database): void | Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export interface Migration {
|
|
13
|
+
version: number;
|
|
14
|
+
name: string;
|
|
15
|
+
up: MigrationFunction;
|
|
16
|
+
down?: MigrationFunction;
|
|
17
|
+
}
|
|
18
|
+
export interface MigrationNamespace {
|
|
19
|
+
namespace: string;
|
|
20
|
+
migrations: Migration[];
|
|
21
|
+
currentVersion: number;
|
|
22
|
+
}
|
|
23
|
+
declare class MigrationRegistry {
|
|
24
|
+
private namespaces;
|
|
25
|
+
private hasVersionTable;
|
|
26
|
+
private ensureVersionTable;
|
|
27
|
+
private getLegacyUserVersion;
|
|
28
|
+
private getTrackedSchemaVersion;
|
|
29
|
+
private bootstrapSchemaVersion;
|
|
30
|
+
/**
|
|
31
|
+
* Register migrations for a namespace (e.g., 'atlas', 'session')
|
|
32
|
+
*/
|
|
33
|
+
register(namespace: string, migrations: Migration[]): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get current schema version from database
|
|
36
|
+
*/
|
|
37
|
+
getSchemaVersion(db: Database, namespace: string): number;
|
|
38
|
+
/**
|
|
39
|
+
* Set schema version in database
|
|
40
|
+
*/
|
|
41
|
+
private setSchemaVersion;
|
|
42
|
+
/**
|
|
43
|
+
* Check if database needs migration
|
|
44
|
+
*/
|
|
45
|
+
needsMigration(db: Database, namespace: string): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Check if database is from an incompatible/old migration system
|
|
48
|
+
* This happens when the version is higher than our max (legacy system)
|
|
49
|
+
*/
|
|
50
|
+
isIncompatibleDatabase(db: Database, namespace: string): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Run all pending migrations for a namespace
|
|
53
|
+
*/
|
|
54
|
+
runMigrations(db: Database, namespace: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Get migration status for all namespaces
|
|
57
|
+
*/
|
|
58
|
+
getStatus(): Array<{
|
|
59
|
+
namespace: string;
|
|
60
|
+
currentVersion: number;
|
|
61
|
+
targetVersion: number;
|
|
62
|
+
pendingMigrations: number;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* Get migration status for a specific database and namespace
|
|
66
|
+
*/
|
|
67
|
+
getDatabaseStatus(db: Database, namespace: string): {
|
|
68
|
+
namespace: string;
|
|
69
|
+
currentVersion: number;
|
|
70
|
+
targetVersion: number;
|
|
71
|
+
pendingMigrations: number;
|
|
72
|
+
migrations: Array<{
|
|
73
|
+
version: number;
|
|
74
|
+
name: string;
|
|
75
|
+
applied: boolean;
|
|
76
|
+
}>;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* List all registered namespaces
|
|
80
|
+
*/
|
|
81
|
+
listNamespaces(): string[];
|
|
82
|
+
/**
|
|
83
|
+
* Get migrations for a namespace
|
|
84
|
+
*/
|
|
85
|
+
getMigrations(namespace: string): Migration[];
|
|
86
|
+
}
|
|
87
|
+
export declare const migrationRegistry: MigrationRegistry;
|
|
88
|
+
export {};
|
|
89
|
+
//# sourceMappingURL=migration-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migration-registry.d.ts","sourceRoot":"","sources":["../../src/core/migration-registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAM3C,MAAM,WAAW,iBAAiB;IACjC,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,SAAS;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,iBAAiB,CAAC;IACtB,IAAI,CAAC,EAAE,iBAAiB,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,cAAM,iBAAiB;IACtB,OAAO,CAAC,UAAU,CAAyC;IAE3D,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,sBAAsB;IAuB9B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI;IA8B1D;;OAEG;IACH,gBAAgB,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAIzD;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAYxB;;OAEG;IACH,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAUxD;;;OAGG;IACH,sBAAsB,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAchE;;OAEG;IACG,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCnE;;OAEG;IACH,SAAS,IAAI,KAAK,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;KAC1B,CAAC;IAoBF;;OAEG;IACH,iBAAiB,CAChB,EAAE,EAAE,QAAQ,EACZ,SAAS,EAAE,MAAM,GACf;QACF,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,UAAU,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KACvE;IAsBD;;OAEG;IACH,cAAc,IAAI,MAAM,EAAE;IAI1B;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE;CAO7C;AAGD,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
|