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 { warmAtlas } from "./pages/atlas.ts";7import { createApp } from "./server/app.ts";8import { startBackupLoop } from "./server/backup.ts";9import { CONFIG_FILE, type Config, ConfigError, loadConfig } from "./server/config.ts";10import { oneTimeCode } from "./server/connect.ts";11import { openKeprDb } from "./server/db.ts";12import { startMailLoop } from "./server/mail.ts";131415const DATA_DIR = "data";161718function start(config: Config): Hono["fetch"] {19 const kepr = openKeprDb(config.dataDir);20 21 const bucket = openBucket(config.bucket);22 startBackupLoop(kepr, config);23 startMailLoop(kepr, config);24 const mirrorDir = join(config.dataDir, "mirror");25 26 startSyncLoop({27 bucket,28 kepr,29 mirrorDir,30 synced: (repo) => warmAtlas({ kepr, mirrorDir }, repo),31 });32 return createApp(config, kepr, bucket).fetch;33}3435try {36 let fetch: Hono["fetch"];37 if (await Bun.file(CONFIG_FILE).exists()) {38 fetch = start(await loadConfig(CONFIG_FILE));39 } else {40 const code = oneTimeCode();41 fetch = createSetupApp({42 code,43 configPath: CONFIG_FILE,44 dataDir: DATA_DIR,45 done: (config) => {46 fetch = start(config);47 },48 }).fetch;49 console.log(50 `kepr: no ${CONFIG_FILE} yet. Open /setup in a browser and enter the code ${code.slice(0, 4)}-${code.slice(4)}`,51 );52 }53 54 const server = Bun.serve({ fetch: (request, bun) => fetch(request, bun) });55 console.log(`kepr listening on ${server.url}`);56} catch (error) {57 if (!(error instanceof ConfigError)) throw error;58 console.error(`kepr: ${error.message}`);59 process.exit(1);60}