2026-02-14 11:47:26 +01:00
|
|
|
|
/**
|
2026-03-08 21:12:52 +01:00
|
|
|
|
* Environment variables parser.
|
2026-02-14 11:47:26 +01:00
|
|
|
|
* Parsed once at startup — all env access should go through this module.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2026-03-08 21:12:52 +01:00
|
|
|
|
export interface Env {
|
|
|
|
|
|
IMMICH_API_URL: string;
|
|
|
|
|
|
IMMICH_API_KEY: string;
|
|
|
|
|
|
SITE_TITLE: string;
|
|
|
|
|
|
SITE_SUBTITLE: string;
|
|
|
|
|
|
CACHE_TTL: number;
|
|
|
|
|
|
RATE_LIMIT_RPM: number;
|
|
|
|
|
|
AUTH_SECRET?: string;
|
2026-07-20 18:57:57 +02:00
|
|
|
|
TRUSTED_PROXY_HOPS: number;
|
feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
|
WEBHOOK_SECRET?: string;
|
|
|
|
|
|
ADMIN_PASSWORD?: string;
|
2026-03-08 21:12:52 +01:00
|
|
|
|
}
|
2026-03-07 08:18:23 +01:00
|
|
|
|
|
2026-03-08 21:12:52 +01:00
|
|
|
|
function parseEnv(): Env {
|
|
|
|
|
|
const errors: string[] = [];
|
|
|
|
|
|
|
|
|
|
|
|
const urlRaw = process.env.IMMICH_API_URL;
|
|
|
|
|
|
let apiUrl = '';
|
2026-03-08 21:38:44 +01:00
|
|
|
|
if (urlRaw) {
|
2026-03-08 21:12:52 +01:00
|
|
|
|
try {
|
|
|
|
|
|
apiUrl = new URL(urlRaw).toString().replace(/\/+$/, '');
|
|
|
|
|
|
} catch {
|
2026-03-08 21:38:44 +01:00
|
|
|
|
console.warn('⚠️ IMMICH_API_URL is invalid, falling back to empty string for setup.');
|
2026-03-08 21:12:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-02-14 11:47:26 +01:00
|
|
|
|
|
2026-03-08 21:38:44 +01:00
|
|
|
|
const apiKey = process.env.IMMICH_API_KEY || '';
|
2026-03-08 21:12:52 +01:00
|
|
|
|
|
|
|
|
|
|
const cacheTtlStr = process.env.CACHE_TTL;
|
2026-03-12 11:30:45 +00:00
|
|
|
|
const cacheTtl =
|
|
|
|
|
|
cacheTtlStr && !isNaN(parseInt(cacheTtlStr, 10)) ? parseInt(cacheTtlStr, 10) : 300;
|
2026-03-08 21:12:52 +01:00
|
|
|
|
|
|
|
|
|
|
const rateLimitStr = process.env.RATE_LIMIT_RPM;
|
2026-03-12 11:30:45 +00:00
|
|
|
|
const rateLimit =
|
chore: clean up repo root and improve .gitignore
- Remove debug scripts: check_albums.js, check_albums.ts
- Remove git-filter-repo binary from root
- Untrack server.log (was accidentally committed)
- Delete .DS_Store files
- Rewrite .gitignore with clear sections: deps, next.js,
TypeScript, testing, logs, env, OS/editor, agent tools,
one-off scripts, deployment, user content
- Add .Jules/ and *.log glob to .gitignore
2026-03-13 10:33:07 +01:00
|
|
|
|
rateLimitStr && !isNaN(parseInt(rateLimitStr, 10)) ? parseInt(rateLimitStr, 10) : 1500;
|
2026-03-08 21:12:52 +01:00
|
|
|
|
|
2026-07-20 18:57:57 +02:00
|
|
|
|
// Number of reverse proxies in front of the app. Determines how far from the
|
|
|
|
|
|
// right of X-Forwarded-For the real client IP sits. nginx/Traefik/Caddy = 1;
|
|
|
|
|
|
// add 1 for each additional layer (e.g. Cloudflare in front of nginx = 2).
|
|
|
|
|
|
const hopsStr = process.env.TRUSTED_PROXY_HOPS;
|
|
|
|
|
|
let trustedProxyHops = hopsStr && !isNaN(parseInt(hopsStr, 10)) ? parseInt(hopsStr, 10) : 0;
|
|
|
|
|
|
|
|
|
|
|
|
// TRUSTED_PROXIES (removed) matched proxy IPs against the socket peer address,
|
|
|
|
|
|
// which self-hosted Next.js never exposes — so it silently disabled per-client
|
|
|
|
|
|
// rate limiting and lumped every visitor into one shared bucket. Migrate the
|
|
|
|
|
|
// common single-proxy case rather than leaving those deploys broken.
|
|
|
|
|
|
if (trustedProxyHops === 0 && process.env.TRUSTED_PROXIES) {
|
|
|
|
|
|
trustedProxyHops = 1;
|
|
|
|
|
|
console.warn(
|
|
|
|
|
|
'\n⚠️ TRUSTED_PROXIES is deprecated and has no effect. Assuming TRUSTED_PROXY_HOPS=1.\n' +
|
|
|
|
|
|
' Set TRUSTED_PROXY_HOPS explicitly (nginx/Traefik/Caddy = 1) and remove TRUSTED_PROXIES.\n',
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (trustedProxyHops < 0) trustedProxyHops = 0;
|
|
|
|
|
|
|
2026-03-08 21:12:52 +01:00
|
|
|
|
return {
|
|
|
|
|
|
IMMICH_API_URL: apiUrl,
|
|
|
|
|
|
IMMICH_API_KEY: apiKey as string,
|
|
|
|
|
|
SITE_TITLE: process.env.SITE_TITLE || 'Gallery',
|
|
|
|
|
|
SITE_SUBTITLE: process.env.SITE_SUBTITLE || '',
|
|
|
|
|
|
CACHE_TTL: Math.max(0, cacheTtl),
|
|
|
|
|
|
RATE_LIMIT_RPM: Math.max(1, rateLimit),
|
|
|
|
|
|
AUTH_SECRET: process.env.AUTH_SECRET,
|
2026-07-20 18:57:57 +02:00
|
|
|
|
TRUSTED_PROXY_HOPS: trustedProxyHops,
|
feat: add visual admin panel with page builder and settings editor
- Add /admin route with password-protected visual page builder
- Page Builder: manage hero images, standalone albums, subpages, and sections
- Album Picker: browse all shared Immich albums with search and filtering
- Settings Editor: theme, grid, footer, legal, SEO configuration
- YAML service with atomic writes and automatic backups (content/.backups/)
- HMAC-signed admin sessions (24h expiry, HttpOnly cookies)
- API endpoints: /api/admin/{auth,gallery,settings,albums,reload}
- Enable with ADMIN_PASSWORD env var; disabled by default
- invalidateConfigCache() export for hot-reload after saves
2026-05-29 17:04:37 +02:00
|
|
|
|
WEBHOOK_SECRET: process.env.WEBHOOK_SECRET || undefined,
|
|
|
|
|
|
ADMIN_PASSWORD: process.env.ADMIN_PASSWORD || undefined,
|
2026-03-08 21:12:52 +01:00
|
|
|
|
};
|
2026-02-14 11:47:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Validated, typed environment variables. */
|
|
|
|
|
|
export const env = parseEnv();
|