mirror of
https://github.com/ajnart/homarr.git
synced 2026-02-27 00:40:58 +01:00
fix: always require db-user and password for mysql (#1730)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// Importing env files here to validate on build
|
||||
import "@homarr/auth/env.mjs";
|
||||
import "@homarr/db/env.mjs";
|
||||
|
||||
import MillionLint from "@million/lint";
|
||||
import createNextIntlPlugin from "next-intl/plugin";
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { createEnv } from "@t3-oss/env-nextjs";
|
||||
import { z } from "zod";
|
||||
|
||||
const isUsingDbUrl = Boolean(process.env.DB_URL);
|
||||
const isUsingDbHost = Boolean(process.env.DB_HOST);
|
||||
const isUsingDbCredentials = process.env.DB_DRIVER === "mysql2";
|
||||
|
||||
export const env = createEnv({
|
||||
shared: {
|
||||
VERCEL_URL: z
|
||||
@@ -19,21 +15,6 @@ export const env = createEnv({
|
||||
* built with invalid env vars.
|
||||
*/
|
||||
server: {
|
||||
DB_DRIVER: z.enum(["better-sqlite3", "mysql2"]).default("better-sqlite3"),
|
||||
// If the DB_HOST is set, the DB_URL is optional
|
||||
DB_URL: isUsingDbHost ? z.string().optional() : z.string(),
|
||||
DB_HOST: isUsingDbUrl ? z.string().optional() : z.string(),
|
||||
DB_PORT: isUsingDbUrl
|
||||
? z.string().regex(/\d+/).transform(Number).optional()
|
||||
: z
|
||||
.string()
|
||||
.regex(/\d+/)
|
||||
.transform(Number)
|
||||
.refine((number) => number >= 1)
|
||||
.default("3306"),
|
||||
DB_USER: isUsingDbCredentials ? z.string() : z.string().optional(),
|
||||
DB_PASSWORD: isUsingDbCredentials ? z.string() : z.string().optional(),
|
||||
DB_NAME: isUsingDbUrl ? z.string().optional() : z.string(),
|
||||
// Comma separated list of docker hostnames that can be used to connect to query the docker endpoints (localhost:2375,host.docker.internal:2375, ...)
|
||||
DOCKER_HOSTNAMES: z.string().optional(),
|
||||
DOCKER_PORTS: z.number().optional(),
|
||||
@@ -51,13 +32,6 @@ export const env = createEnv({
|
||||
runtimeEnv: {
|
||||
VERCEL_URL: process.env.VERCEL_URL,
|
||||
PORT: process.env.PORT,
|
||||
DB_URL: process.env.DB_URL,
|
||||
DB_HOST: process.env.DB_HOST,
|
||||
DB_USER: process.env.DB_USER,
|
||||
DB_PASSWORD: process.env.DB_PASSWORD,
|
||||
DB_NAME: process.env.DB_NAME,
|
||||
DB_PORT: process.env.DB_PORT,
|
||||
DB_DRIVER: process.env.DB_DRIVER,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
DOCKER_HOSTNAMES: process.env.DOCKER_HOSTNAMES,
|
||||
DOCKER_PORTS: process.env.DOCKER_PORTS,
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import * as dotenv from "dotenv";
|
||||
import type { Config } from "drizzle-kit";
|
||||
|
||||
dotenv.config({ path: "../../.env" });
|
||||
import { env } from "../env.mjs";
|
||||
|
||||
export default {
|
||||
dialect: "mysql",
|
||||
schema: "./schema",
|
||||
casing: "snake_case",
|
||||
dbCredentials: {
|
||||
host: process.env.DB_HOST!,
|
||||
user: process.env.DB_USER!,
|
||||
password: process.env.DB_PASSWORD!,
|
||||
database: process.env.DB_NAME!,
|
||||
port: parseInt(process.env.DB_PORT!),
|
||||
},
|
||||
dbCredentials: env.DB_URL
|
||||
? { url: env.DB_URL }
|
||||
: {
|
||||
host: env.DB_HOST,
|
||||
user: env.DB_USER,
|
||||
password: env.DB_PASSWORD,
|
||||
database: env.DB_NAME,
|
||||
port: env.DB_PORT,
|
||||
},
|
||||
out: "./migrations/mysql",
|
||||
} satisfies Config;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import * as dotenv from "dotenv";
|
||||
import type { Config } from "drizzle-kit";
|
||||
|
||||
dotenv.config({ path: "../../.env" });
|
||||
import { env } from "../env.mjs";
|
||||
|
||||
export default {
|
||||
dialect: "sqlite",
|
||||
schema: "./schema",
|
||||
casing: "snake_case",
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
dbCredentials: { url: process.env.DB_URL! },
|
||||
dbCredentials: { url: env.DB_URL },
|
||||
out: "./migrations/sqlite",
|
||||
} satisfies Config;
|
||||
|
||||
@@ -7,6 +7,7 @@ import mysql from "mysql2";
|
||||
|
||||
import { logger } from "@homarr/log";
|
||||
|
||||
import { env } from "./env.mjs";
|
||||
import * as mysqlSchema from "./schema/mysql";
|
||||
import * as sqliteSchema from "./schema/sqlite";
|
||||
|
||||
@@ -15,7 +16,7 @@ type HomarrDatabase = BetterSQLite3Database<typeof sqliteSchema>;
|
||||
const init = () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!connection) {
|
||||
switch (process.env.DB_DRIVER) {
|
||||
switch (env.DB_DRIVER) {
|
||||
case "mysql2":
|
||||
initMySQL2();
|
||||
break;
|
||||
@@ -36,7 +37,7 @@ class WinstonDrizzleLogger implements Logger {
|
||||
}
|
||||
|
||||
const initBetterSqlite = () => {
|
||||
connection = new Database(process.env.DB_URL);
|
||||
connection = new Database(env.DB_URL);
|
||||
database = drizzleSqlite(connection, {
|
||||
schema: sqliteSchema,
|
||||
logger: new WinstonDrizzleLogger(),
|
||||
@@ -45,16 +46,15 @@ const initBetterSqlite = () => {
|
||||
};
|
||||
|
||||
const initMySQL2 = () => {
|
||||
if (!process.env.DB_HOST) {
|
||||
connection = mysql.createConnection({ uri: process.env.DB_URL });
|
||||
if (!env.DB_HOST) {
|
||||
connection = mysql.createConnection({ uri: env.DB_URL });
|
||||
} else {
|
||||
connection = mysql.createConnection({
|
||||
host: process.env.DB_HOST,
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
database: process.env.DB_NAME!,
|
||||
port: Number(process.env.DB_PORT),
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
host: env.DB_HOST,
|
||||
database: env.DB_NAME,
|
||||
port: env.DB_PORT,
|
||||
user: env.DB_USER,
|
||||
password: env.DB_PASSWORD,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
60
packages/db/env.mjs
Normal file
60
packages/db/env.mjs
Normal file
@@ -0,0 +1,60 @@
|
||||
import { createEnv } from "@t3-oss/env-nextjs";
|
||||
import { z } from "zod";
|
||||
|
||||
const drivers = {
|
||||
betterSqlite3: "better-sqlite3",
|
||||
mysql2: "mysql2",
|
||||
};
|
||||
|
||||
const isDriver = (driver) => process.env.DB_DRIVER === driver;
|
||||
const isUsingDbHost = Boolean(process.env.DB_HOST);
|
||||
const onlyAllowUrl = isDriver(drivers.betterSqlite3);
|
||||
const urlRequired = onlyAllowUrl || !isUsingDbHost;
|
||||
const hostRequired = isUsingDbHost && !onlyAllowUrl;
|
||||
|
||||
export const env = createEnv({
|
||||
/**
|
||||
* Specify your server-side environment variables schema here. This way you can ensure the app isn't
|
||||
* built with invalid env vars.
|
||||
*/
|
||||
server: {
|
||||
DB_DRIVER: z
|
||||
.union([z.literal(drivers.betterSqlite3), z.literal(drivers.mysql2)], {
|
||||
message: `Invalid database driver, supported are ${Object.keys(drivers).join(", ")}`,
|
||||
})
|
||||
.default(drivers.betterSqlite3),
|
||||
...(urlRequired
|
||||
? {
|
||||
DB_URL: z.string(),
|
||||
}
|
||||
: {}),
|
||||
...(hostRequired
|
||||
? {
|
||||
DB_HOST: z.string(),
|
||||
DB_PORT: z
|
||||
.string()
|
||||
.regex(/\d+/)
|
||||
.transform(Number)
|
||||
.refine((number) => number >= 1)
|
||||
.default("3306"),
|
||||
DB_USER: z.string(),
|
||||
DB_PASSWORD: z.string(),
|
||||
DB_NAME: z.string(),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
/**
|
||||
* Destructure all variables from `process.env` to make sure they aren't tree-shaken away.
|
||||
*/
|
||||
runtimeEnv: {
|
||||
DB_DRIVER: process.env.DB_DRIVER,
|
||||
DB_URL: process.env.DB_URL,
|
||||
DB_HOST: process.env.DB_HOST,
|
||||
DB_USER: process.env.DB_USER,
|
||||
DB_PASSWORD: process.env.DB_PASSWORD,
|
||||
DB_NAME: process.env.DB_NAME,
|
||||
DB_PORT: process.env.DB_PORT,
|
||||
},
|
||||
skipValidation:
|
||||
Boolean(process.env.CI) || Boolean(process.env.SKIP_ENV_VALIDATION) || process.env.npm_lifecycle_event === "lint",
|
||||
});
|
||||
@@ -1,9 +1,9 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import { drizzle } from "drizzle-orm/mysql2";
|
||||
import { migrate } from "drizzle-orm/mysql2/migrator";
|
||||
import mysql from "mysql2";
|
||||
|
||||
import type { Database } from "../..";
|
||||
import { env } from "../../env.mjs";
|
||||
import * as mysqlSchema from "../../schema/mysql";
|
||||
import { seedDataAsync } from "../seed";
|
||||
|
||||
@@ -11,15 +11,15 @@ const migrationsFolder = process.argv[2] ?? ".";
|
||||
|
||||
const migrateAsync = async () => {
|
||||
const mysql2 = mysql.createConnection(
|
||||
process.env.DB_HOST
|
||||
? {
|
||||
host: process.env.DB_HOST,
|
||||
database: process.env.DB_NAME!,
|
||||
port: Number(process.env.DB_PORT),
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
}
|
||||
: { uri: process.env.DB_URL },
|
||||
env.DB_URL
|
||||
? { uri: env.DB_URL }
|
||||
: {
|
||||
host: env.DB_HOST,
|
||||
database: env.DB_NAME,
|
||||
port: env.DB_PORT,
|
||||
user: env.DB_USER,
|
||||
password: env.DB_PASSWORD,
|
||||
},
|
||||
);
|
||||
|
||||
const db = drizzle(mysql2, {
|
||||
|
||||
@@ -2,13 +2,14 @@ import Database from "better-sqlite3";
|
||||
import { drizzle } from "drizzle-orm/better-sqlite3";
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
|
||||
import { env } from "../../env.mjs";
|
||||
import * as sqliteSchema from "../../schema/sqlite";
|
||||
import { seedDataAsync } from "../seed";
|
||||
|
||||
const migrationsFolder = process.argv[2] ?? ".";
|
||||
|
||||
const migrateAsync = async () => {
|
||||
const sqlite = new Database(process.env.DB_URL?.replace("file:", ""));
|
||||
const sqlite = new Database(env.DB_URL.replace("file:", ""));
|
||||
|
||||
const db = drizzle(sqlite, { schema: sqliteSchema, casing: "snake_case" });
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
"./schema": "./schema/index.ts",
|
||||
"./test": "./test/index.ts",
|
||||
"./queries": "./queries/index.ts",
|
||||
"./validationSchemas": "./validationSchemas.ts"
|
||||
"./validationSchemas": "./validationSchemas.ts",
|
||||
"./env.mjs": "./env.mjs"
|
||||
},
|
||||
"main": "./index.ts",
|
||||
"types": "./index.ts",
|
||||
@@ -21,16 +22,16 @@
|
||||
"clean": "rm -rf .turbo node_modules",
|
||||
"format": "prettier --check . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint",
|
||||
"migration:mysql:drop": "drizzle-kit drop --config ./configs/mysql.config.ts",
|
||||
"migration:mysql:generate": "drizzle-kit generate --config ./configs/mysql.config.ts",
|
||||
"migration:mysql:run": "drizzle-kit migrate --config ./configs/mysql.config.ts && pnpm run seed",
|
||||
"migration:sqlite:drop": "drizzle-kit drop --config ./configs/sqlite.config.ts",
|
||||
"migration:sqlite:generate": "drizzle-kit generate --config ./configs/sqlite.config.ts",
|
||||
"migration:sqlite:run": "drizzle-kit migrate --config ./configs/sqlite.config.ts && pnpm run seed",
|
||||
"push:mysql": "drizzle-kit push --config ./configs/mysql.config.ts",
|
||||
"push:sqlite": "drizzle-kit push --config ./configs/sqlite.config.ts",
|
||||
"migration:mysql:drop": "pnpm with-env drizzle-kit drop --config ./configs/mysql.config.ts",
|
||||
"migration:mysql:generate": "pnpm with-env drizzle-kit generate --config ./configs/mysql.config.ts",
|
||||
"migration:mysql:run": "pnpm with-env drizzle-kit migrate --config ./configs/mysql.config.ts && pnpm run seed",
|
||||
"migration:sqlite:drop": "pnpm with-env drizzle-kit drop --config ./configs/sqlite.config.ts",
|
||||
"migration:sqlite:generate": "pnpm with-env drizzle-kit generate --config ./configs/sqlite.config.ts",
|
||||
"migration:sqlite:run": "pnpm with-env drizzle-kit migrate --config ./configs/sqlite.config.ts && pnpm run seed",
|
||||
"push:mysql": "pnpm with-env drizzle-kit push --config ./configs/mysql.config.ts",
|
||||
"push:sqlite": "pnpm with-env drizzle-kit push --config ./configs/sqlite.config.ts",
|
||||
"seed": "pnpm with-env tsx ./migrations/run-seed.ts",
|
||||
"studio": "drizzle-kit studio --config ./configs/sqlite.config.ts",
|
||||
"studio": "pnpm with-env drizzle-kit studio --config ./configs/sqlite.config.ts",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"with-env": "dotenv -e ../../.env --"
|
||||
},
|
||||
@@ -42,6 +43,7 @@
|
||||
"@homarr/log": "workspace:^0.1.0",
|
||||
"@homarr/server-settings": "workspace:^0.1.0",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@t3-oss/env-nextjs": "^0.11.1",
|
||||
"@testcontainers/mysql": "^10.16.0",
|
||||
"better-sqlite3": "^11.7.0",
|
||||
"dotenv": "^16.4.7",
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -895,6 +895,9 @@ importers:
|
||||
'@paralleldrive/cuid2':
|
||||
specifier: ^2.2.2
|
||||
version: 2.2.2
|
||||
'@t3-oss/env-nextjs':
|
||||
specifier: ^0.11.1
|
||||
version: 0.11.1(typescript@5.7.2)(zod@3.24.1)
|
||||
'@testcontainers/mysql':
|
||||
specifier: ^10.16.0
|
||||
version: 10.16.0
|
||||
|
||||
Reference in New Issue
Block a user