feat: prepare six-lesson trial backend with reliable rewards and operations
Backend CI / type-check, build, tests (push) Successful in 1m0s
Backend CI / type-check, build, tests (push) Successful in 1m0s
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* WAL-safe SQLite backup via better-sqlite3 backup API (not a raw file copy).
|
||||
* Usage: DB_PATH=./data/app.db BACKUP_DIR=./backups node scripts/sqlite-backup.mjs
|
||||
*/
|
||||
import Database from 'better-sqlite3'
|
||||
import { mkdirSync, existsSync, readdirSync, statSync, unlinkSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
|
||||
const srcPath = process.env.DB_PATH ?? join(process.cwd(), 'data', 'app.db')
|
||||
const backupDir = process.env.BACKUP_DIR ?? join(process.cwd(), 'backups')
|
||||
const retentionDays = Number(process.env.BACKUP_RETENTION_DAYS ?? '0')
|
||||
|
||||
if (!existsSync(srcPath)) {
|
||||
console.error(`Source database not found: ${srcPath}`)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
mkdirSync(backupDir, { recursive: true })
|
||||
|
||||
const stamp = new Date().toISOString().replace(/[:.]/g, '-')
|
||||
const destPath = join(backupDir, `app-${stamp}.db`)
|
||||
|
||||
const src = new Database(srcPath, { readonly: true })
|
||||
try {
|
||||
await src.backup(destPath)
|
||||
} finally {
|
||||
src.close()
|
||||
}
|
||||
|
||||
const verify = new Database(destPath, { readonly: true })
|
||||
try {
|
||||
const integrity = verify.pragma('integrity_check', { simple: true })
|
||||
if (integrity !== 'ok') {
|
||||
console.error(`Backup integrity check failed: ${integrity}`)
|
||||
process.exit(1)
|
||||
}
|
||||
} finally {
|
||||
verify.close()
|
||||
}
|
||||
|
||||
console.log(`Backup written: ${destPath}`)
|
||||
|
||||
if (retentionDays > 0) {
|
||||
const cutoff = Date.now() - retentionDays * 86_400_000
|
||||
for (const name of readdirSync(backupDir)) {
|
||||
if (!name.startsWith('app-') || !name.endsWith('.db')) continue
|
||||
const full = join(backupDir, name)
|
||||
if (statSync(full).mtimeMs < cutoff) {
|
||||
unlinkSync(full)
|
||||
console.log(`Removed old backup: ${name}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user