1import { join } from "node:path";2import type { Hono } from "hono";3import { createSetupApp } from "./admin/setup.ts";4import { openBucket } from "./bucket/reader.ts";5import { startSyncLoop } from "./bucket/sync.ts";6import { createApp } from "./server/app.ts";7import { startBackupLoop } from "./server/backup.ts";8import { CONFIG_FILE, type Config, ConfigError, loadConfig } from "./server/config.ts";9import { oneTimeCode } from "./server/connect.ts";10import { openKeprDb } from "./server/db.ts";11import { startMailLoop } from "./server/mail.ts";121314const DATA_DIR = "data";151617function start(config: Config): Hono["fetch"] {18 const kepr = openKeprDb(config.dataDir);19 20 const bucket = openBucket(config.bucket);21 startBackupLoop(kepr, config);22 startMailLoop(kepr, config);23 startSyncLoop({ bucket, kepr, mirrorDir: join(config.dataDir, "mirror") });24 return createApp(config, kepr, bucket).fetch;25}2627try {28 let fetch: Hono["fetch"];29 if (await Bun.file(CONFIG_FILE).exists()) {30 fetch = start(await loadConfig(CONFIG_FILE));31 } else {32 const code = oneTimeCode();33 fetch = createSetupApp({34 code,35 configPath: CONFIG_FILE,36 dataDir: DATA_DIR,37 done: (config) => {38 fetch = start(config);39 },40 }).fetch;41 console.log(42 `kepr: no ${CONFIG_FILE} yet. Open /setup in a browser and enter the code ${code.slice(0, 4)}-${code.slice(4)}`,43 );44 }45 46 const server = Bun.serve({ fetch: (request, bun) => fetch(request, bun) });47 console.log(`kepr listening on ${server.url}`);48} catch (error) {49 if (!(error instanceof ConfigError)) throw error;50 console.error(`kepr: ${error.message}`);51 process.exit(1);52}