steroids-api 0.2.7
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/API/src/index.d.ts +10 -0
- package/dist/API/src/index.d.ts.map +1 -0
- package/dist/API/src/index.js +130 -0
- package/dist/API/src/index.js.map +1 -0
- package/dist/API/src/routes/activity.d.ts +7 -0
- package/dist/API/src/routes/activity.d.ts.map +1 -0
- package/dist/API/src/routes/activity.js +252 -0
- package/dist/API/src/routes/activity.js.map +1 -0
- package/dist/API/src/routes/config.d.ts +7 -0
- package/dist/API/src/routes/config.d.ts.map +1 -0
- package/dist/API/src/routes/config.js +521 -0
- package/dist/API/src/routes/config.js.map +1 -0
- package/dist/API/src/routes/health.d.ts +7 -0
- package/dist/API/src/routes/health.d.ts.map +1 -0
- package/dist/API/src/routes/health.js +172 -0
- package/dist/API/src/routes/health.js.map +1 -0
- package/dist/API/src/routes/incidents.d.ts +7 -0
- package/dist/API/src/routes/incidents.d.ts.map +1 -0
- package/dist/API/src/routes/incidents.js +117 -0
- package/dist/API/src/routes/incidents.js.map +1 -0
- package/dist/API/src/routes/projects.d.ts +7 -0
- package/dist/API/src/routes/projects.d.ts.map +1 -0
- package/dist/API/src/routes/projects.js +398 -0
- package/dist/API/src/routes/projects.js.map +1 -0
- package/dist/API/src/routes/runners.d.ts +7 -0
- package/dist/API/src/routes/runners.d.ts.map +1 -0
- package/dist/API/src/routes/runners.js +242 -0
- package/dist/API/src/routes/runners.js.map +1 -0
- package/dist/API/src/routes/tasks.d.ts +7 -0
- package/dist/API/src/routes/tasks.d.ts.map +1 -0
- package/dist/API/src/routes/tasks.js +1007 -0
- package/dist/API/src/routes/tasks.js.map +1 -0
- package/dist/API/src/utils/validation.d.ts +22 -0
- package/dist/API/src/utils/validation.d.ts.map +1 -0
- package/dist/API/src/utils/validation.js +50 -0
- package/dist/API/src/utils/validation.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +184 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/activity.d.ts +7 -0
- package/dist/routes/activity.d.ts.map +1 -0
- package/dist/routes/activity.js +252 -0
- package/dist/routes/activity.js.map +1 -0
- package/dist/routes/config.d.ts +7 -0
- package/dist/routes/config.d.ts.map +1 -0
- package/dist/routes/config.js +647 -0
- package/dist/routes/config.js.map +1 -0
- package/dist/routes/credit-alerts.d.ts +2 -0
- package/dist/routes/credit-alerts.d.ts.map +1 -0
- package/dist/routes/credit-alerts.js +97 -0
- package/dist/routes/credit-alerts.js.map +1 -0
- package/dist/routes/health.d.ts +7 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +200 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/incidents.d.ts +7 -0
- package/dist/routes/incidents.d.ts.map +1 -0
- package/dist/routes/incidents.js +117 -0
- package/dist/routes/incidents.js.map +1 -0
- package/dist/routes/projects.d.ts +7 -0
- package/dist/routes/projects.d.ts.map +1 -0
- package/dist/routes/projects.js +643 -0
- package/dist/routes/projects.js.map +1 -0
- package/dist/routes/runners.d.ts +7 -0
- package/dist/routes/runners.d.ts.map +1 -0
- package/dist/routes/runners.js +299 -0
- package/dist/routes/runners.js.map +1 -0
- package/dist/routes/skills.d.ts +3 -0
- package/dist/routes/skills.d.ts.map +1 -0
- package/dist/routes/skills.js +109 -0
- package/dist/routes/skills.js.map +1 -0
- package/dist/routes/storage.d.ts +7 -0
- package/dist/routes/storage.d.ts.map +1 -0
- package/dist/routes/storage.js +93 -0
- package/dist/routes/storage.js.map +1 -0
- package/dist/routes/tasks.d.ts +7 -0
- package/dist/routes/tasks.d.ts.map +1 -0
- package/dist/routes/tasks.js +1145 -0
- package/dist/routes/tasks.js.map +1 -0
- package/dist/src/cleanup/invocation-logs.d.ts +30 -0
- package/dist/src/cleanup/invocation-logs.d.ts.map +1 -0
- package/dist/src/cleanup/invocation-logs.js +66 -0
- package/dist/src/cleanup/invocation-logs.js.map +1 -0
- package/dist/src/commands/loop-phases.d.ts +11 -0
- package/dist/src/commands/loop-phases.d.ts.map +1 -0
- package/dist/src/commands/loop-phases.js +304 -0
- package/dist/src/commands/loop-phases.js.map +1 -0
- package/dist/src/config/loader.d.ts +160 -0
- package/dist/src/config/loader.d.ts.map +1 -0
- package/dist/src/config/loader.js +276 -0
- package/dist/src/config/loader.js.map +1 -0
- package/dist/src/database/connection.d.ts +35 -0
- package/dist/src/database/connection.d.ts.map +1 -0
- package/dist/src/database/connection.js +197 -0
- package/dist/src/database/connection.js.map +1 -0
- package/dist/src/database/queries.d.ts +220 -0
- package/dist/src/database/queries.d.ts.map +1 -0
- package/dist/src/database/queries.js +589 -0
- package/dist/src/database/queries.js.map +1 -0
- package/dist/src/database/schema.d.ts +8 -0
- package/dist/src/database/schema.d.ts.map +1 -0
- package/dist/src/database/schema.js +184 -0
- package/dist/src/database/schema.js.map +1 -0
- package/dist/src/git/push.d.ts +26 -0
- package/dist/src/git/push.d.ts.map +1 -0
- package/dist/src/git/push.js +91 -0
- package/dist/src/git/push.js.map +1 -0
- package/dist/src/git/status.d.ts +83 -0
- package/dist/src/git/status.d.ts.map +1 -0
- package/dist/src/git/status.js +315 -0
- package/dist/src/git/status.js.map +1 -0
- package/dist/src/health/stuck-task-detector.d.ts +131 -0
- package/dist/src/health/stuck-task-detector.d.ts.map +1 -0
- package/dist/src/health/stuck-task-detector.js +233 -0
- package/dist/src/health/stuck-task-detector.js.map +1 -0
- package/dist/src/health/stuck-task-recovery.d.ts +45 -0
- package/dist/src/health/stuck-task-recovery.d.ts.map +1 -0
- package/dist/src/health/stuck-task-recovery.js +309 -0
- package/dist/src/health/stuck-task-recovery.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +130 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/locking/queries.d.ts +116 -0
- package/dist/src/locking/queries.d.ts.map +1 -0
- package/dist/src/locking/queries.js +232 -0
- package/dist/src/locking/queries.js.map +1 -0
- package/dist/src/locking/section-lock.d.ts +74 -0
- package/dist/src/locking/section-lock.d.ts.map +1 -0
- package/dist/src/locking/section-lock.js +196 -0
- package/dist/src/locking/section-lock.js.map +1 -0
- package/dist/src/locking/task-lock.d.ts +92 -0
- package/dist/src/locking/task-lock.d.ts.map +1 -0
- package/dist/src/locking/task-lock.js +233 -0
- package/dist/src/locking/task-lock.js.map +1 -0
- package/dist/src/migrations/index.d.ts +7 -0
- package/dist/src/migrations/index.d.ts.map +1 -0
- package/dist/src/migrations/index.js +9 -0
- package/dist/src/migrations/index.js.map +1 -0
- package/dist/src/migrations/manifest.d.ts +92 -0
- package/dist/src/migrations/manifest.d.ts.map +1 -0
- package/dist/src/migrations/manifest.js +255 -0
- package/dist/src/migrations/manifest.js.map +1 -0
- package/dist/src/migrations/runner.d.ts +84 -0
- package/dist/src/migrations/runner.d.ts.map +1 -0
- package/dist/src/migrations/runner.js +338 -0
- package/dist/src/migrations/runner.js.map +1 -0
- package/dist/src/orchestrator/coder.d.ts +32 -0
- package/dist/src/orchestrator/coder.d.ts.map +1 -0
- package/dist/src/orchestrator/coder.js +170 -0
- package/dist/src/orchestrator/coder.js.map +1 -0
- package/dist/src/orchestrator/coordinator.d.ts +28 -0
- package/dist/src/orchestrator/coordinator.d.ts.map +1 -0
- package/dist/src/orchestrator/coordinator.js +252 -0
- package/dist/src/orchestrator/coordinator.js.map +1 -0
- package/dist/src/orchestrator/fallback-handler.d.ts +24 -0
- package/dist/src/orchestrator/fallback-handler.d.ts.map +1 -0
- package/dist/src/orchestrator/fallback-handler.js +280 -0
- package/dist/src/orchestrator/fallback-handler.js.map +1 -0
- package/dist/src/orchestrator/invoke.d.ts +14 -0
- package/dist/src/orchestrator/invoke.d.ts.map +1 -0
- package/dist/src/orchestrator/invoke.js +76 -0
- package/dist/src/orchestrator/invoke.js.map +1 -0
- package/dist/src/orchestrator/post-coder.d.ts +10 -0
- package/dist/src/orchestrator/post-coder.d.ts.map +1 -0
- package/dist/src/orchestrator/post-coder.js +198 -0
- package/dist/src/orchestrator/post-coder.js.map +1 -0
- package/dist/src/orchestrator/post-reviewer.d.ts +10 -0
- package/dist/src/orchestrator/post-reviewer.d.ts.map +1 -0
- package/dist/src/orchestrator/post-reviewer.js +199 -0
- package/dist/src/orchestrator/post-reviewer.js.map +1 -0
- package/dist/src/orchestrator/reviewer.d.ts +35 -0
- package/dist/src/orchestrator/reviewer.d.ts.map +1 -0
- package/dist/src/orchestrator/reviewer.js +237 -0
- package/dist/src/orchestrator/reviewer.js.map +1 -0
- package/dist/src/orchestrator/schemas.d.ts +10 -0
- package/dist/src/orchestrator/schemas.d.ts.map +1 -0
- package/dist/src/orchestrator/schemas.js +81 -0
- package/dist/src/orchestrator/schemas.js.map +1 -0
- package/dist/src/orchestrator/task-selector.d.ts +102 -0
- package/dist/src/orchestrator/task-selector.d.ts.map +1 -0
- package/dist/src/orchestrator/task-selector.js +326 -0
- package/dist/src/orchestrator/task-selector.js.map +1 -0
- package/dist/src/orchestrator/types.d.ts +74 -0
- package/dist/src/orchestrator/types.d.ts.map +1 -0
- package/dist/src/orchestrator/types.js +5 -0
- package/dist/src/orchestrator/types.js.map +1 -0
- package/dist/src/prompts/coder.d.ts +36 -0
- package/dist/src/prompts/coder.d.ts.map +1 -0
- package/dist/src/prompts/coder.js +303 -0
- package/dist/src/prompts/coder.js.map +1 -0
- package/dist/src/prompts/prompt-helpers.d.ts +51 -0
- package/dist/src/prompts/prompt-helpers.d.ts.map +1 -0
- package/dist/src/prompts/prompt-helpers.js +299 -0
- package/dist/src/prompts/prompt-helpers.js.map +1 -0
- package/dist/src/prompts/reviewer.d.ts +40 -0
- package/dist/src/prompts/reviewer.d.ts.map +1 -0
- package/dist/src/prompts/reviewer.js +416 -0
- package/dist/src/prompts/reviewer.js.map +1 -0
- package/dist/src/providers/claude.d.ts +53 -0
- package/dist/src/providers/claude.d.ts.map +1 -0
- package/dist/src/providers/claude.js +227 -0
- package/dist/src/providers/claude.js.map +1 -0
- package/dist/src/providers/codex.d.ts +53 -0
- package/dist/src/providers/codex.d.ts.map +1 -0
- package/dist/src/providers/codex.js +253 -0
- package/dist/src/providers/codex.js.map +1 -0
- package/dist/src/providers/gemini.d.ts +58 -0
- package/dist/src/providers/gemini.d.ts.map +1 -0
- package/dist/src/providers/gemini.js +240 -0
- package/dist/src/providers/gemini.js.map +1 -0
- package/dist/src/providers/interface.d.ts +185 -0
- package/dist/src/providers/interface.d.ts.map +1 -0
- package/dist/src/providers/interface.js +92 -0
- package/dist/src/providers/interface.js.map +1 -0
- package/dist/src/providers/invocation-logger.d.ts +97 -0
- package/dist/src/providers/invocation-logger.d.ts.map +1 -0
- package/dist/src/providers/invocation-logger.js +378 -0
- package/dist/src/providers/invocation-logger.js.map +1 -0
- package/dist/src/providers/openai.d.ts +53 -0
- package/dist/src/providers/openai.d.ts.map +1 -0
- package/dist/src/providers/openai.js +230 -0
- package/dist/src/providers/openai.js.map +1 -0
- package/dist/src/providers/registry.d.ts +100 -0
- package/dist/src/providers/registry.d.ts.map +1 -0
- package/dist/src/providers/registry.js +170 -0
- package/dist/src/providers/registry.js.map +1 -0
- package/dist/src/routes/activity.d.ts +7 -0
- package/dist/src/routes/activity.d.ts.map +1 -0
- package/dist/src/routes/activity.js +252 -0
- package/dist/src/routes/activity.js.map +1 -0
- package/dist/src/routes/config.d.ts +7 -0
- package/dist/src/routes/config.d.ts.map +1 -0
- package/dist/src/routes/config.js +521 -0
- package/dist/src/routes/config.js.map +1 -0
- package/dist/src/routes/health.d.ts +7 -0
- package/dist/src/routes/health.d.ts.map +1 -0
- package/dist/src/routes/health.js +172 -0
- package/dist/src/routes/health.js.map +1 -0
- package/dist/src/routes/incidents.d.ts +7 -0
- package/dist/src/routes/incidents.d.ts.map +1 -0
- package/dist/src/routes/incidents.js +117 -0
- package/dist/src/routes/incidents.js.map +1 -0
- package/dist/src/routes/projects.d.ts +7 -0
- package/dist/src/routes/projects.d.ts.map +1 -0
- package/dist/src/routes/projects.js +398 -0
- package/dist/src/routes/projects.js.map +1 -0
- package/dist/src/routes/runners.d.ts +7 -0
- package/dist/src/routes/runners.d.ts.map +1 -0
- package/dist/src/routes/runners.js +242 -0
- package/dist/src/routes/runners.js.map +1 -0
- package/dist/src/routes/tasks.d.ts +7 -0
- package/dist/src/routes/tasks.d.ts.map +1 -0
- package/dist/src/routes/tasks.js +1007 -0
- package/dist/src/routes/tasks.js.map +1 -0
- package/dist/src/runners/activity-log.d.ts +65 -0
- package/dist/src/runners/activity-log.d.ts.map +1 -0
- package/dist/src/runners/activity-log.js +140 -0
- package/dist/src/runners/activity-log.js.map +1 -0
- package/dist/src/runners/cron.d.ts +30 -0
- package/dist/src/runners/cron.d.ts.map +1 -0
- package/dist/src/runners/cron.js +333 -0
- package/dist/src/runners/cron.js.map +1 -0
- package/dist/src/runners/daemon.d.ts +71 -0
- package/dist/src/runners/daemon.d.ts.map +1 -0
- package/dist/src/runners/daemon.js +233 -0
- package/dist/src/runners/daemon.js.map +1 -0
- package/dist/src/runners/global-db.d.ts +31 -0
- package/dist/src/runners/global-db.d.ts.map +1 -0
- package/dist/src/runners/global-db.js +220 -0
- package/dist/src/runners/global-db.js.map +1 -0
- package/dist/src/runners/hang-detector.d.ts +38 -0
- package/dist/src/runners/hang-detector.d.ts.map +1 -0
- package/dist/src/runners/hang-detector.js +130 -0
- package/dist/src/runners/hang-detector.js.map +1 -0
- package/dist/src/runners/heartbeat.d.ts +39 -0
- package/dist/src/runners/heartbeat.d.ts.map +1 -0
- package/dist/src/runners/heartbeat.js +71 -0
- package/dist/src/runners/heartbeat.js.map +1 -0
- package/dist/src/runners/lock.d.ts +47 -0
- package/dist/src/runners/lock.d.ts.map +1 -0
- package/dist/src/runners/lock.js +140 -0
- package/dist/src/runners/lock.js.map +1 -0
- package/dist/src/runners/orchestrator-loop.d.ts +20 -0
- package/dist/src/runners/orchestrator-loop.d.ts.map +1 -0
- package/dist/src/runners/orchestrator-loop.js +208 -0
- package/dist/src/runners/orchestrator-loop.js.map +1 -0
- package/dist/src/runners/projects.d.ts +96 -0
- package/dist/src/runners/projects.d.ts.map +1 -0
- package/dist/src/runners/projects.js +243 -0
- package/dist/src/runners/projects.js.map +1 -0
- package/dist/src/runners/wakeup.d.ts +37 -0
- package/dist/src/runners/wakeup.d.ts.map +1 -0
- package/dist/src/runners/wakeup.js +355 -0
- package/dist/src/runners/wakeup.js.map +1 -0
- package/dist/src/utils/validation.d.ts +22 -0
- package/dist/src/utils/validation.d.ts.map +1 -0
- package/dist/src/utils/validation.js +50 -0
- package/dist/src/utils/validation.js.map +1 -0
- package/dist/utils/sqlite.d.ts +17 -0
- package/dist/utils/sqlite.d.ts.map +1 -0
- package/dist/utils/sqlite.js +27 -0
- package/dist/utils/sqlite.js.map +1 -0
- package/dist/utils/storage-cache.d.ts +33 -0
- package/dist/utils/storage-cache.d.ts.map +1 -0
- package/dist/utils/storage-cache.js +81 -0
- package/dist/utils/storage-cache.js.map +1 -0
- package/dist/utils/validation.d.ts +22 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +51 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +39 -0
- package/src/index.ts +199 -0
- package/src/routes/activity.ts +302 -0
- package/src/routes/config.ts +723 -0
- package/src/routes/credit-alerts.ts +73 -0
- package/src/routes/health.ts +219 -0
- package/src/routes/incidents.ts +131 -0
- package/src/routes/projects.ts +854 -0
- package/src/routes/runners.ts +357 -0
- package/src/routes/skills.ts +127 -0
- package/src/routes/storage.ts +108 -0
- package/src/routes/tasks.ts +1372 -0
- package/src/utils/sqlite.ts +36 -0
- package/src/utils/storage-cache.ts +107 -0
- package/src/utils/validation.ts +61 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration manifest management
|
|
3
|
+
* Handles reading, parsing, and validating the migration manifest
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
// Cache for package root to avoid repeated filesystem operations
|
|
10
|
+
let _packageRoot = null;
|
|
11
|
+
/**
|
|
12
|
+
* Get the CLI package root directory
|
|
13
|
+
* Works whether running from src/ or dist/
|
|
14
|
+
*/
|
|
15
|
+
function getPackageRoot() {
|
|
16
|
+
if (_packageRoot)
|
|
17
|
+
return _packageRoot;
|
|
18
|
+
// Try multiple strategies to find the package root
|
|
19
|
+
const candidates = [];
|
|
20
|
+
// Strategy 1: Check process.argv[1] - this is the executed script path
|
|
21
|
+
if (process.argv[1]) {
|
|
22
|
+
let dir = dirname(process.argv[1]);
|
|
23
|
+
for (let i = 0; i < 5; i++) {
|
|
24
|
+
candidates.push(dir);
|
|
25
|
+
dir = dirname(dir);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Strategy 2: Check require.main.filename if available
|
|
29
|
+
// In ESM, `require` is not defined, so guard with typeof.
|
|
30
|
+
if (typeof require !== 'undefined' && require.main?.filename) {
|
|
31
|
+
let dir = dirname(require.main.filename);
|
|
32
|
+
for (let i = 0; i < 5; i++) {
|
|
33
|
+
candidates.push(dir);
|
|
34
|
+
dir = dirname(dir);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Strategy 3: Check __dirname of this module (works in CommonJS)
|
|
38
|
+
// In compiled output this will be dist/migrations/
|
|
39
|
+
if (typeof __dirname !== 'undefined') {
|
|
40
|
+
let dir = __dirname;
|
|
41
|
+
for (let i = 0; i < 5; i++) {
|
|
42
|
+
candidates.push(dir);
|
|
43
|
+
dir = dirname(dir);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Find the first candidate that contains package.json with name 'steroids-cli'
|
|
47
|
+
for (const dir of candidates) {
|
|
48
|
+
const pkgPath = join(dir, 'package.json');
|
|
49
|
+
if (existsSync(pkgPath)) {
|
|
50
|
+
try {
|
|
51
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
52
|
+
if (pkg.name === 'steroids-cli') {
|
|
53
|
+
_packageRoot = dir;
|
|
54
|
+
return dir;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch { /* ignore */ }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Last resort: try cwd (useful during development)
|
|
61
|
+
const cwdPkg = join(process.cwd(), 'package.json');
|
|
62
|
+
if (existsSync(cwdPkg)) {
|
|
63
|
+
try {
|
|
64
|
+
const pkg = JSON.parse(readFileSync(cwdPkg, 'utf-8'));
|
|
65
|
+
if (pkg.name === 'steroids-cli') {
|
|
66
|
+
_packageRoot = process.cwd();
|
|
67
|
+
return process.cwd();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch { /* ignore */ }
|
|
71
|
+
}
|
|
72
|
+
throw new Error('Could not locate steroids-cli package root');
|
|
73
|
+
}
|
|
74
|
+
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours
|
|
75
|
+
const GLOBAL_STEROIDS_DIR = join(homedir(), '.steroids');
|
|
76
|
+
const CACHE_DIR = join(GLOBAL_STEROIDS_DIR, 'migrations');
|
|
77
|
+
const CACHE_FILE = join(CACHE_DIR, 'manifest-cache.json');
|
|
78
|
+
/**
|
|
79
|
+
* Get the path to the bundled manifest (in the package)
|
|
80
|
+
*/
|
|
81
|
+
export function getBundledManifestPath() {
|
|
82
|
+
// Resolve relative to CLI package root, not cwd
|
|
83
|
+
return join(getPackageRoot(), 'migrations', 'manifest.json');
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get the path to a migration file (in the package)
|
|
87
|
+
*/
|
|
88
|
+
export function getMigrationFilePath(filename) {
|
|
89
|
+
return join(getPackageRoot(), 'migrations', filename);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the path to the cached manifest
|
|
93
|
+
*/
|
|
94
|
+
export function getCachedManifestPath() {
|
|
95
|
+
return join(CACHE_DIR, 'manifest.json');
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Read the bundled manifest from the package
|
|
99
|
+
*/
|
|
100
|
+
export function readBundledManifest() {
|
|
101
|
+
const manifestPath = getBundledManifestPath();
|
|
102
|
+
if (!existsSync(manifestPath)) {
|
|
103
|
+
throw new Error(`Bundled manifest not found at: ${manifestPath}`);
|
|
104
|
+
}
|
|
105
|
+
const content = readFileSync(manifestPath, 'utf-8');
|
|
106
|
+
return parseManifest(content);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Read the cached manifest if it exists and is valid
|
|
110
|
+
*/
|
|
111
|
+
export function readCachedManifest() {
|
|
112
|
+
if (!existsSync(CACHE_FILE)) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const cacheContent = readFileSync(CACHE_FILE, 'utf-8');
|
|
117
|
+
const cache = JSON.parse(cacheContent);
|
|
118
|
+
// Check if cache is still valid
|
|
119
|
+
if (Date.now() - cache.fetchedAt > CACHE_TTL) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return cache.manifest;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Save manifest to cache
|
|
130
|
+
*/
|
|
131
|
+
export function cacheManifest(manifest) {
|
|
132
|
+
if (!existsSync(CACHE_DIR)) {
|
|
133
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
134
|
+
}
|
|
135
|
+
const cache = {
|
|
136
|
+
fetchedAt: Date.now(),
|
|
137
|
+
manifest,
|
|
138
|
+
};
|
|
139
|
+
writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
140
|
+
// Also save the manifest itself for offline access
|
|
141
|
+
writeFileSync(getCachedManifestPath(), JSON.stringify(manifest, null, 2));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Parse and validate manifest content
|
|
145
|
+
*/
|
|
146
|
+
export function parseManifest(content) {
|
|
147
|
+
const manifest = JSON.parse(content);
|
|
148
|
+
validateManifest(manifest);
|
|
149
|
+
return manifest;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Validate manifest structure
|
|
153
|
+
*/
|
|
154
|
+
export function validateManifest(manifest) {
|
|
155
|
+
if (!manifest.version) {
|
|
156
|
+
throw new Error('Manifest missing version field');
|
|
157
|
+
}
|
|
158
|
+
if (typeof manifest.latestDbVersion !== 'number' || manifest.latestDbVersion < 1) {
|
|
159
|
+
throw new Error('Manifest missing or invalid latestDbVersion field');
|
|
160
|
+
}
|
|
161
|
+
if (!Array.isArray(manifest.migrations)) {
|
|
162
|
+
throw new Error('Manifest missing migrations array');
|
|
163
|
+
}
|
|
164
|
+
// Validate each migration entry
|
|
165
|
+
for (const migration of manifest.migrations) {
|
|
166
|
+
validateMigrationEntry(migration);
|
|
167
|
+
}
|
|
168
|
+
// Validate migrations are in order
|
|
169
|
+
const ids = manifest.migrations.map(m => m.id);
|
|
170
|
+
for (let i = 1; i < ids.length; i++) {
|
|
171
|
+
if (ids[i] <= ids[i - 1]) {
|
|
172
|
+
throw new Error(`Migrations not in order: ${ids[i - 1]} followed by ${ids[i]}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Validate latestDbVersion matches
|
|
176
|
+
if (manifest.migrations.length > 0) {
|
|
177
|
+
const maxId = Math.max(...ids);
|
|
178
|
+
if (maxId !== manifest.latestDbVersion) {
|
|
179
|
+
throw new Error(`latestDbVersion (${manifest.latestDbVersion}) does not match highest migration id (${maxId})`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Validate a single migration entry
|
|
185
|
+
*/
|
|
186
|
+
function validateMigrationEntry(entry) {
|
|
187
|
+
if (typeof entry.id !== 'number' || entry.id < 1) {
|
|
188
|
+
throw new Error(`Invalid migration id: ${entry.id}`);
|
|
189
|
+
}
|
|
190
|
+
if (!entry.name || typeof entry.name !== 'string') {
|
|
191
|
+
throw new Error(`Migration ${entry.id} missing name`);
|
|
192
|
+
}
|
|
193
|
+
if (!entry.file || typeof entry.file !== 'string') {
|
|
194
|
+
throw new Error(`Migration ${entry.id} missing file`);
|
|
195
|
+
}
|
|
196
|
+
if (!entry.description || typeof entry.description !== 'string') {
|
|
197
|
+
throw new Error(`Migration ${entry.id} missing description`);
|
|
198
|
+
}
|
|
199
|
+
if (!entry.cliVersion || typeof entry.cliVersion !== 'string') {
|
|
200
|
+
throw new Error(`Migration ${entry.id} missing cliVersion`);
|
|
201
|
+
}
|
|
202
|
+
// Checksum can be empty for new migrations
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Calculate SHA256 checksum for migration file content
|
|
206
|
+
*/
|
|
207
|
+
export function calculateChecksum(content) {
|
|
208
|
+
const hash = createHash('sha256');
|
|
209
|
+
hash.update(content);
|
|
210
|
+
return `sha256:${hash.digest('hex')}`;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Verify checksum matches
|
|
214
|
+
*/
|
|
215
|
+
export function verifyChecksum(content, expectedChecksum) {
|
|
216
|
+
if (!expectedChecksum) {
|
|
217
|
+
// No checksum to verify
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
const actual = calculateChecksum(content);
|
|
221
|
+
return actual === expectedChecksum;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Find pending migrations that need to be applied
|
|
225
|
+
*/
|
|
226
|
+
export function findPendingMigrations(manifest, appliedMigrations) {
|
|
227
|
+
const appliedIds = new Set(appliedMigrations.map(m => m.id));
|
|
228
|
+
return manifest.migrations.filter(m => !appliedIds.has(m.id));
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Find migrations to rollback (applied but not in manifest)
|
|
232
|
+
*/
|
|
233
|
+
export function findOrphanedMigrations(manifest, appliedMigrations) {
|
|
234
|
+
const manifestIds = new Set(manifest.migrations.map(m => m.id));
|
|
235
|
+
return appliedMigrations.filter(m => !manifestIds.has(m.id));
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get migration entry by ID
|
|
239
|
+
*/
|
|
240
|
+
export function getMigrationById(manifest, id) {
|
|
241
|
+
return manifest.migrations.find(m => m.id === id) ?? null;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get the current supported database version range for this CLI
|
|
245
|
+
*/
|
|
246
|
+
export function getCliSupportedVersions(manifest) {
|
|
247
|
+
if (manifest.migrations.length === 0) {
|
|
248
|
+
return { min: 0, max: 0 };
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
min: 1, // Always support from version 1
|
|
252
|
+
max: manifest.latestDbVersion,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../../src/migrations/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration runner
|
|
3
|
+
* Applies and rolls back database migrations with transaction safety
|
|
4
|
+
*/
|
|
5
|
+
import Database from 'better-sqlite3';
|
|
6
|
+
import { MigrationManifest, MigrationEntry, AppliedMigration } from './manifest.js';
|
|
7
|
+
/**
|
|
8
|
+
* Result of a migration operation
|
|
9
|
+
*/
|
|
10
|
+
export interface MigrationResult {
|
|
11
|
+
success: boolean;
|
|
12
|
+
applied: string[];
|
|
13
|
+
failed?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Migration SQL sections
|
|
18
|
+
*/
|
|
19
|
+
interface MigrationSql {
|
|
20
|
+
up: string;
|
|
21
|
+
down: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Parse migration file into UP and DOWN sections
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseMigrationFile(content: string): MigrationSql;
|
|
27
|
+
/**
|
|
28
|
+
* Read migration file content
|
|
29
|
+
*/
|
|
30
|
+
export declare function readMigrationFile(entry: MigrationEntry): string;
|
|
31
|
+
/**
|
|
32
|
+
* Get applied migrations from database
|
|
33
|
+
*/
|
|
34
|
+
export declare function getAppliedMigrations(db: Database.Database): AppliedMigration[];
|
|
35
|
+
/**
|
|
36
|
+
* Get current database version
|
|
37
|
+
*/
|
|
38
|
+
export declare function getDatabaseVersion(db: Database.Database): number;
|
|
39
|
+
/**
|
|
40
|
+
* Create backup of database before migration
|
|
41
|
+
*/
|
|
42
|
+
export declare function createBackup(dbPath: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Apply a single migration
|
|
45
|
+
* Handles idempotent migrations (e.g., duplicate column errors are treated as success)
|
|
46
|
+
*/
|
|
47
|
+
export declare function applyMigration(db: Database.Database, entry: MigrationEntry, content: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Rollback a single migration
|
|
50
|
+
*/
|
|
51
|
+
export declare function rollbackMigration(db: Database.Database, entry: MigrationEntry, content: string): void;
|
|
52
|
+
/**
|
|
53
|
+
* Run all pending migrations
|
|
54
|
+
*/
|
|
55
|
+
export declare function runMigrations(db: Database.Database, manifest: MigrationManifest, options?: {
|
|
56
|
+
toVersion?: number;
|
|
57
|
+
dryRun?: boolean;
|
|
58
|
+
}): MigrationResult;
|
|
59
|
+
/**
|
|
60
|
+
* Rollback to a specific version
|
|
61
|
+
*/
|
|
62
|
+
export declare function rollbackToVersion(db: Database.Database, manifest: MigrationManifest, targetVersion: number): MigrationResult;
|
|
63
|
+
/**
|
|
64
|
+
* Get migration status
|
|
65
|
+
*/
|
|
66
|
+
export interface MigrationStatus {
|
|
67
|
+
currentVersion: number;
|
|
68
|
+
latestVersion: number;
|
|
69
|
+
isUpToDate: boolean;
|
|
70
|
+
pending: MigrationEntry[];
|
|
71
|
+
applied: AppliedMigration[];
|
|
72
|
+
}
|
|
73
|
+
export declare function getMigrationStatus(db: Database.Database, manifest: MigrationManifest): MigrationStatus;
|
|
74
|
+
/**
|
|
75
|
+
* Check and apply any pending migrations automatically
|
|
76
|
+
* Returns true if migrations were applied, false if already up to date
|
|
77
|
+
*/
|
|
78
|
+
export declare function autoMigrate(db: Database.Database, dbPath?: string): {
|
|
79
|
+
applied: boolean;
|
|
80
|
+
migrations: string[];
|
|
81
|
+
error?: string;
|
|
82
|
+
};
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../../src/migrations/runner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAMjB,MAAM,eAAe,CAAC;AAEvB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CA8BhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAQ/D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,gBAAgB,EAAE,CAQ9E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAiBhE;AA4BD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAyBnD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,MAAM,GACd,IAAI,CAwCN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,MAAM,GACd,IAAI,CA4BN;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CACb,GACL,eAAe,CA+CjB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,MAAM,GACpB,eAAe,CA8CjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,QAAQ,EAAE,iBAAiB,GAC1B,eAAe,CAYjB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG;IACnE,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAyCA"}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration runner
|
|
3
|
+
* Applies and rolls back database migrations with transaction safety
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, existsSync, copyFileSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import { join, dirname } from 'node:path';
|
|
7
|
+
import { readBundledManifest, getMigrationFilePath, calculateChecksum, verifyChecksum, findPendingMigrations, } from './manifest.js';
|
|
8
|
+
/**
|
|
9
|
+
* Parse migration file into UP and DOWN sections
|
|
10
|
+
*/
|
|
11
|
+
export function parseMigrationFile(content) {
|
|
12
|
+
const lines = content.split('\n');
|
|
13
|
+
let currentSection = 'none';
|
|
14
|
+
const upLines = [];
|
|
15
|
+
const downLines = [];
|
|
16
|
+
for (const line of lines) {
|
|
17
|
+
const trimmed = line.trim().toUpperCase();
|
|
18
|
+
if (trimmed === '-- UP') {
|
|
19
|
+
currentSection = 'up';
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (trimmed === '-- DOWN') {
|
|
23
|
+
currentSection = 'down';
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (currentSection === 'up') {
|
|
27
|
+
upLines.push(line);
|
|
28
|
+
}
|
|
29
|
+
else if (currentSection === 'down') {
|
|
30
|
+
downLines.push(line);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
up: upLines.join('\n').trim(),
|
|
35
|
+
down: downLines.join('\n').trim(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Read migration file content
|
|
40
|
+
*/
|
|
41
|
+
export function readMigrationFile(entry) {
|
|
42
|
+
const filePath = getMigrationFilePath(entry.file);
|
|
43
|
+
if (!existsSync(filePath)) {
|
|
44
|
+
throw new Error(`Migration file not found: ${filePath}`);
|
|
45
|
+
}
|
|
46
|
+
return readFileSync(filePath, 'utf-8');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get applied migrations from database
|
|
50
|
+
*/
|
|
51
|
+
export function getAppliedMigrations(db) {
|
|
52
|
+
try {
|
|
53
|
+
const rows = db.prepare('SELECT id, name, checksum, applied_at FROM _migrations ORDER BY id').all();
|
|
54
|
+
return rows;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Table may not exist yet
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get current database version
|
|
63
|
+
*/
|
|
64
|
+
export function getDatabaseVersion(db) {
|
|
65
|
+
try {
|
|
66
|
+
const row = db.prepare('SELECT value FROM _schema WHERE key = ?').get('version');
|
|
67
|
+
if (!row)
|
|
68
|
+
return 0;
|
|
69
|
+
// Parse version - could be semver "0.1.0" or just a number
|
|
70
|
+
const version = row.value;
|
|
71
|
+
if (/^\d+$/.test(version)) {
|
|
72
|
+
return parseInt(version, 10);
|
|
73
|
+
}
|
|
74
|
+
// For semver, use the number of applied migrations as the version
|
|
75
|
+
const migrations = getAppliedMigrations(db);
|
|
76
|
+
return migrations.length;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Update database version in _schema table
|
|
84
|
+
*/
|
|
85
|
+
function updateDatabaseVersion(db, version, migrationName) {
|
|
86
|
+
db.prepare('INSERT OR REPLACE INTO _schema (key, value) VALUES (?, ?)').run('version', version.toString());
|
|
87
|
+
db.prepare('INSERT OR REPLACE INTO _schema (key, value) VALUES (?, ?)').run('last_migration', migrationName);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Record applied migration
|
|
91
|
+
*/
|
|
92
|
+
function recordMigration(db, entry, checksum) {
|
|
93
|
+
db.prepare('INSERT INTO _migrations (id, name, checksum) VALUES (?, ?, ?)').run(entry.id, entry.name, checksum);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Remove migration record (for rollback)
|
|
97
|
+
*/
|
|
98
|
+
function removeMigrationRecord(db, id) {
|
|
99
|
+
db.prepare('DELETE FROM _migrations WHERE id = ?').run(id);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create backup of database before migration
|
|
103
|
+
*/
|
|
104
|
+
export function createBackup(dbPath) {
|
|
105
|
+
const steroidsDir = dirname(dbPath);
|
|
106
|
+
const backupDir = join(steroidsDir, 'backup');
|
|
107
|
+
if (!existsSync(backupDir)) {
|
|
108
|
+
mkdirSync(backupDir, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
111
|
+
const backupPath = join(backupDir, `pre-migrate-${timestamp}.db`);
|
|
112
|
+
copyFileSync(dbPath, backupPath);
|
|
113
|
+
// Also copy WAL and SHM files if they exist
|
|
114
|
+
const walPath = `${dbPath}-wal`;
|
|
115
|
+
const shmPath = `${dbPath}-shm`;
|
|
116
|
+
if (existsSync(walPath)) {
|
|
117
|
+
copyFileSync(walPath, `${backupPath}-wal`);
|
|
118
|
+
}
|
|
119
|
+
if (existsSync(shmPath)) {
|
|
120
|
+
copyFileSync(shmPath, `${backupPath}-shm`);
|
|
121
|
+
}
|
|
122
|
+
return backupPath;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Apply a single migration
|
|
126
|
+
* Handles idempotent migrations (e.g., duplicate column errors are treated as success)
|
|
127
|
+
*/
|
|
128
|
+
export function applyMigration(db, entry, content) {
|
|
129
|
+
const parsed = parseMigrationFile(content);
|
|
130
|
+
const checksum = calculateChecksum(content);
|
|
131
|
+
if (entry.checksum && !verifyChecksum(content, entry.checksum)) {
|
|
132
|
+
throw new Error(`Checksum mismatch for migration ${entry.name}. ` +
|
|
133
|
+
`Expected ${entry.checksum}, got ${checksum}. ` +
|
|
134
|
+
'The migration file may have been corrupted or tampered with.');
|
|
135
|
+
}
|
|
136
|
+
if (!parsed.up) {
|
|
137
|
+
throw new Error(`Migration ${entry.name} has no UP section`);
|
|
138
|
+
}
|
|
139
|
+
// Apply the migration in a transaction
|
|
140
|
+
// Handle idempotent cases like "duplicate column name" or "table already exists"
|
|
141
|
+
const transaction = db.transaction(() => {
|
|
142
|
+
try {
|
|
143
|
+
db.exec(parsed.up);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
147
|
+
// These errors indicate the migration was already effectively applied
|
|
148
|
+
const idempotentErrors = [
|
|
149
|
+
'duplicate column name',
|
|
150
|
+
'table already exists',
|
|
151
|
+
'index already exists',
|
|
152
|
+
];
|
|
153
|
+
const isIdempotent = idempotentErrors.some(e => msg.toLowerCase().includes(e));
|
|
154
|
+
if (!isIdempotent) {
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
// Migration already applied, continue to record it
|
|
158
|
+
}
|
|
159
|
+
recordMigration(db, entry, checksum);
|
|
160
|
+
updateDatabaseVersion(db, entry.id, entry.name);
|
|
161
|
+
});
|
|
162
|
+
transaction();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Rollback a single migration
|
|
166
|
+
*/
|
|
167
|
+
export function rollbackMigration(db, entry, content) {
|
|
168
|
+
const parsed = parseMigrationFile(content);
|
|
169
|
+
if (!parsed.down) {
|
|
170
|
+
throw new Error(`Migration ${entry.name} has no DOWN section - cannot rollback`);
|
|
171
|
+
}
|
|
172
|
+
// Rollback in a transaction
|
|
173
|
+
const transaction = db.transaction(() => {
|
|
174
|
+
db.exec(parsed.down);
|
|
175
|
+
removeMigrationRecord(db, entry.id);
|
|
176
|
+
// Update version to previous migration
|
|
177
|
+
const previousId = entry.id - 1;
|
|
178
|
+
if (previousId > 0) {
|
|
179
|
+
const manifest = readBundledManifest();
|
|
180
|
+
const previousMigration = manifest.migrations.find(m => m.id === previousId);
|
|
181
|
+
if (previousMigration) {
|
|
182
|
+
updateDatabaseVersion(db, previousId, previousMigration.name);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// No more migrations, set version to 0
|
|
187
|
+
db.prepare('DELETE FROM _schema WHERE key = ?').run('version');
|
|
188
|
+
db.prepare('DELETE FROM _schema WHERE key = ?').run('last_migration');
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
transaction();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Run all pending migrations
|
|
195
|
+
*/
|
|
196
|
+
export function runMigrations(db, manifest, options = {}) {
|
|
197
|
+
const applied = getAppliedMigrations(db);
|
|
198
|
+
const pending = findPendingMigrations(manifest, applied);
|
|
199
|
+
// Filter by target version if specified
|
|
200
|
+
const migrationsToApply = options.toVersion
|
|
201
|
+
? pending.filter(m => m.id <= options.toVersion)
|
|
202
|
+
: pending;
|
|
203
|
+
if (migrationsToApply.length === 0) {
|
|
204
|
+
return {
|
|
205
|
+
success: true,
|
|
206
|
+
applied: [],
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// Sort by ID to ensure correct order
|
|
210
|
+
migrationsToApply.sort((a, b) => a.id - b.id);
|
|
211
|
+
if (options.dryRun) {
|
|
212
|
+
return {
|
|
213
|
+
success: true,
|
|
214
|
+
applied: migrationsToApply.map(m => m.name),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const appliedNames = [];
|
|
218
|
+
for (const migration of migrationsToApply) {
|
|
219
|
+
try {
|
|
220
|
+
const content = readMigrationFile(migration);
|
|
221
|
+
applyMigration(db, migration, content);
|
|
222
|
+
appliedNames.push(migration.name);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
return {
|
|
226
|
+
success: false,
|
|
227
|
+
applied: appliedNames,
|
|
228
|
+
failed: migration.name,
|
|
229
|
+
error: error instanceof Error ? error.message : String(error),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
success: true,
|
|
235
|
+
applied: appliedNames,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Rollback to a specific version
|
|
240
|
+
*/
|
|
241
|
+
export function rollbackToVersion(db, manifest, targetVersion) {
|
|
242
|
+
const applied = getAppliedMigrations(db);
|
|
243
|
+
// Find migrations to rollback (those with id > targetVersion)
|
|
244
|
+
const toRollback = applied
|
|
245
|
+
.filter(m => m.id > targetVersion)
|
|
246
|
+
.sort((a, b) => b.id - a.id); // Rollback in reverse order
|
|
247
|
+
if (toRollback.length === 0) {
|
|
248
|
+
return {
|
|
249
|
+
success: true,
|
|
250
|
+
applied: [],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const rolledBack = [];
|
|
254
|
+
for (const migration of toRollback) {
|
|
255
|
+
const entry = manifest.migrations.find(m => m.id === migration.id);
|
|
256
|
+
if (!entry) {
|
|
257
|
+
return {
|
|
258
|
+
success: false,
|
|
259
|
+
applied: rolledBack,
|
|
260
|
+
failed: migration.name,
|
|
261
|
+
error: `Migration ${migration.name} not found in manifest`,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
const content = readMigrationFile(entry);
|
|
266
|
+
rollbackMigration(db, entry, content);
|
|
267
|
+
rolledBack.push(migration.name);
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
return {
|
|
271
|
+
success: false,
|
|
272
|
+
applied: rolledBack,
|
|
273
|
+
failed: migration.name,
|
|
274
|
+
error: error instanceof Error ? error.message : String(error),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
success: true,
|
|
280
|
+
applied: rolledBack,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
export function getMigrationStatus(db, manifest) {
|
|
284
|
+
const applied = getAppliedMigrations(db);
|
|
285
|
+
const pending = findPendingMigrations(manifest, applied);
|
|
286
|
+
const currentVersion = applied.length > 0 ? Math.max(...applied.map(m => m.id)) : 0;
|
|
287
|
+
return {
|
|
288
|
+
currentVersion,
|
|
289
|
+
latestVersion: manifest.latestDbVersion,
|
|
290
|
+
isUpToDate: pending.length === 0,
|
|
291
|
+
pending,
|
|
292
|
+
applied,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Check and apply any pending migrations automatically
|
|
297
|
+
* Returns true if migrations were applied, false if already up to date
|
|
298
|
+
*/
|
|
299
|
+
export function autoMigrate(db, dbPath) {
|
|
300
|
+
try {
|
|
301
|
+
const manifest = readBundledManifest();
|
|
302
|
+
const status = getMigrationStatus(db, manifest);
|
|
303
|
+
if (status.isUpToDate) {
|
|
304
|
+
return { applied: false, migrations: [] };
|
|
305
|
+
}
|
|
306
|
+
// Create backup before migrating if path provided
|
|
307
|
+
if (dbPath) {
|
|
308
|
+
try {
|
|
309
|
+
createBackup(dbPath);
|
|
310
|
+
}
|
|
311
|
+
catch (backupErr) {
|
|
312
|
+
// Log but don't fail - backup is optional
|
|
313
|
+
console.error('Warning: Could not create backup before migration:', backupErr);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// Apply pending migrations
|
|
317
|
+
const result = runMigrations(db, manifest);
|
|
318
|
+
if (!result.success) {
|
|
319
|
+
return {
|
|
320
|
+
applied: false,
|
|
321
|
+
migrations: result.applied,
|
|
322
|
+
error: `Migration failed at ${result.failed}: ${result.error}`,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
applied: result.applied.length > 0,
|
|
327
|
+
migrations: result.applied,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
return {
|
|
332
|
+
applied: false,
|
|
333
|
+
migrations: [],
|
|
334
|
+
error: err instanceof Error ? err.message : String(err),
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=runner.js.map
|