init.ts
Raw
1import { Database } from "bun:sqlite";
2import { mkdirSync, readFileSync } from "node:fs";
3import path from "node:path";
4import * as argon2 from "argon2";
5import { DATA_DIR } from "../config.ts";
6import {
7 ADMIN_USERNAME,
8 AVATARS_DIR,
9 DB_PATH,
10 REPOS_DIR,
11} from "../constants.ts";
12
13// Ensure data directories exist
14mkdirSync(DATA_DIR, { recursive: true });
15mkdirSync(REPOS_DIR, { recursive: true });
16mkdirSync(AVATARS_DIR, { recursive: true });
17
18const db = new Database(DB_PATH);
19db.run("PRAGMA journal_mode=WAL");
20db.run("PRAGMA foreign_keys=ON");
21
22// Run schema
23const schema = readFileSync(path.join(import.meta.dir, "schema.sql"), "utf-8");
24db.run(schema);
25
26// Seed admin account if not present
27const existing = db
28 .query("SELECT id FROM users WHERE username = ?")
29 .get(ADMIN_USERNAME);
30if (!existing) {
31 const password = process.env.ADMIN_PASSWORD ?? "changeme";
32 const hash = await argon2.hash(password);
33 const now = new Date().toISOString();
34 db.run(
35 "INSERT INTO users (username, password_hash, created_at) VALUES (?, ?, ?)",
36 [ADMIN_USERNAME, hash, now],
37 );
38 console.log(
39 `Created admin account (username: ${ADMIN_USERNAME}, password: ${password})`,
40 );
41 if (password === "changeme") {
42 console.warn(
43 "WARNING: Using default admin password. Set ADMIN_PASSWORD env var before running db:init.",
44 );
45 }
46} else {
47 console.log("Admin account already exists.");
48}
49
50console.log("Database initialized at", DB_PATH);
51db.close();
52