diff --git a/src/app/core/unsplash/unsplash.service.ts b/src/app/core/unsplash/unsplash.service.ts index 243918e14..7adc255e8 100644 --- a/src/app/core/unsplash/unsplash.service.ts +++ b/src/app/core/unsplash/unsplash.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, of } from 'rxjs'; import { catchError } from 'rxjs/operators'; -import { getEnv } from '../../util/env'; +import { getEnvOptional } from '../../util/env'; export interface UnsplashPhoto { id: string; @@ -42,12 +42,12 @@ export class UnsplashService { private readonly API_URL = 'https://api.unsplash.com'; // Register your app at https://unsplash.com/developers for a free Access Key (50 req/hour) // The Access Key is used with "Client-ID" prefix in the Authorization header - private readonly ACCESS_KEY = getEnv('UNSPLASH_KEY'); + private readonly ACCESS_KEY = getEnvOptional('UNSPLASH_KEY'); constructor(private _http: HttpClient) {} isAvailable(): boolean { - return !!this.ACCESS_KEY && this.ACCESS_KEY !== 'undefined'; + return !!this.ACCESS_KEY; } searchPhotos(query: string, page = 1): Observable { diff --git a/src/app/util/env.ts b/src/app/util/env.ts index 9b4a7e972..0f6f1e266 100644 --- a/src/app/util/env.ts +++ b/src/app/util/env.ts @@ -15,6 +15,16 @@ export const getEnv = (key: keyof typeof ENV): string | undefined => { return ENV[key] || undefined; }; +/** + * Get an optional environment variable that may not be in the required list. + * Use this for environment variables that are truly optional and may not be defined + * in the REQUIRED_ENV_KEYS list in load-env.js. + * Returns undefined if the variable is not set. + */ +export const getEnvOptional = (key: string): string | undefined => { + return (ENV as any)[key] || undefined; +}; + /** * Get an environment variable as a number. * Returns undefined if the value is not a valid number. diff --git a/tools/load-env.js b/tools/load-env.js index 5054e6ffb..221104bab 100755 --- a/tools/load-env.js +++ b/tools/load-env.js @@ -4,19 +4,29 @@ const fs = require('fs'); const path = require('path'); const dotenv = require('dotenv'); +// Define keys that should always be included in types for backwards compatibility +// These are checked with getEnv() which requires strict typing const REQUIRED_ENV_KEYS = [ - 'UNSPLASH_KEY', - 'UNSPLASH_CLIENT_ID', - // 'GOOGLE_DRIVE_TOKEN', - // 'DROPBOX_API_KEY', - // 'WEBDAV_URL', - // 'WEBDAV_USERNAME', - // 'WEBDAV_PASSWORD', + // Currently empty - add keys here that should always be in the type definition ]; -// Start with system environment variables for required keys +// Define optional keys that might be provided +// These can be accessed with getEnvOptional() without strict typing +const OPTIONAL_ENV_KEYS = [ + 'UNSPLASH_KEY', + 'UNSPLASH_CLIENT_ID', + 'GOOGLE_DRIVE_TOKEN', + 'DROPBOX_API_KEY', + 'WEBDAV_URL', + 'WEBDAV_USERNAME', + 'WEBDAV_PASSWORD', +]; + +const ALL_KEYS = [...REQUIRED_ENV_KEYS, ...OPTIONAL_ENV_KEYS]; + +// Start with system environment variables const env = {}; -REQUIRED_ENV_KEYS.forEach((key) => { +ALL_KEYS.forEach((key) => { if (process.env[key]) { env[key] = process.env[key]; } @@ -26,32 +36,32 @@ REQUIRED_ENV_KEYS.forEach((key) => { const envPath = path.join(process.cwd(), '.env'); const envConfig = dotenv.config({ path: envPath }); if (envConfig.parsed) { + // Add all values from .env file, not just the predefined keys Object.assign(env, envConfig.parsed); } // Log what we found -const foundKeys = Object.keys(env).filter((key) => REQUIRED_ENV_KEYS.includes(key)); +const foundKeys = Object.keys(env); if (foundKeys.length > 0) { - console.log( - `✅ Found ${foundKeys.length} environment variable(s): ${foundKeys.join(', ')}`, - ); + console.log(`✅ Found ${foundKeys.length} environment variable(s)`); } else { - console.warn( - '⚠️ No environment variables found, generating env.generated.ts with undefined values', - ); + console.warn('⚠️ No environment variables found'); } -// Create ENV object with all expected keys (undefined if not set) -const envEntries = REQUIRED_ENV_KEYS.map((key) => { - const value = env[key]; - if (value !== undefined) { - // Escape quotes in values - const escapedValue = value.replace(/'/g, "\\'"); - return ` ${key}: '${escapedValue}',`; - } else { - return ` ${key}: undefined,`; - } -}); +// Create ENV object with all found keys plus required keys (undefined if not set) +const allEnvKeys = new Set([...REQUIRED_ENV_KEYS, ...Object.keys(env)]); +const envEntries = Array.from(allEnvKeys) + .sort() + .map((key) => { + const value = env[key]; + if (value !== undefined) { + // Escape quotes in values + const escapedValue = value.replace(/'/g, "\\'"); + return ` ${key}: '${escapedValue}',`; + } else if (REQUIRED_ENV_KEYS.includes(key)) { + throw new Error(`Required env key ${key} not found`); + } + }); // Generate TypeScript content const tsContent = `// This file is auto-generated by tools/load-env.js