import { Injectable, signal, computed } from '@angular/core'; export interface PasswordPolicyInfo { minLength: number; requireMixed: boolean; description: string; } export interface BootstrapPayload { initialized: boolean; pageTitle: string; logo: string; welcomeMarkdown: string; theme: any; defaultChallengeIp: string; registrationsEnabled: boolean; passwordPolicy: PasswordPolicyInfo; } const DEFAULT_POLICY: PasswordPolicyInfo = { minLength: 12, requireMixed: true, description: 'At least 12 characters with upper, lower, digit and symbol', }; @Injectable({ providedIn: 'root' }) export class BootstrapService { readonly payload = signal(null); readonly initialized = signal(false); readonly passwordPolicy = computed( () => this.payload()?.passwordPolicy ?? DEFAULT_POLICY, ); private loadPromise: Promise | null = null; async load(): Promise { if (!this.loadPromise) { this.loadPromise = this._load(); } return this.loadPromise; } private async _load(): Promise { try { const res = await fetch('/api/v1/bootstrap', { credentials: 'include' }); const data = (await res.json()) as BootstrapPayload; this.payload.set(data); this.initialized.set(data.initialized); this.applyTheme(data.theme); return data; } catch (e) { console.error('Bootstrap load failed', e); return null; } } ready(): Promise { if (!this.loadPromise) { this.loadPromise = this._load(); } return this.loadPromise; } markInitialized(): void { this.initialized.set(true); } private applyTheme(theme: any): void { if (!theme?.tokens) return; const root = document.documentElement.style; const t = theme.tokens; root.setProperty('--color-primary', t.primary); root.setProperty('--color-secondary', t.secondary); root.setProperty('--color-accent', t.accent); root.setProperty('--color-surface', t.surface); root.setProperty('--color-text', t.text); root.setProperty('--color-success', t.success); root.setProperty('--color-warning', t.warning); root.setProperty('--color-danger', t.danger); root.setProperty('--font-family', t.fontFamily); root.setProperty('--radius-sm', t.radii.sm); root.setProperty('--radius-md', t.radii.md); root.setProperty('--radius-lg', t.radii.lg); } }