aboutsummaryrefslogtreecommitdiff
path: root/src/index.ts
blob: 2985d36fa11f97d1924ba7eaf3df462ef3725bfc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env node

import { argv, Either, getEnv, type IEither, HonoProxy } from '@emprespresso/pengueno';
import { PosthookServer } from './server/index.js';
import { Storage } from './storage/index.js';
import { TokenSigner } from './token/index.js';

const main = async (_argv = process.argv.slice(2)): Promise<IEither<Error, void>> => {
    const argsResult = argv(
        ['--port', '--host', '--data-dir', '--config', '--token-secret', '--cors-origins'],
        {
            '--port': { absent: 9000, present: (port) => parseInt(port) },
            '--host': { absent: '0.0.0.0', present: (host) => host },
            '--data-dir': { absent: './data', present: (dir) => dir },
            '--config': { absent: './routes.toml', present: (path) => path },
            '--token-secret': { absent: undefined, present: (secret) => secret },
            '--cors-origins': { absent: '*', present: (origins) => origins },
        },
        _argv,
    );

    return argsResult
        .mapRight((args) => ({
            port: args['--port'],
            host: args['--host'],
            dataDir: args['--data-dir'],
            configPath: args['--config'],
            tokenSecret: args['--token-secret'],
            corsOrigins: args['--cors-origins'],
        }))
        .flatMapAsync(async (config) => {
            // Initialize storage
            const storage = new Storage(config.dataDir, config.configPath);
            const initResult = await storage.init();

            if (initResult.left().present()) {
                return Either.left(initResult.left().get());
            }

            // Initialize token signer (use env var or command line arg or generate random)
            const envSecret = getEnv('POSTHOOK_TOKEN_SECRET');
            const secret = config.tokenSecret ?? (envSecret.present() ? envSecret.get() : undefined);
            const signer = new TokenSigner(secret);

            if (config.tokenSecret === undefined && !envSecret.present()) {
                console.log('No token secret provided; generated a random one (will not persist across restarts).');
                console.log('Set POSTHOOK_TOKEN_SECRET or pass --token-secret to use a persistent secret.');
            }

            console.log(`Storage initialized at: ${config.dataDir}`);
            console.log(`Starting server on ${config.host}:${config.port}`);

            // Create and start server
            const server = new PosthookServer(storage, signer, config.corsOrigins);
            const hono = new HonoProxy(server);

            return hono.serve(config.port, config.host);
        });
};

if (process.argv[1] === import.meta.filename) {
    await main().then((eitherDone) =>
        eitherDone.mapLeft((err) => {
            console.error('error:', err);
            process.exit(1);
        }),
    );
}