From c579f58c9e6e671771edbf3ea13d271cb7bf6ab6 Mon Sep 17 00:00:00 2001 From: Simon Planinschek Date: Thu, 23 Jul 2026 18:40:08 +0200 Subject: [PATCH 1/3] add env validation utility --- src/slack/app.ts | 5 +++-- src/utils/env.ts | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/utils/env.ts diff --git a/src/slack/app.ts b/src/slack/app.ts index d331338..9f711de 100644 --- a/src/slack/app.ts +++ b/src/slack/app.ts @@ -1,7 +1,8 @@ import { App } from '@slack/bolt' +import { requiredString } from '@utils/env.ts' export const app = new App({ - token: process.env.SLACK_BOT_TOKEN, - appToken: process.env.SLACK_APP_TOKEN, + token: requiredString('SLACK_BOT_TOKEN'), + appToken: requiredString('SLACK_APP_TOKEN'), socketMode: true, }) diff --git a/src/utils/env.ts b/src/utils/env.ts new file mode 100644 index 0000000..0285014 --- /dev/null +++ b/src/utils/env.ts @@ -0,0 +1,24 @@ +type EnvVarName = keyof typeof process.env + +export function requiredString(name: EnvVarName): string { + const value = process.env[name] + if (!value) { + throw new Error(`${name} is required`) + } + + return value +} + +export function positiveInt(name: EnvVarName, defaultValue: number): number { + const raw = process.env[name] + if (!raw) { + return defaultValue + } + + const value = Number(raw) + if (!Number.isInteger(value) || value < 1) { + throw new Error(`${name} must be a positive integer`) + } + + return value +} From 522e2f08597b103c672f2aa3c00f64a2920039a1 Mon Sep 17 00:00:00 2001 From: Simon Planinschek Date: Thu, 23 Jul 2026 18:40:27 +0200 Subject: [PATCH 2/3] make database pool size configurable --- .env.example | 1 + installation.md | 1 + src/db/client.ts | 12 +++++++----- src/env.d.ts | 1 + tsconfig.json | 11 ++++++----- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.env.example b/.env.example index 924c45a..bd38b6f 100644 --- a/.env.example +++ b/.env.example @@ -2,3 +2,4 @@ SLACK_BOT_TOKEN=xoxb- SLACK_APP_TOKEN=xapp- GITHUB_TOKEN=github_pat_ DATABASE_URL=postgres://root:password@localhost:5432/app +# DB_POOL_MAX=10 diff --git a/installation.md b/installation.md index 2eb15cc..2e17e20 100644 --- a/installation.md +++ b/installation.md @@ -46,6 +46,7 @@ DATABASE_URL=postgres://user:password@localhost/releases_db # Optional # POLL_CRON=0 * * * * # How often to check releases (default: every hour) # DIGEST_CRON=30 7 * * * # When to send the periodic digest in UTC (default: 07:30 UTC) +# DB_POOL_MAX=10 # Max connections in the DB connection pool (default: 10) ``` All tables are created in the `main` PostgreSQL schema. To use a different schema, change the hardcoded value in `src/db/schema.ts` and `drizzle.config.ts`, then regenerate and re-apply migrations. diff --git a/src/db/client.ts b/src/db/client.ts index 0c40efc..86091fa 100644 --- a/src/db/client.ts +++ b/src/db/client.ts @@ -1,7 +1,9 @@ import { drizzle } from 'drizzle-orm/bun-sql' +import { positiveInt, requiredString } from '@utils/env' -if (!process.env.DATABASE_URL) { - throw new Error('DATABASE_URL is required') -} - -export const db = drizzle(process.env.DATABASE_URL) +export const db = drizzle({ + connection: { + url: requiredString('DATABASE_URL'), + max: positiveInt('DB_POOL_MAX', 10), + }, +}) diff --git a/src/env.d.ts b/src/env.d.ts index a779b2a..6b0d704 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -9,6 +9,7 @@ declare module 'bun' { // Database DATABASE_URL: string + DB_POOL_MAX?: string // Jobs POLL_CRON?: string DIGEST_CRON?: string diff --git a/tsconfig.json b/tsconfig.json index 4d253b5..1246e71 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,11 +13,12 @@ "noEmit": true, "skipLibCheck": true, "paths": { - "@db/*": ["./src/db/*"], - "@forges/*": ["./src/forges/*"], - "@bot/*": ["./src/slack/*"], - "@jobs/*": ["./src/jobs/*"], - "@classify/*": ["./src/classify/*"] + "@db/*": ["./src/db/*"], + "@forges/*": ["./src/forges/*"], + "@bot/*": ["./src/slack/*"], + "@jobs/*": ["./src/jobs/*"], + "@classify/*": ["./src/classify/*"], + "@utils/*": ["./src/utils/*"] } } } From 1ce2a959f20908848cba75c530563dfcecad0503 Mon Sep 17 00:00:00 2001 From: Simon Planinschek Date: Mon, 27 Jul 2026 08:24:00 +0200 Subject: [PATCH 3/3] rename DB_POOL_MAX to DATABASE_POOL_MAX --- .env.example | 2 +- installation.md | 2 +- src/db/client.ts | 2 +- src/env.d.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index bd38b6f..0b8fcc9 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,4 @@ SLACK_BOT_TOKEN=xoxb- SLACK_APP_TOKEN=xapp- GITHUB_TOKEN=github_pat_ DATABASE_URL=postgres://root:password@localhost:5432/app -# DB_POOL_MAX=10 +# DATABASE_POOL_MAX=10 diff --git a/installation.md b/installation.md index 2e17e20..9c4fc9a 100644 --- a/installation.md +++ b/installation.md @@ -46,7 +46,7 @@ DATABASE_URL=postgres://user:password@localhost/releases_db # Optional # POLL_CRON=0 * * * * # How often to check releases (default: every hour) # DIGEST_CRON=30 7 * * * # When to send the periodic digest in UTC (default: 07:30 UTC) -# DB_POOL_MAX=10 # Max connections in the DB connection pool (default: 10) +# DATABASE_POOL_MAX=10 # Max connections in the DB connection pool (default: 10) ``` All tables are created in the `main` PostgreSQL schema. To use a different schema, change the hardcoded value in `src/db/schema.ts` and `drizzle.config.ts`, then regenerate and re-apply migrations. diff --git a/src/db/client.ts b/src/db/client.ts index 86091fa..bcee9a1 100644 --- a/src/db/client.ts +++ b/src/db/client.ts @@ -4,6 +4,6 @@ import { positiveInt, requiredString } from '@utils/env' export const db = drizzle({ connection: { url: requiredString('DATABASE_URL'), - max: positiveInt('DB_POOL_MAX', 10), + max: positiveInt('DATABASE_POOL_MAX', 10), }, }) diff --git a/src/env.d.ts b/src/env.d.ts index 6b0d704..f0639e0 100644 --- a/src/env.d.ts +++ b/src/env.d.ts @@ -9,7 +9,7 @@ declare module 'bun' { // Database DATABASE_URL: string - DB_POOL_MAX?: string + DATABASE_POOL_MAX?: string // Jobs POLL_CRON?: string DIGEST_CRON?: string