84 lines
2.1 KiB
TypeScript
84 lines
2.1 KiB
TypeScript
import { Injectable, signal, computed } from '@angular/core';
|
|
import {
|
|
applyThemeToCss,
|
|
BootstrapPayload,
|
|
PasswordPolicyInfo,
|
|
Theme,
|
|
} from './bootstrap.types';
|
|
|
|
export {
|
|
applyThemeToCss,
|
|
clearThemeCss,
|
|
THEME_CSS_PROPERTIES,
|
|
Theme,
|
|
ThemeTokens,
|
|
ThemeCssTarget,
|
|
BootstrapPayload,
|
|
PasswordPolicyInfo,
|
|
} from './bootstrap.types';
|
|
|
|
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<BootstrapPayload | null>(null);
|
|
readonly initialized = signal<boolean>(false);
|
|
readonly passwordPolicy = computed<PasswordPolicyInfo>(
|
|
() => this.payload()?.passwordPolicy ?? DEFAULT_POLICY,
|
|
);
|
|
|
|
private loadPromise: Promise<BootstrapPayload | null> | null = null;
|
|
|
|
async load(): Promise<BootstrapPayload | null> {
|
|
if (!this.loadPromise) {
|
|
this.loadPromise = this._load();
|
|
}
|
|
return this.loadPromise;
|
|
}
|
|
|
|
private async _load(): Promise<BootstrapPayload | null> {
|
|
try {
|
|
const data = await this.fetchAndApply('/api/v1/bootstrap');
|
|
return data;
|
|
} catch (e) {
|
|
console.error('Bootstrap load failed', e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
ready(): Promise<BootstrapPayload | null> {
|
|
if (!this.loadPromise) {
|
|
this.loadPromise = this._load();
|
|
}
|
|
return this.loadPromise;
|
|
}
|
|
|
|
async refresh(): Promise<BootstrapPayload> {
|
|
const data = await this.fetchAndApply('/api/v1/bootstrap');
|
|
return data;
|
|
}
|
|
|
|
markInitialized(): void {
|
|
this.initialized.set(true);
|
|
}
|
|
|
|
applyTheme(theme: Theme | null | undefined): void {
|
|
applyThemeToCss(theme);
|
|
}
|
|
|
|
private async fetchAndApply(url: string): Promise<BootstrapPayload> {
|
|
const res = await fetch(url, { credentials: 'include' });
|
|
if (!res.ok) {
|
|
throw new Error(`Bootstrap request failed: ${res.status}`);
|
|
}
|
|
const data = (await res.json()) as BootstrapPayload;
|
|
this.payload.set(data);
|
|
this.initialized.set(data.initialized);
|
|
this.applyTheme(data.theme);
|
|
return data;
|
|
}
|
|
} |