diff --git a/.eslintrc.json b/.eslintrc.json index 84d8fc4e..af419ff4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -21,7 +21,9 @@ "import" ], "rules": { - "prettier/prettier": "error", + "prettier/prettier":[ "error", { + "endOfLine": "auto" + }], "arrow-body-style": "off", "prefer-arrow-callback": "off", "consistent-return": "off", diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 937361f8..aebb17e4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,7 @@ jobs: if: ${{ github.ref != 'refs/heads/main' }} with: context: . - push: true + push: ${{ !github.event.pull_request.head.repo.fork }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - name: Build and Push Latest Docker Image diff --git a/.gitignore b/.gitignore index 4405af71..1476e168 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,7 @@ dist # Data data/ -*.env \ No newline at end of file +*.env + +# Jetbrains IDE +.idea/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5b4070a3..d647a196 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,6 @@ "@prisma/client": "4.10.1", "callback-data": "1.0.2", "dotenv": "16.0.3", - "envalid": "7.3.1", "fastify": "4.13.0", "grammy": "1.14.1", "grammy-guard": "0.4.1", @@ -29,7 +28,8 @@ "pino": "8.10.0", "pino-pretty": "9.3.0", "prom-client": "14.1.1", - "tsx": "3.12.3" + "tsx": "3.12.2", + "zod": "^3.20.2" }, "devDependencies": { "@types/debug": "4.1.7", @@ -1562,17 +1562,6 @@ "node": ">=10.13.0" } }, - "node_modules/envalid": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/envalid/-/envalid-7.3.1.tgz", - "integrity": "sha512-KL1YRwn8WcoF/Ty7t+yLLtZol01xr9ZJMTjzoGRM8NaSU+nQQjSWOQKKJhJP2P57bpdakJ9jbxqQX4fGTOicZg==", - "dependencies": { - "tslib": "2.3.1" - }, - "engines": { - "node": ">=8.12" - } - }, "node_modules/es-abstract": { "version": "1.21.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", @@ -4975,7 +4964,8 @@ "node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true }, "node_modules/tsutils": { "version": "3.21.0", @@ -4999,13 +4989,13 @@ "dev": true }, "node_modules/tsx": { - "version": "3.12.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.3.tgz", - "integrity": "sha512-Wc5BFH1xccYTXaQob+lEcimkcb/Pq+0en2s+ruiX0VEIC80nV7/0s7XRahx8NnsoCnpCVUPz8wrqVSPi760LkA==", + "version": "3.12.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-3.12.2.tgz", + "integrity": "sha512-ykAEkoBg30RXxeOMVeZwar+JH632dZn9EUJVyJwhfag62k6UO/dIyJEV58YuLF6e5BTdV/qmbQrpkWqjq9cUnQ==", "dependencies": { - "@esbuild-kit/cjs-loader": "^2.4.2", + "@esbuild-kit/cjs-loader": "^2.4.1", "@esbuild-kit/core-utils": "^3.0.0", - "@esbuild-kit/esm-loader": "^2.5.5" + "@esbuild-kit/esm-loader": "^2.5.4" }, "bin": { "tsx": "dist/cli.js" @@ -5250,6 +5240,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.20.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.20.6.tgz", + "integrity": "sha512-oyu0m54SGCtzh6EClBVqDDlAYRz4jrVtKwQ7ZnsEmMI9HnzuZFj8QFwAY1M5uniIYACdGvv0PBWPF2kO0aNofA==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 1f34cfb4..5609e771 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "@prisma/client": "4.10.1", "callback-data": "1.0.2", "dotenv": "16.0.3", - "envalid": "7.3.1", "fastify": "4.13.0", "grammy": "1.14.1", "grammy-guard": "0.4.1", @@ -36,7 +35,8 @@ "pino": "8.10.0", "pino-pretty": "9.3.0", "prom-client": "14.1.1", - "tsx": "3.12.3" + "tsx": "3.12.2", + "zod": "^3.20.2" }, "devDependencies": { "@types/debug": "4.1.7", diff --git a/src/config.ts b/src/config.ts index 97176f15..b458c97f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,26 +1,60 @@ import "dotenv/config"; -import { cleanEnv, json, num, str } from "envalid"; -import { PollingOptions } from "grammy"; +import z from "zod"; -export const config = cleanEnv(process.env, { - NODE_ENV: str({ choices: ["development", "production"] }), - LOG_LEVEL: str({ - choices: ["trace", "debug", "info", "warn", "error", "fatal", "silent"], - }), - DATABASE_URL: str(), - REDIS_URL: str(), - BOT_SERVER_HOST: str({ - default: "0.0.0.0", - }), - BOT_SERVER_PORT: num({ - default: 80, - }), - BOT_ALLOWED_UPDATES: json({ - default: [], - }), - BOT_TOKEN: str(), - BOT_WEBHOOK: str(), - BOT_ADMIN_USER_ID: num(), +const updates = [ + "message", + "poll", + "poll_answer", + "my_chat_member", + "chat_member", + "chat_join_request", + "edited_message", + "channel_post", + "edited_channel_post", + "inline_query", + "chosen_inline_result", + "callback_query", + "shipping_query", + "pre_checkout_query", +] as const; + +const configSchema = z.object({ + NODE_ENV: z.enum(["development", "production"]), + LOG_LEVEL: z.enum([ + "trace", + "debug", + "info", + "warn", + "error", + "fatal", + "silent", + ]), + DATABASE_URL: z.string(), + REDIS_URL: z.string(), + BOT_SERVER_HOST: z.string().default("0.0.0.0"), + BOT_SERVER_PORT: z.coerce.number().positive().default(80), + BOT_ALLOWED_UPDATES: z.preprocess((v: unknown) => { + try { + return JSON.parse(String(v)); + } catch (e) { + return null; + } + }, z.array(z.enum(updates))), + BOT_TOKEN: z.string(), + BOT_WEBHOOK: z.string().url(), + BOT_ADMIN_USER_ID: z.coerce.number().finite(), }); -export type Config = typeof config; +const parseConfig = (env: NodeJS.ProcessEnv) => { + const config = configSchema.parse(env); + + return { + ...config, + isDev: process.env.NODE_ENV === "development", + isProd: process.env.NODE_ENV === "production", + }; +}; + +export type Config = ReturnType; + +export const config = parseConfig(process.env);