From 872f9934cafe95279976f040b69c8a1983d1efe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrik=20Mint=C4=9Bl?= Date: Thu, 29 Jan 2026 08:33:16 +0000 Subject: [PATCH] chore: Don't require envs in build time, and load them dynamically --- src/lib/server/_routes/ai.ts | 4 ++-- src/lib/server/_routes/article.ts | 4 +++- src/lib/server/_routes/login.ts | 11 ++++++----- src/lib/server/_routes/upload.ts | 12 +++++++----- src/lib/server/env.ts | 18 ++++++++++++++++++ src/lib/server/functions.ts | 4 +++- src/lib/server/nina.ts | 4 ++-- src/lib/server/variables.ts | 22 +++++++--------------- src/routes/image/[name]/+server.ts | 12 +++++++----- 9 files changed, 55 insertions(+), 36 deletions(-) create mode 100644 src/lib/server/env.ts diff --git a/src/lib/server/_routes/ai.ts b/src/lib/server/_routes/ai.ts index 58ae6e3..05419fa 100644 --- a/src/lib/server/_routes/ai.ts +++ b/src/lib/server/_routes/ai.ts @@ -1,10 +1,10 @@ -import { GEMINI_API_KEY } from '$env/static/private'; +import { env } from '$/lib/server/env'; import { GoogleGenerativeAI } from '@google/generative-ai'; import { MiddleWareError } from '@patrick115/sveltekitapi'; import { z } from 'zod'; import { loggedProcedure } from '../api'; -const genAI = new GoogleGenerativeAI(GEMINI_API_KEY); +const genAI = new GoogleGenerativeAI(env.GEMINI_API_KEY); const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash-lite' }); export default { diff --git a/src/lib/server/_routes/article.ts b/src/lib/server/_routes/article.ts index 41bd5ea..8ab38ff 100644 --- a/src/lib/server/_routes/article.ts +++ b/src/lib/server/_routes/article.ts @@ -1,7 +1,7 @@ import { languages, type ErrorPath } from '$/lib/lang'; +import { env } from '$/lib/server/env'; import { articleSchema as _articleSchema } from '$/types/schemes'; import type { ActionsResponse, Response } from '$/types/types'; -import { FILE_FOLDER } from '$env/static/private'; import { AnyFormDataInput, type ErrorApiResponse } from '@patrick115/sveltekitapi'; import { fail } from '@sveltejs/kit'; import fs from 'node:fs/promises'; @@ -12,6 +12,8 @@ import { loggedProcedure } from '../api'; import { insertTranslations, parseFormData, updateTranslations } from '../functions'; import { conn } from '../variables'; +const FILE_FOLDER = env.FILE_FOLDER; + const articleSchema = _articleSchema('cs'); const TRANSLATION_FIELDS = ['title', 'description', 'content_md'] as const; diff --git a/src/lib/server/_routes/login.ts b/src/lib/server/_routes/login.ts index 214ed41..a327792 100644 --- a/src/lib/server/_routes/login.ts +++ b/src/lib/server/_routes/login.ts @@ -1,16 +1,17 @@ -import { FormDataInput } from '@patrick115/sveltekitapi'; -import { procedure } from '../api'; import type { ErrorPath } from '$/lib/lang'; +import { env } from '$/lib/server/env'; import type { ActionsResponse, Response } from '$/types/types'; +import { FormDataInput } from '@patrick115/sveltekitapi'; import { fail } from '@sveltejs/kit'; -import { conn, jwt } from '../variables'; import bcrypt from 'bcrypt'; -import { COOKIE_EXPIRE } from '$env/static/private'; +import { procedure } from '../api'; +import { conn, jwt } from '../variables'; export default procedure.POST.input(FormDataInput).query( async ({ input, ev: { cookies } }) => { const username = input.get('username') as string | null; const password = input.get('password') as string | null; + const COOKIE_EXPIRE = env.COOKIE_EXPIRE; if (!username || !password) { return fail(401, { @@ -48,7 +49,7 @@ export default procedure.POST.input(FormDataInput).query( cookies.set('session', session, { path: '/', - maxAge: parseInt(COOKIE_EXPIRE) + maxAge: COOKIE_EXPIRE }); return { diff --git a/src/lib/server/_routes/upload.ts b/src/lib/server/_routes/upload.ts index aaa8e4a..ad8aa45 100644 --- a/src/lib/server/_routes/upload.ts +++ b/src/lib/server/_routes/upload.ts @@ -1,12 +1,14 @@ -import { FormDataInput, type ErrorApiResponse } from '@patrick115/sveltekitapi'; -import { loggedProcedure } from '../api'; import type { ErrorPath } from '$/lib/lang'; -import { isFile, uploadFile } from '../functions'; +import { env } from '$/lib/server/env'; import type { Response, ResponseWithData } from '$/types/types'; -import { z } from 'zod'; +import { FormDataInput, type ErrorApiResponse } from '@patrick115/sveltekitapi'; import fs from 'node:fs/promises'; import Path from 'node:path'; -import { FILE_FOLDER } from '$env/static/private'; +import { z } from 'zod'; +import { loggedProcedure } from '../api'; +import { isFile, uploadFile } from '../functions'; + +const FILE_FOLDER = env.FILE_FOLDER; export default [ loggedProcedure.POST.input(FormDataInput).query(async ({ input }) => { diff --git a/src/lib/server/env.ts b/src/lib/server/env.ts new file mode 100644 index 0000000..79f8028 --- /dev/null +++ b/src/lib/server/env.ts @@ -0,0 +1,18 @@ +import { env as dynamicEnv } from '$env/dynamic/private'; +import { z } from 'zod'; + +const envSchema = z.object({ + NINA_BASE_URL: z.string().default('http://10.10.10.211:1888/'), + UPDATE_THRESHOLD_COUNT: z.coerce.number().default(30), + JWT_SECRET: z.string().min(1), + DATABASE_IP: z.string().min(1), + DATABASE_PORT: z.coerce.number(), + DATABASE_USER: z.string().min(1), + DATABASE_PASSWORD: z.string().min(1), + DATABASE_NAME: z.string().min(1), + FILE_FOLDER: z.string().min(1), + GEMINI_API_KEY: z.string().min(1), + COOKIE_EXPIRE: z.coerce.number() +}); + +export const env = envSchema.parse(dynamicEnv); diff --git a/src/lib/server/functions.ts b/src/lib/server/functions.ts index 30ce3a9..4c0e5b7 100644 --- a/src/lib/server/functions.ts +++ b/src/lib/server/functions.ts @@ -1,3 +1,4 @@ +import { env } from '$/lib/server/env'; import type { DB, Translations } from '$/types/database'; import { extensions, @@ -6,7 +7,6 @@ import { type UserData, type UserState } from '$/types/types'; -import { FILE_FOLDER } from '$env/static/private'; import type { Cookies } from '@sveltejs/kit'; import { redirect as _redirect } from '@sveltejs/kit'; import type { ControlledTransaction, Insertable } from 'kysely'; @@ -20,6 +20,8 @@ import { languages } from '../lang'; import { getState } from '../state.svelte'; import { conn, jwt } from './variables'; +const FILE_FOLDER = env.FILE_FOLDER; + const randomBytesAsync = promisify(crypto.randomBytes); export const getUserState = (cookies: Cookies): UserState => { diff --git a/src/lib/server/nina.ts b/src/lib/server/nina.ts index 54a0b3a..7730cbb 100644 --- a/src/lib/server/nina.ts +++ b/src/lib/server/nina.ts @@ -61,8 +61,8 @@ export class NinaClient { private cachedLiveImage: Buffer | undefined; constructor() { - this.baseUrl = NINA_BASE_URL ?? 'http://10.10.10.211:1888/'; - this.updateThreshold = parseInt(UPDATE_THRESHOLD_COUNT || '30'); // Default 30 seconds + this.baseUrl = NINA_BASE_URL; + this.updateThreshold = UPDATE_THRESHOLD_COUNT; } private async fetch(endpoint: string): Promise { diff --git a/src/lib/server/variables.ts b/src/lib/server/variables.ts index f124acc..6a78c0c 100644 --- a/src/lib/server/variables.ts +++ b/src/lib/server/variables.ts @@ -1,28 +1,20 @@ import type { DB } from '$/types/database'; -import { env } from '$env/dynamic/private'; -import { - DATABASE_IP, - DATABASE_NAME, - DATABASE_PASSWORD, - DATABASE_PORT, - DATABASE_USER, - JWT_SECRET -} from '$env/static/private'; import { Kysely, MysqlDialect } from 'kysely'; import { createPool } from 'mysql2'; import { JWTCookies } from './cookies/main'; +import { env } from './env'; export const NINA_BASE_URL = env.NINA_BASE_URL; export const UPDATE_THRESHOLD_COUNT = env.UPDATE_THRESHOLD_COUNT; -export const jwt = new JWTCookies(JWT_SECRET); +export const jwt = new JWTCookies(env.JWT_SECRET); const dialect = new MysqlDialect({ pool: createPool({ - host: DATABASE_IP, - port: parseInt(DATABASE_PORT), - user: DATABASE_USER, - password: DATABASE_PASSWORD, - database: DATABASE_NAME + host: env.DATABASE_IP, + port: env.DATABASE_PORT, + user: env.DATABASE_USER, + password: env.DATABASE_PASSWORD, + database: env.DATABASE_NAME }) }); diff --git a/src/routes/image/[name]/+server.ts b/src/routes/image/[name]/+server.ts index cf9237f..51c7d3a 100644 --- a/src/routes/image/[name]/+server.ts +++ b/src/routes/image/[name]/+server.ts @@ -1,12 +1,14 @@ +import { env } from '$/lib/server/env'; +import { isDirectory, isFile } from '$/lib/server/functions'; +import { extensions, type ImageExtension } from '$/types/types'; import { error, type RequestHandler } from '@sveltejs/kit'; -import Path from 'node:path'; -import fs from 'node:fs/promises'; import { createReadStream } from 'node:fs'; +import fs from 'node:fs/promises'; +import Path from 'node:path'; import { Readable } from 'node:stream'; -import { FILE_FOLDER } from '$env/static/private'; import sharp from 'sharp'; -import { isDirectory, isFile } from '$/lib/server/functions'; -import { extensions, type ImageExtension } from '$/types/types'; + +const FILE_FOLDER = env.FILE_FOLDER; const CACHE_FOLDER = '.cache'; const DEFAULT_IMAGE_QUALITY = 75;