feat: parameterize PORT and MIGRATIONS_PATH environment variables
Allow configuring the server port (default: 4096) and migrations folder path via environment variables for flexible deployment.
This commit is contained in:
parent
90f2c0ac06
commit
a6818762af
4 changed files with 86 additions and 4 deletions
74
app/server/core/__tests__/config.test.ts
Normal file
74
app/server/core/__tests__/config.test.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import { test, describe, expect } from "bun:test";
|
||||
import { type } from "arktype";
|
||||
|
||||
// Re-create the schema to test in isolation (avoids side effects from importing config)
|
||||
const createEnvSchema = () =>
|
||||
type({
|
||||
NODE_ENV: type.enumerated("development", "production", "test").default("production"),
|
||||
SERVER_IP: 'string = "localhost"',
|
||||
SERVER_IDLE_TIMEOUT: 'string.integer.parse = "60"',
|
||||
RESTIC_HOSTNAME: "string = 'zerobyte'",
|
||||
PORT: 'string.integer.parse = "4096"',
|
||||
"MIGRATIONS_PATH?": "string",
|
||||
}).pipe((s) => ({
|
||||
__prod__: s.NODE_ENV === "production",
|
||||
environment: s.NODE_ENV,
|
||||
serverIp: s.SERVER_IP,
|
||||
serverIdleTimeout: s.SERVER_IDLE_TIMEOUT,
|
||||
resticHostname: s.RESTIC_HOSTNAME,
|
||||
port: s.PORT,
|
||||
migrationsPath: s.MIGRATIONS_PATH,
|
||||
}));
|
||||
|
||||
describe("config", () => {
|
||||
describe("PORT", () => {
|
||||
test("should default to 4096 when not set", () => {
|
||||
const schema = createEnvSchema();
|
||||
const result = schema({});
|
||||
|
||||
expect(result).not.toBeInstanceOf(type.errors);
|
||||
if (!(result instanceof type.errors)) {
|
||||
expect(result.port).toBe(4096);
|
||||
}
|
||||
});
|
||||
|
||||
test("should parse PORT as integer", () => {
|
||||
const schema = createEnvSchema();
|
||||
const result = schema({ PORT: "8080" });
|
||||
|
||||
expect(result).not.toBeInstanceOf(type.errors);
|
||||
if (!(result instanceof type.errors)) {
|
||||
expect(result.port).toBe(8080);
|
||||
}
|
||||
});
|
||||
|
||||
test("should reject non-integer PORT", () => {
|
||||
const schema = createEnvSchema();
|
||||
const result = schema({ PORT: "not-a-number" });
|
||||
|
||||
expect(result).toBeInstanceOf(type.errors);
|
||||
});
|
||||
});
|
||||
|
||||
describe("MIGRATIONS_PATH", () => {
|
||||
test("should be undefined when not set", () => {
|
||||
const schema = createEnvSchema();
|
||||
const result = schema({});
|
||||
|
||||
expect(result).not.toBeInstanceOf(type.errors);
|
||||
if (!(result instanceof type.errors)) {
|
||||
expect(result.migrationsPath).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
test("should accept a valid path", () => {
|
||||
const schema = createEnvSchema();
|
||||
const result = schema({ MIGRATIONS_PATH: "/custom/migrations" });
|
||||
|
||||
expect(result).not.toBeInstanceOf(type.errors);
|
||||
if (!(result instanceof type.errors)) {
|
||||
expect(result.migrationsPath).toBe("/custom/migrations");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -6,12 +6,16 @@ const envSchema = type({
|
|||
SERVER_IP: 'string = "localhost"',
|
||||
SERVER_IDLE_TIMEOUT: 'string.integer.parse = "60"',
|
||||
RESTIC_HOSTNAME: "string = 'zerobyte'",
|
||||
PORT: 'string.integer.parse = "4096"',
|
||||
"MIGRATIONS_PATH?": "string",
|
||||
}).pipe((s) => ({
|
||||
__prod__: s.NODE_ENV === "production",
|
||||
environment: s.NODE_ENV,
|
||||
serverIp: s.SERVER_IP,
|
||||
serverIdleTimeout: s.SERVER_IDLE_TIMEOUT,
|
||||
resticHostname: s.RESTIC_HOSTNAME,
|
||||
port: s.PORT,
|
||||
migrationsPath: s.MIGRATIONS_PATH,
|
||||
}));
|
||||
|
||||
const parseConfig = (env: unknown) => {
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@ const sqlite = new Database(DATABASE_URL);
|
|||
export const db = drizzle({ client: sqlite, schema });
|
||||
|
||||
export const runDbMigrations = () => {
|
||||
let migrationsFolder = path.join("/app", "assets", "migrations");
|
||||
let migrationsFolder: string;
|
||||
|
||||
if (!config.__prod__) {
|
||||
if (config.migrationsPath) {
|
||||
migrationsFolder = config.migrationsPath;
|
||||
} else if (config.__prod__) {
|
||||
migrationsFolder = path.join("/app", "assets", "migrations");
|
||||
} else {
|
||||
migrationsFolder = path.join("/app", "app", "drizzle");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ await validateRequiredMigrations(REQUIRED_MIGRATIONS);
|
|||
|
||||
startup();
|
||||
|
||||
logger.info(`Server is running at http://localhost:4096`);
|
||||
logger.info(`Server is running at http://localhost:${config.port}`);
|
||||
|
||||
export type AppType = typeof app;
|
||||
|
||||
|
|
@ -36,7 +36,7 @@ process.on("SIGINT", async () => {
|
|||
|
||||
export default await createHonoServer({
|
||||
app,
|
||||
port: 4096,
|
||||
port: config.port,
|
||||
customBunServer: {
|
||||
idleTimeout: config.serverIdleTimeout,
|
||||
error(err) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue