Use node:Sqlite

This commit is contained in:
2026-07-27 09:19:17 +00:00
parent 17e646c2e3
commit 1723b1cca1
5 changed files with 87 additions and 12 deletions
+11 -1
View File
@@ -16,7 +16,8 @@
"debug": "^4.4.3",
"dotenv": "^17.4.2",
"hono": "^4.12.26",
"kysely": "^0.29.2",
"kysely": "^0.29.4",
"kysely-node-native-sqlite": "^1.0.1",
"ws": "^8.21.0",
"zod": "^4.4.3"
},
@@ -8314,6 +8315,15 @@
"node": ">=22.0.0"
}
},
"node_modules/kysely-node-native-sqlite": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/kysely-node-native-sqlite/-/kysely-node-native-sqlite-1.0.1.tgz",
"integrity": "sha512-FHty4bi885waQMMMw2P9F+mqZUdozd1OBWQI72CffsQzbZhcOgsz3jpZRTUM1xAtG1wkz/VQAj3JavQvCdhL2w==",
"license": "ISC",
"peerDependencies": {
"kysely": ">=0.27.0"
}
},
"node_modules/language-subtag-registry": {
"version": "0.3.23",
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
+2 -1
View File
@@ -51,7 +51,8 @@
"debug": "^4.4.3",
"dotenv": "^17.4.2",
"hono": "^4.12.26",
"kysely": "^0.29.2",
"kysely": "^0.29.4",
"kysely-node-native-sqlite": "^1.0.1",
"ws": "^8.21.0",
"zod": "^4.4.3"
},
+59
View File
@@ -0,0 +1,59 @@
import { Config } from './services/config.ts';
import { Database, MigrationService } from './services/storage/index.ts';
import { Logger } from './utils/logger.ts';
/** Application composition root. */
export class App {
/**
* Construct infrastructure and validate all routes before returning a runnable app.
*/
static async create(): Promise<App> {
const config = Config.fromEnv();
const debug = new Logger('sync-server-v2');
debug('config loaded: %O', config);
// Persistence must be ready before routes accept traffic.
const database = new Database({ path: config.database.path, debug });
const migrations = new MigrationService(database, debug);
await migrations.migrateToLatest();
return new App(database);
}
private stopPromise: Promise<void> | undefined;
constructor(private readonly database: Database) {}
async start(): Promise<void> {}
/** Stop transports before releasing the database they may still use. */
async stop(): Promise<void> {
this.stopPromise ??= this.database.destroy();
await this.stopPromise;
}
}
const app = await App.create();
let shuttingDown = false;
const shutdown = (signal: NodeJS.Signals): void => {
if (shuttingDown) {
return;
}
shuttingDown = true;
void app.stop().catch((error) => {
console.error('Graceful shutdown failed after ' + signal, error);
process.exitCode = 1;
});
};
process.once('SIGINT', (): void => shutdown('SIGINT'));
process.once('SIGTERM', (): void => shutdown('SIGTERM'));
try {
await app.start();
} catch (error: unknown) {
await app.stop();
throw error;
}
+13 -9
View File
@@ -1,5 +1,6 @@
import DatabaseConstructor from 'better-sqlite3';
import { Kysely, SqliteDialect } from 'kysely';
import { CompiledQuery, Kysely } from 'kysely';
import { NodeNativeSqliteDialect } from 'kysely-node-native-sqlite';
import type { DatabaseTables } from './tables.ts';
import type { Logger } from '../../utils/logger.ts';
@@ -13,13 +14,13 @@ export type DatabaseOptions = {
};
/**
* Thin wrapper around better-sqlite3 and Kysely.
* Thin wrapper around Kysely and NodeNativeSqliteDialect (which uses node:sqlite).
*
* Owns connection setup, pragma configuration, and graceful teardown.
*/
export class Database {
private readonly debug: Logger;
private readonly sqlite: DatabaseConstructor.Database;
private readonly dialect: NodeNativeSqliteDialect;
private readonly kysely: Kysely<DatabaseTables>;
/**
@@ -32,13 +33,15 @@ export class Database {
this.debug = options.debug.extend('database');
// Create the SQLite database.
this.sqlite = new DatabaseConstructor(options.path);
this.configurePragmas();
this.dialect = new NodeNativeSqliteDialect(options.path);
// Create the Kysely database.
this.kysely = new Kysely<DatabaseTables>({
dialect: new SqliteDialect({ database: this.sqlite }),
dialect: this.dialect,
});
// Configure the SQLite pragmas.
this.configurePragmas();
}
/**
@@ -65,7 +68,8 @@ export class Database {
*/
private configurePragmas(): void {
this.debug('configuring SQLite pragmas');
this.sqlite.pragma('journal_mode = WAL');
this.sqlite.pragma('foreign_keys = ON');
this.kysely.executeQuery(CompiledQuery.raw('PRAGMA journal_mode = WAL'));
this.kysely.executeQuery(CompiledQuery.raw('PRAGMA foreign_keys = ON'));
}
}
+2 -1
View File
@@ -12,7 +12,8 @@
"allowImportingTsExtensions": true,
"noEmit": true,
"declaration": true,
"declarationMap": true
"declarationMap": true,
"types": ["node"]
},
"exclude": ["node_modules/**/*", "dist/**/*", "test"]
}