import { join } from "node:path"; import type { Hono } from "hono"; import { createSetupApp } from "./admin/setup.ts"; import { startStorageLoop } from "./admin/storage.ts"; import { openBucket } from "./bucket/reader.ts"; import { startSyncWorker } from "./bucket/sync.ts"; import { openMirrors } from "./mirror/store.ts"; import { createApp } from "./server/app.ts"; import { startBackupLoop } from "./server/backup.ts"; import { CONFIG_FILE, type Config, ConfigError, loadConfig } from "./server/config.ts"; import { oneTimeCode } from "./server/connect.ts"; import { openKeprDb } from "./server/db.ts"; import { startMailLoop } from "./server/mail.ts"; // Where a first-run setup puts Kepr's data, beside kepr.toml. const DATA_DIR = "data"; /** Starts the loops for a config and returns the app that serves it. */ function start(config: Config): Hono["fetch"] { const kepr = openKeprDb(config.dataDir); // One bucket for the sync loop and the app, so settings saved in the console reach both. const bucket = openBucket(config.bucket); startBackupLoop(kepr, config); startMailLoop(kepr, config); const mirrorDir = join(config.dataDir, "mirror"); openMirrors(mirrorDir); // The first visitor after a new save would otherwise wait a second or two on a big repo. const syncer = startSyncWorker(config.dataDir, config.bucket); startStorageLoop({ bucket, kepr, mirrorDir }); return createApp(config, kepr, bucket, CONFIG_FILE, syncer).fetch; } try { let fetch: Hono["fetch"]; if (await Bun.file(CONFIG_FILE).exists()) { fetch = start(await loadConfig(CONFIG_FILE)); } else { const code = oneTimeCode(); fetch = createSetupApp({ code, configPath: CONFIG_FILE, dataDir: DATA_DIR, done: (config) => { fetch = start(config); }, }).fetch; console.log( `kepr: no ${CONFIG_FILE} yet. Open /setup in a browser and enter the code ${code.slice(0, 4)}-${code.slice(4)}`, ); } // Bun.serve reads the port from $PORT (default 3000). const server = Bun.serve({ fetch: (request, bun) => fetch(request, bun) }); console.log(`kepr listening on ${server.url}`); } catch (error) { if (!(error instanceof ConfigError)) throw error; console.error(`kepr: ${error.message}`); process.exit(1); }