UNPKG

ngx-runtime-initializer

Version:

Angular package for loading runtime configuration, managing app settings, and injecting services with post-initialization callbacks, compatible with standalone Angular 19+ applications.

1 lines 17.3 kB
{"version":3,"file":"ngx-runtime-initializer.mjs","sources":["../../../projects/ngx-runtime-initializer/src/lib/app-config.ts","../../../projects/ngx-runtime-initializer/src/lib/app-config.service.ts","../../../projects/ngx-runtime-initializer/src/lib/guards/maintenance.guard.ts","../../../projects/ngx-runtime-initializer/src/lib/models/runtime-initializer-options.ts","../../../projects/ngx-runtime-initializer/src/lib/runtime-initializer.ts","../../../projects/ngx-runtime-initializer/src/public-api.ts","../../../projects/ngx-runtime-initializer/src/ngx-runtime-initializer.ts"],"sourcesContent":["import { RuntimeConfig } from './models/app-config.model';\r\n\r\n/**\r\n * Implementation of the runtime application configuration.\r\n *\r\n * Holds core configuration values (API URL, debug mode, request timeout)\r\n * and the current status of the application.\r\n *\r\n * Can be initialized partially using a `Partial<RuntimeConfig>` object,\r\n * with optional override for the `status` flag.\r\n *\r\n * @example\r\n * // Default initialization\r\n * const config = new AppConfig();\r\n *\r\n * // Initialize with custom API URL and enable debug\r\n * const config = new AppConfig({\r\n * coreConfig: { apiURL: 'https://api.example.com', debug: true, requestTimeout: 20000 }\r\n * }, true);\r\n */\r\nexport class AppConfig implements RuntimeConfig {\r\n /**\r\n * Core configuration object containing API URL, debug flag, and request timeout.\r\n */\r\n coreConfig = {\r\n apiURL: '__BACKEND__',\r\n debug: false,\r\n requestTimeout: 30000,\r\n };\r\n\r\n /**\r\n * Status of the application (true = up/active, false = down/maintenance).\r\n */\r\n status = false;\r\n\r\n /**\r\n * Creates a new AppConfig instance.\r\n *\r\n * @param init - Partial configuration to override default values.\r\n * @param status - Optional status override (default is `false`).\r\n */\r\n constructor(init?: Partial<RuntimeConfig>, status: boolean = false) {\r\n Object.assign(this, init);\r\n this.status = status;\r\n }\r\n}\r\n","import { Injectable, signal, WritableSignal } from '@angular/core';\r\nimport { AppConfig } from './app-config';\r\n\r\n/**\r\n * Service for managing the application's runtime configuration.\r\n *\r\n * Provides reactive access to the configuration using Angular signals,\r\n * allows updating configuration at runtime, and exposes convenience\r\n * methods to retrieve configuration values or application status.\r\n *\r\n * Additionally, it sets global variables `$CORE_API` and `$DEBUG`\r\n * when the configuration is updated.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class AppConfigService {\r\n /**\r\n * Internal writable signal holding the current application configuration.\r\n */\r\n private readonly config: WritableSignal<AppConfig> = signal<AppConfig>(new AppConfig());\r\n\r\n /**\r\n * Updates the application configuration.\r\n *\r\n * This will also update the global variables:\r\n * - `$CORE_API` with `config.coreConfig.apiURL`\r\n * - `$DEBUG` with `config.coreConfig.debug`\r\n *\r\n * @param config - The new configuration to set.\r\n */\r\n setConfig(config: AppConfig) {\r\n (globalThis as any).$CORE_API = config.coreConfig.apiURL;\r\n (globalThis as any).$DEBUG = config.coreConfig.debug;\r\n this.config.set(config);\r\n }\r\n\r\n /**\r\n * Returns the current status of the application.\r\n *\r\n * @returns `true` if the app is up/active, `false` if it is down/maintenance.\r\n */\r\n getStatus(): boolean {\r\n return this.config().status;\r\n }\r\n\r\n /**\r\n * Returns the reactive `WritableSignal` holding the configuration.\r\n *\r\n * Consumers can subscribe to this signal for reactive updates.\r\n *\r\n * @returns The `WritableSignal<AppConfig>` instance.\r\n */\r\n getConfigSignal(): WritableSignal<AppConfig> {\r\n return this.config;\r\n }\r\n\r\n /**\r\n * Returns the current configuration snapshot.\r\n *\r\n * @returns The current `AppConfig` object.\r\n */\r\n getConfig(): AppConfig {\r\n return this.config();\r\n }\r\n\r\n /**\r\n * Retrieves a specific property from the current configuration.\r\n *\r\n * @typeParam T - Expected type of the property.\r\n * @param key - The key of the property in `AppConfig`.\r\n * @returns The value of the property if it exists, otherwise `undefined`.\r\n *\r\n * @example\r\n * const apiUrl = service.getConfigProperty<string>('coreConfig').apiURL;\r\n */\r\n getConfigProperty<T>(key: keyof AppConfig): T | undefined {\r\n return this.config()[key] as T;\r\n }\r\n}\r\n","import { inject } from '@angular/core';\nimport { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router';\nimport { AppConfigService } from '../app-config.service';\n\n/**\n * Factory function to create a route guard that checks the application status.\n *\n * The guard compares the current application status from {@link AppConfigService}\n * with the expected `shouldBeOk` value. If the actual status does not match,\n * the user is redirected to the provided `redirectUrl`.\n *\n * @param shouldBeOk - Expected status:\n * - `true`: route is accessible only if the app is up/active\n * - `false`: route is accessible only if the app is down/maintenance\n * @param redirectUrl - URL to redirect to when the status does not match `shouldBeOk`\n * @returns A `CanActivateFn` that enforces the status check.\n *\n * @example\n * // Only allow access when the app is up\n * const guard = createStatusGuard(true, '/maintenance');\n *\n * // Only allow access when the app is down\n * const guard = createStatusGuard(false, '/');\n */\nexport function createStatusGuard(shouldBeOk: boolean, redirectUrl: string): CanActivateFn {\n return (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {\n const router = inject(Router);\n const isStatusOK = inject(AppConfigService).getStatus();\n\n if (isStatusOK !== shouldBeOk) {\n router.navigate([redirectUrl], { replaceUrl: true });\n return false;\n }\n\n return true;\n };\n}\n\n/**\n * Predefined guard that only allows access when the application is UP.\n * Redirects to `/maintenance` if the application is down.\n */\nexport const InMaintenanceGuard = createStatusGuard(true, '/maintenance');\n\n/**\n * Predefined guard that only allows access when the application is DOWN.\n * Redirects to `/` if the application is up.\n */\nexport const MaintenanceGuard = createStatusGuard(false, '/');\n","import { Type } from '@angular/core';\nimport { AppConfig } from '../app-config';\n\n/**\n * Options for configuring the runtime initializer.\n */\nexport class RuntimeInitializerOptions {\n /** URL of the runtime configuration JSON */\n configUrl: string = 'config.json';\n\n /** Array of Angular service classes to inject and pass to callbacks */\n servicesToInject: Type<any>[] = [];\n\n /**\n * Optional async callback executed after successful configuration load.\n * Receives the loaded `AppConfig` and an object mapping injected services by class name.\n */\n postInit: (config: AppConfig, services: Record<string, any>) => Promise<void> = async () => {};\n\n /**\n * Optional callback executed if initialization fails.\n * Receives the error and injected services object.\n */\n handleInitializationFailure: (error: any, services: Record<string, any>) => void = () => {};\n\n /**\n * Constructor for fast initialization or custom values.\n * @param configUrl - URL of the config JSON\n * @param servicesToInject - Array of Angular services to inject\n * @param postInit - Callback after successful initialization\n * @param handleInitializationFailure - Callback on initialization failure\n */\n constructor(\n configUrl?: string,\n servicesToInject?: Type<any>[],\n postInit?: (config: AppConfig, services: Record<string, any>) => Promise<void>,\n handleInitializationFailure?: (error: any, services: Record<string, any>) => void\n ) {\n if (configUrl) this.configUrl = configUrl;\n if (servicesToInject) this.servicesToInject = servicesToInject;\n if (postInit) this.postInit = postInit;\n if (handleInitializationFailure) this.handleInitializationFailure = handleInitializationFailure;\n }\n}\n","import { HttpClient, HttpErrorResponse } from '@angular/common/http';\r\nimport { inject, provideAppInitializer } from '@angular/core';\r\nimport { catchError, firstValueFrom, of, throwError, timeout } from 'rxjs';\r\nimport { AppConfigService, RuntimeInitializerOptions } from '../public-api';\r\nimport { AppConfig } from './app-config';\r\n\r\n/**\r\n * Provides an Angular application initializer that loads runtime configuration from a JSON file\r\n * and optionally injects additional services.\r\n *\r\n * @param options - Configuration options for the runtime initializer.\r\n *\r\n * @returns A provider for Angular's `APP_INITIALIZER`.\r\n *\r\n * @example\r\n * // Basic usage: load config from default 'config.json'\r\n * provideRuntimeInitializer({});\r\n *\r\n * @example\r\n * // With custom services and post-init callback\r\n * provideRuntimeInitializer({\r\n * configUrl: '/assets/runtime-config.json',\r\n * servicesToInject: [MyService1, MyService2],\r\n * postInit: async (config, services) => {\r\n * console.log('Config loaded:', config);\r\n * services.MyService1?.initialize();\r\n * },\r\n * handleInitializationFailure: (error, services) => {\r\n * console.warn('Failed to initialize runtime config:', error);\r\n * }\r\n * });\r\n */\r\nexport function provideRuntimeInitializer({\r\n configUrl = 'config.json',\r\n servicesToInject = [],\r\n postInit = async () => {},\r\n handleInitializationFailure = () => {},\r\n}: RuntimeInitializerOptions) {\r\n return provideAppInitializer(async () => {\r\n const http = inject(HttpClient);\r\n const appService = inject(AppConfigService);\r\n const injectedServices: Record<string, any> = {};\r\n\r\n servicesToInject.forEach((cls) => {\r\n try {\r\n injectedServices[cls.name.replace('_', '')] = inject(cls, { optional: true });\r\n } catch {\r\n injectedServices[cls.name.replace('_', '')] = undefined;\r\n }\r\n });\r\n\r\n try {\r\n const runtimeConfig = await firstValueFrom(\r\n http.get<AppConfig>(configUrl).pipe(\r\n timeout(3000),\r\n catchError((err) => {\r\n if (err.name === 'TimeoutError') {\r\n return throwError(() => new Error(`[RuntimeInitializer] Timeout: Could not load config from ${configUrl}`));\r\n }\r\n if (err instanceof HttpErrorResponse) {\r\n return throwError(\r\n () => new Error(`[RuntimeInitializer] Failed to load config from ${configUrl}: ${err.status} ${err.statusText}`)\r\n );\r\n }\r\n return throwError(() => err);\r\n })\r\n )\r\n );\r\n\r\n if (runtimeConfig.coreConfig.debug) {\r\n console.log(runtimeConfig);\r\n }\r\n\r\n if (!runtimeConfig?.coreConfig) {\r\n throw new Error('[RuntimeInitializer] Missing coreConfig in config.json');\r\n }\r\n if (!runtimeConfig.coreConfig.apiURL) {\r\n throw new Error('[RuntimeInitializer] coreConfig.apiURL is required');\r\n }\r\n if (typeof runtimeConfig.coreConfig.debug !== 'boolean') {\r\n throw new Error('[RuntimeInitializer] coreConfig.debug must be boolean');\r\n }\r\n if (typeof runtimeConfig.coreConfig.requestTimeout !== 'number') {\r\n throw new Error('[RuntimeInitializer] coreConfig.requestTimeout must be a number');\r\n }\r\n\r\n appService.setConfig(new AppConfig(runtimeConfig, true));\r\n\r\n if (postInit) {\r\n await postInit(appService.getConfig(), injectedServices);\r\n }\r\n return of(runtimeConfig);\r\n } catch (error) {\r\n console.error('Failed to load runtime config', error);\r\n const fallbackConfig = new AppConfig();\r\n\r\n appService.setConfig(fallbackConfig);\r\n if (handleInitializationFailure) {\r\n handleInitializationFailure(error, injectedServices);\r\n }\r\n return of(fallbackConfig);\r\n }\r\n });\r\n}\r\n","/*\r\n * Public API Surface of ngx-runtime-initializer\r\n */\r\nexport * from './lib/app-config';\r\nexport * from './lib/app-config.service';\r\nexport * from './lib/guards/maintenance.guard';\r\nexport * from './lib/models/app-config.model';\r\nexport * from './lib/models/runtime-initializer-options';\r\nexport * from './lib/runtime-initializer';\r\ndeclare global {\r\n const $CORE_API: string;\r\n const $DEBUG: boolean;\r\n}\r\n\r\nexport {};\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}