Files
medassist-ng/backend/src/utils/server-config.ts
T

114 lines
2.7 KiB
TypeScript

/**
* Utility functions for server configuration.
* Exported separately to allow testing without triggering server start.
*/
import { existsSync, mkdirSync } from "node:fs";
import { resolve } from "node:path";
import type { CookieSerializeOptions } from "@fastify/cookie";
import { getDataDir } from "../db/path-utils.js";
/**
* Parse comma-separated CORS origins string
*/
export function parseCorsOrigins(originsStr: string): string[] {
return originsStr
.split(",")
.map((o) => o.trim())
.filter((o) => o.length > 0);
}
/**
* Build base cookie options for access token
*/
export function buildBaseCookieOptions(accessTtlMinutes: number, isProduction: boolean): CookieSerializeOptions {
return {
httpOnly: true,
secure: isProduction,
sameSite: "lax",
path: "/",
maxAge: accessTtlMinutes * 60, // Convert minutes to seconds
};
}
/**
* Build refresh cookie options (extends base with longer TTL)
*/
export function buildRefreshCookieOptions(
baseCookieOptions: CookieSerializeOptions,
refreshTtlDays: number
): CookieSerializeOptions {
return {
...baseCookieOptions,
maxAge: refreshTtlDays * 24 * 60 * 60, // Convert days to seconds
};
}
/**
* Build complete app configuration object
*/
export interface AppConfigOptions {
jwtSecret?: string;
refreshSecret?: string;
accessTtlMinutes: number;
refreshTtlDays: number;
isProduction: boolean;
}
export interface AppConfig {
accessSecret: string;
refreshSecret: string;
accessTtl: number;
refreshTtl: number;
cookieOptions: CookieSerializeOptions;
refreshCookieOptions: CookieSerializeOptions;
}
export function buildAppConfig(options: AppConfigOptions): AppConfig {
const cookieOptions = buildBaseCookieOptions(options.accessTtlMinutes, options.isProduction);
const refreshCookieOptions = buildRefreshCookieOptions(cookieOptions, options.refreshTtlDays);
return {
accessSecret: options.jwtSecret || "",
refreshSecret: options.refreshSecret || "",
accessTtl: options.accessTtlMinutes,
refreshTtl: options.refreshTtlDays,
cookieOptions,
refreshCookieOptions,
};
}
/**
* Ensure images directory exists
*/
export function ensureImagesDirectory(cwd?: string): string {
const imagesDir = resolve(getDataDir(cwd), "images");
if (!existsSync(imagesDir)) {
mkdirSync(imagesDir, { recursive: true });
}
return imagesDir;
}
/**
* Get JWT configuration based on auth enabled status
*/
export interface JwtConfig {
secret: string;
cookie: {
cookieName: string;
signed: boolean;
};
}
export function getJwtConfig(authEnabled: boolean, jwtSecret?: string): JwtConfig {
const effectiveSecret = authEnabled && jwtSecret ? jwtSecret : "auth-disabled-no-secret-needed";
return {
secret: effectiveSecret,
cookie: {
cookieName: "access_token",
signed: false,
},
};
}