···11## This is a configuration file for Clippr.
22## Please copy to "config.example.toml" before starting the server,
33## otherwise it will not start. Modify as necessary.
44-## All keys that are listed are expected to be included in the config, even if not explicity declared as required.
5465## Where the server is broadcasted to.
76hostname = "localhost"
87port = 9090
99-webDomain = "https://localhost"
88+99+## Where the server will be deployed to.
1010+baseUrl = "https://localhost:9090"
10111112## For most deployments, you will want to keep the log level at "info".
1213## If you are a developer, move it down to "debug" for more information.
···2223logLevel = "info"
23242425## How the SQLite database is stored.
2525-## For experimenting, you can store the database in memory with ":memory:"
2626+## NOTE: Storing the database in-memory does not work as the schema is not properly loaded. Fixme!
2627[database]
2728## Paths can be used here.
2829name = "file:clippr.db"
···3031## How the server interacts with the ATproto network.
3132[network]
3233## What Jetstream instance to use for receiving content from the network.
3434+## Non-Bluesky relay: relay2.fire.hose.cam
3335firehose = "jetstream1.us-east.bsky.network"
3436## What DID to use for service proxying. This should be the domain that the API is accessible from.
3537## Default: "did:web:localhost%3A9090"
3638serviceDid = "did:web:localhost%3A9090"
3737-## A multibase public key to use for signing in the service proxy DID, formatted as "did:key:[key]". Required.
3838-## Do not use the default key outside of testing.
3939+## A multibase public key to use for DID service proxying, formatted as "did:key:[key]".
4040+## Do not use the default key outside of development.
3941didSigningKey = "did:key:zDnaeuuRRQuYp4S76LwosLhHbpU1HJcg6S5oJAUHmdZLVdLM5"
+2-5
backend/drizzle.config.ts
···88// @ts-expect-error Read from the TypeScript file instead of assuming that it's JavaScript
99import { Config } from "./src/config.ts";
10101111-const config = Config.getInstance();
1111+const config = Config.getInstance().getConfig();
1212let dbname;
13131414-dbname = config.get("database.name");
1515-if (typeof dbname !== "string") {
1616- dbname = "file:clippr.db"; // Only way to disable linter error
1717-}
1414+dbname = config.database.name;
18151916export default defineConfig({
2017 out: "./drizzle",
+35-14
backend/src/config.ts
···77import { readFileSync } from "fs";
88import * as toml from "toml";
991010+interface ConfigSchema {
1111+ hostname: string | "localhost";
1212+ port: number | 9090;
1313+ baseUrl: string | "http://localhost:9090";
1414+ logLevel: string | "debug";
1515+ database: {
1616+ name: string | "file:clippr.db";
1717+ };
1818+ network: {
1919+ firehose: string | "jetstream1.us-east.bsky.network";
2020+ serviceDid: string | "did:web:localhost%3A9090";
2121+ didSigningKey: string | "did:key:zDnaeuuRRQuYp4S76LwosLhHbpU1HJcg6S5oJAUHmdZLVdLM5";
2222+ };
2323+}
2424+2525+class ConfigError extends Error {
2626+ constructor(message: string) {
2727+ super(message);
2828+ this.name = "ConfigError";
2929+ }
3030+}
3131+1032export class Config {
1133 private static instance: Config;
1212- private readonly configData;
3434+ private readonly configData: ConfigSchema;
13351436 private constructor() {
1537 let tomlString;
1638 try {
1739 tomlString = readFileSync("config.toml", "utf-8");
1840 } catch {
1919- throw new Error("Config file not found");
4141+ throw new ConfigError("Config file not found");
2042 }
2121- this.configData = toml.parse(tomlString);
4343+4444+ try {
4545+ this.configData = toml.parse(tomlString);
4646+ } catch {
4747+ throw new ConfigError(`Config file is not valid TOML`);
4848+ }
2249 }
23505151+ /**
5252+ * Gets a singleton instance of the program configuration
5353+ * @throws {ConfigError} if the config file cannot be read or parsed
5454+ */
2455 static getInstance(): Config {
2556 if (!Config.instance) {
2657 try {
···3364 return Config.instance;
3465 }
35663636- get<T>(path: string): T | undefined {
3737- const keys = path.split(".");
3838- let value = this.configData;
3939- for (const key of keys) {
4040- if (value == null) return undefined;
4141- value = value[key];
4242- }
4343- return value;
4444- }
4545-4646- getAll() {
6767+ getConfig(): ConfigSchema {
4768 return this.configData;
4869 }
4970}