From 1083a1d260ba956ed0dfd11e1e8f864092bee3d1 Mon Sep 17 00:00:00 2001 From: Jennie Robinson Faber Date: Sun, 26 Apr 2026 14:46:55 +0100 Subject: [PATCH 1/2] =?UTF-8?q?chore(docker):=20bump=20node=2020=20?= =?UTF-8?q?=E2=86=92=2022?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Silences oidc-provider's "Unsupported runtime" warning on every boot. --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5102ee0..0375bac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build stage -FROM node:20-alpine AS builder +FROM node:22-alpine AS builder WORKDIR /app COPY package*.json ./ @@ -10,7 +10,7 @@ RUN npm run build # Production stage — only the self-contained .output is needed. # bash + curl are added so Dokploy scheduled tasks (which wrap commands in # `bash -c "..."`) can run; alpine ships only ash and has no curl by default. -FROM node:20-alpine +FROM node:22-alpine RUN apk add --no-cache bash curl WORKDIR /app COPY --from=builder /app/.output .output From 04eb33df6e70efff83aee30cabf85afa9c8c1064 Mon Sep 17 00:00:00 2001 From: Jennie Robinson Faber Date: Sun, 26 Apr 2026 14:47:02 +0100 Subject: [PATCH 2/2] refactor(env): unify required-env validation through useRuntimeConfig validate-env.js now reads all four required vars (MONGODB_URI, JWT_SECRET, RESEND_API_KEY, HELCIM_API_TOKEN) from useRuntimeConfig() instead of mixing direct process.env reads with a JWT-only special case. Mongoose and the six Resend instantiations follow suit. Either bare or NUXT_-prefixed env names are accepted, so Dokploy no longer needs duplicate entries. --- nuxt.config.ts | 3 +-- server/api/admin/members/invite.post.js | 2 +- .../api/admin/pre-registrants/invite.post.js | 2 +- server/plugins/validate-env.js | 24 +++++++------------ server/routes/oidc/interaction/login.post.ts | 2 +- server/utils/magicLink.js | 2 +- server/utils/mongoose.js | 2 +- server/utils/payments.js | 2 +- server/utils/resend.js | 2 +- 9 files changed, 17 insertions(+), 24 deletions(-) diff --git a/nuxt.config.ts b/nuxt.config.ts index 7757b4c..2043abb 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -91,8 +91,7 @@ export default defineNuxtConfig({ }, runtimeConfig: { // Private keys (server-side only) - mongodbUri: - process.env.MONGODB_URI || "mongodb://localhost:27017/ghostguild", + mongodbUri: process.env.MONGODB_URI || "", jwtSecret: process.env.JWT_SECRET || "", resendApiKey: process.env.RESEND_API_KEY || "", helcimApiToken: process.env.HELCIM_API_TOKEN || "", diff --git a/server/api/admin/members/invite.post.js b/server/api/admin/members/invite.post.js index ebd866c..710f4e1 100644 --- a/server/api/admin/members/invite.post.js +++ b/server/api/admin/members/invite.post.js @@ -4,7 +4,7 @@ import { Resend } from 'resend' import Member from '../../../models/member.js' import { connectDB } from '../../../utils/mongoose.js' -const resend = new Resend(process.env.RESEND_API_KEY) +const resend = new Resend(useRuntimeConfig().resendApiKey) export default defineEventHandler(async (event) => { await requireAdmin(event) diff --git a/server/api/admin/pre-registrants/invite.post.js b/server/api/admin/pre-registrants/invite.post.js index 3d16b88..f3d46b3 100644 --- a/server/api/admin/pre-registrants/invite.post.js +++ b/server/api/admin/pre-registrants/invite.post.js @@ -4,7 +4,7 @@ import { Resend } from 'resend' import PreRegistration from '../../../models/preRegistration.js' import { connectDB } from '../../../utils/mongoose.js' -const resend = new Resend(process.env.RESEND_API_KEY) +const resend = new Resend(useRuntimeConfig().resendApiKey) export default defineEventHandler(async (event) => { await requireAdmin(event) diff --git a/server/plugins/validate-env.js b/server/plugins/validate-env.js index c190c4b..cb1c6ff 100644 --- a/server/plugins/validate-env.js +++ b/server/plugins/validate-env.js @@ -1,23 +1,17 @@ export default defineNitroPlugin(() => { - const required = [ - 'MONGODB_URI', - 'JWT_SECRET', - 'RESEND_API_KEY', - 'HELCIM_API_TOKEN', - ] + const config = useRuntimeConfig() + const checks = { + MONGODB_URI: config.mongodbUri, + JWT_SECRET: config.jwtSecret, + RESEND_API_KEY: config.resendApiKey, + HELCIM_API_TOKEN: config.helcimApiToken, + } - const missing = required.filter((key) => { - // Check both process.env and runtime config where applicable - if (key === 'JWT_SECRET') { - const config = useRuntimeConfig() - return !config.jwtSecret - } - return !process.env[key] - }) + const missing = Object.entries(checks).filter(([, value]) => !value).map(([key]) => key) if (missing.length > 0) { console.error(`FATAL: Missing required environment variables: ${missing.join(', ')}`) - console.error('Set these in your .env file or environment variables.') + console.error('Set these (or their NUXT_-prefixed equivalents) in your .env file or environment variables.') process.exit(1) } }) diff --git a/server/routes/oidc/interaction/login.post.ts b/server/routes/oidc/interaction/login.post.ts index 0799a27..a19af7b 100644 --- a/server/routes/oidc/interaction/login.post.ts +++ b/server/routes/oidc/interaction/login.post.ts @@ -12,7 +12,7 @@ import { Resend } from "resend"; import Member from "../../../models/member.js"; import { connectDB } from "../../../utils/mongoose.js"; -const resend = new Resend(process.env.RESEND_API_KEY); +const resend = new Resend(useRuntimeConfig().resendApiKey); export default defineEventHandler(async (event) => { await connectDB(); diff --git a/server/utils/magicLink.js b/server/utils/magicLink.js index 9503539..928c7f0 100644 --- a/server/utils/magicLink.js +++ b/server/utils/magicLink.js @@ -6,7 +6,7 @@ import { randomUUID } from 'crypto' import { Resend } from 'resend' import Member from '../models/member.js' -const resend = new Resend(process.env.RESEND_API_KEY) +const resend = new Resend(useRuntimeConfig().resendApiKey) /** * Issue a 15-minute magic-link JWT for `email` and email it. diff --git a/server/utils/mongoose.js b/server/utils/mongoose.js index 6456191..e75a5b4 100644 --- a/server/utils/mongoose.js +++ b/server/utils/mongoose.js @@ -7,7 +7,7 @@ export const connectDB = async () => { return; } - const MONGODB_URI = process.env.NUXT_MONGODB_URI || process.env.MONGODB_URI || 'mongodb://localhost:27017/ghostguild'; + const MONGODB_URI = useRuntimeConfig().mongodbUri; try { await mongoose.connect(MONGODB_URI, { diff --git a/server/utils/payments.js b/server/utils/payments.js index bd0e984..9e529f2 100644 --- a/server/utils/payments.js +++ b/server/utils/payments.js @@ -2,7 +2,7 @@ import { Resend } from 'resend' import Payment from '../models/payment.js' import { paymentConfirmationEmail } from '../emails/paymentConfirmation.js' -const resend = new Resend(process.env.RESEND_API_KEY) +const resend = new Resend(useRuntimeConfig().resendApiKey) function mapStatus(helcimStatus) { if (helcimStatus === 'paid') return 'success' diff --git a/server/utils/resend.js b/server/utils/resend.js index 24b2356..e3cada2 100644 --- a/server/utils/resend.js +++ b/server/utils/resend.js @@ -1,6 +1,6 @@ import { Resend } from "resend"; -const resend = new Resend(process.env.RESEND_API_KEY); +const resend = new Resend(useRuntimeConfig().resendApiKey); /** * Send event registration confirmation email