main.ts

1.9 KB · raw

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";1213// Where a first-run setup puts Kepr's data, beside kepr.toml.14const DATA_DIR = "data";1516/** Starts the loops for a config and returns the app that serves it. */17function start(config: Config): Hono["fetch"] {18	const kepr = openKeprDb(config.dataDir);19	// One bucket for the sync loop and the app, so settings saved in the console reach both.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	// Bun.serve reads the port from $PORT (default 3000).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}