@coolms/core-angular 2.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/fesm2022/coolms-core-angular.mjs +2085 -0
- package/fesm2022/coolms-core-angular.mjs.map +1 -0
- package/package.json +51 -0
- package/types/coolms-core-angular.d.ts +1415 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coolms-core-angular.mjs","sources":["../../src/api/api-manifest.types.ts","../../src/api/form-render.types.ts","../../src/state/app-config.state.ts","../../src/api/identity-api.client.ts","../../src/api/realtime-token.client.ts","../../src/auth/auth.actions.ts","../../src/services/user-preferences.service.ts","../../src/auth/auth.state.ts","../../src/auth/auth-refresh.coordinator.ts","../../src/auth/auth.interceptor.ts","../../src/auth/cross-tab-auth-sync.service.ts","../../src/bootstrap/app-init.service.ts","../../src/auth/auth.guard.ts","../../src/auth/login-page.guard.ts","../../src/auth/login/login.component.ts","../../src/auth/login/login.component.html","../../src/config/config.service.ts","../../src/errors/error-handler.service.ts","../../src/theme/theme.service.ts","../../src/loader/cms-loader.component.ts","../../src/sidebar/sidebar-state.service.ts","../../src/entity-search/entity-search.service.ts","../../src/navi-graph/navi-graph.service.ts","../../src/navi-graph/navi-graph.types.ts","../../src/navi-graph/component-registry.ts","../../src/section/current-section.port.ts","../../src/interceptors/section.interceptor.ts","../../src/public-api.ts","../../src/coolms-core-angular.ts"],"sourcesContent":["// Typed contract — must mirror ApiManifest PHP VOs exactly.\n// No `any` anywhere.\n\nexport interface AuthApiManifest {\n readonly login: string;\n readonly logout: string;\n readonly refresh: string;\n readonly register: string;\n readonly me: string;\n readonly usersApi?: string; // GET /api/v1/auth/users\n readonly groupsApi?: string; // GET /api/v1/auth/groups\n readonly preferencesUrl?: string; // PATCH /api/v1/auth/me/preferences\n readonly groupFormId?: string | null;\n readonly userFormId?: string | null;\n}\n\nexport interface SectionApiManifest {\n readonly list: string;\n readonly create: string;\n readonly item: string; // URL pattern: /api/v1/sections/{id}\n readonly update: string;\n readonly delete: string;\n readonly formId?: string;\n readonly apply?: string; // POST /api/v1/sections/_apply (H9)\n}\n\nexport interface NaviApiManifest {\n readonly treesList: string;\n readonly treesCreate: string;\n readonly treesItem: string; // pattern: /api/v1/navi/trees/{slug}\n readonly nodesList: string;\n readonly nodesCreate: string;\n readonly nodesItem: string; // pattern: /api/v1/navi/nodes/{id}\n readonly nodesReorder: string; // PATCH /api/v1/navi/nodes/reorder\n readonly nodesMove: string; // pattern: /api/v1/navi/nodes/{id}/move\n readonly nodesByTree: string; // pattern: /api/v1/navi/trees/{slug}/nodes\n readonly treesFormId?: string;\n readonly nodesFormId?: string;\n readonly adminNavGraph?: string; // /api/v1/navi/trees/navi.admin/graph\n readonly topbarNavGraph?: string; // /api/v1/navi/trees/navi.admin.topbar/graph\n readonly toolbarVfsGraph?: string; // /api/v1/navi/trees/navi.toolbar.vfs/graph\n readonly graphBySlug?: string; // URL pattern: /api/v1/navi/trees/{slug}/graph\n}\n\nexport interface ContentApiManifest {\n // Page + variant CRUD lives on the generic VFS node endpoints, filtered\n // by mime where needed; what stays here is Content-owned surface.\n readonly variantPublishUrl: string; // pattern: /api/v1/content/variants/{id}/publish\n // Pages admin. Optional because a client built against an older backend\n // will not receive them, and the affected control degrades (an empty\n // space list, a picker with only \"Default\") rather than throwing.\n //\n // The five `articleXxxUrl` fields that stood here are GONE with the\n // endpoints they named. Placement destinations now\n // come from `/content/pages/surfaces` — still never hardcoded on the\n // client, because a surface is configuration, not a product concept.\n readonly pageSpacesUrl?: string; // /api/v1/content/pages/spaces\n readonly pageTypesUrl?: string; // /api/v1/content/page-types\n}\n\nexport interface DataGridApiManifest {\n readonly configBase: string; // base URL: /api/v1/datagrids\n}\n\nexport interface TerminalApiManifest {\n readonly executeUrl: string; // POST /api/v1/terminal/execute (SSE)\n readonly completeUrl: string; // POST /api/v1/terminal/complete\n}\n\nexport interface MediaApiManifest {\n readonly listUrl: string; // GET /media\n readonly itemUrl: string; // pattern: /api/v1/media/{id}\n readonly permissionsUrl: string; // pattern: /api/v1/media/{id}/permissions\n readonly regenerateUrl: string; // pattern: /api/v1/media/{id}/regenerate\n readonly resizeUrl: string; // pattern: /media/resize/{id}\n readonly collectionsUrl: string; // GET /api/v1/media/collections\n readonly collectionsCreateUrl: string; // POST /api/v1/media/collections\n readonly collectionPermissionsUrl: string; // PATCH /api/v1/media/collections/permissions\n readonly moveUrl?: string; // pattern: /api/v1/media/{id}/move\n readonly spacesUrl?: string; // GET /api/v1/media/spaces\n}\n\nexport interface VfsApiManifest {\n readonly fileContentUrl: string; // GET/PUT /api/v1/vfs/files/content?path={path}\n readonly binaryWriteUrl: string; // POST /api/v1/vfs/files/binary (multipart)\n}\n\n/**\n * Document module URL section. Today the only entry is `spacesUrl`;\n * the struct is reserved so future Document-module URLs can land\n * here without a new manifest section.\n */\nexport interface DocumentApiManifest {\n readonly spacesUrl?: string; // GET /api/v1/document/spaces\n}\n\nexport interface DynamicEntityApiManifest {\n readonly typesUrl: string; // GET /api/v1/dynamic-entity/types\n readonly fieldDefinitionsUrl: string; // POST /api/v1/field/definitions\n readonly fieldDefinitionUrl: string; // PUT/PATCH/DELETE /api/v1/field/definitions/{id}\n readonly fieldDefinitionsReorderUrl: string; // PATCH /api/v1/field/definitions/reorder\n readonly toolbarNaviGraphUrl: string; // GET /navi/trees/navi.toolbar.dynamic-entity/graph\n readonly constraintsUrl: string; // GET /api/v1/dynamic-entity/constraints\n readonly recordsUrl: string; // pattern: GET/POST /api/v1/dynamic-entity/{type}/records\n readonly recordUrl: string; // pattern: GET/PATCH/DELETE .../records/{id}\n readonly recordsByTypeUrl: string; // pattern: GET/POST /api/v1/dynamic-entity/{type}/records\n readonly typeUrl: string; // GET/PATCH/DELETE .../types/{id}\n readonly typesCreateUrl: string; // POST .../types (same as typesUrl)\n readonly formTypesUrl?: string; // GET /api/v1/field/form-types\n readonly typeByAliasUrl?: string; // GET /api/v1/dynamic-entity/types/{alias}\n}\n\nexport interface DomainExplorerApiManifest {\n readonly entitiesUrl: string; // GET /api/v1/domain-explorer/entities\n readonly entityUrl: string; // pattern: /api/v1/domain-explorer/entities/{entityAlias}\n readonly toolbarNaviGraphUrl: string; // GET /navi/trees/navi.toolbar.domain_explorer/graph\n readonly domainExplorerToolbarUrl: string; // alias for toolbarNaviGraphUrl (backward compat)\n readonly entityFieldsDataGridUrl?: string; // GET /api/v1/datagrids/domain_explorer:entity_fields\n readonly typeFieldsDataGridUrl?: string; // GET /api/v1/datagrids/domain_explorer:type_fields\n}\n\nexport interface IdentityApiManifest {\n readonly usersUrl: string; // GET /auth/users\n readonly userUrl: string; // /auth/users/{id} pattern\n readonly groupsUrl: string; // GET /auth/groups\n readonly groupUrl: string; // /auth/groups/{id} pattern\n readonly meUrl: string; // GET /auth/me\n readonly assignGroupsUrl: string; // /auth/users/{id}/groups pattern\n readonly avatarUploadUrl: string; // POST /auth/me/avatar\n readonly settingsUrl: string; // GET /auth/me/settings\n readonly settingsSectionsUrl: string; // GET /auth/me/settings/sections\n readonly settingsSectionUrl: string; // PATCH /auth/me/settings/{section} pattern\n readonly colorUrl: string; // PATCH /auth/me/color\n readonly rolesUrl?: string; // GET /api/v1/identity/roles\n}\n\n/**\n * Editor sub-manifest emitted by the backend's Editor module. The\n * frontend bridge (`@coolms/editor-angular`) consumes this through the\n * `EDITOR_MANIFEST_PROVIDER` token.\n *\n * schemaVersion 2 (sub-prompt D) replaced the editorId axis with a profile\n * axis: `manifest.editor.profiles[name]` returns a slice with the\n * pre-resolved contributor list AND the storage allow-list a sanitizer\n * enforces on save.\n */\nexport interface EditorApiManifestEntry {\n readonly id: string;\n readonly group: string;\n readonly priority: number;\n readonly icon: string;\n readonly label: string;\n readonly actionType: string;\n readonly actionParams: Readonly<Record<string, unknown>>;\n readonly extensions: ReadonlyArray<string>;\n readonly stateKeys: ReadonlyArray<string>;\n readonly shortcut?: string | null;\n // `slashable` (derived from `group`) flags the\n // entries the `/`-command palette offers; `keywords` are extra fuzzy-search\n // aliases. Both serialized into `GET /api/v1/theme/config`.\n readonly slashable?: boolean;\n readonly keywords?: ReadonlyArray<string>;\n}\n\nexport interface EditorApiManifestProfile {\n readonly contributors: ReadonlyArray<EditorApiManifestEntry>;\n readonly allowedWidgets: ReadonlyArray<string>;\n}\n\nexport interface EditorApiManifest {\n readonly schemaVersion: number;\n readonly profiles: Readonly<Record<string, EditorApiManifestProfile>>;\n}\n\n/**\n * Viewer manifest emitted by the backend's Document module.\n * Each viewer declares the MIME types / extensions it handles, the\n * Angular component selector to dispatch into, and one config blob per\n * profile. Profile config is open-ended — every viewer interprets the\n * keys it understands and ignores the rest.\n */\nexport interface ViewerProfileApiManifest {\n readonly key: string;\n readonly config: Readonly<Record<string, unknown>>;\n}\n\nexport interface ViewerDefinitionApiManifest {\n readonly key: string;\n readonly mimeTypes: ReadonlyArray<string>;\n readonly extensions: ReadonlyArray<string>;\n readonly component: string;\n readonly profiles: Readonly<Record<string, ViewerProfileApiManifest>>;\n}\n\nexport interface ViewerApiManifest {\n readonly schemaVersion: number;\n readonly viewers: Readonly<Record<string, ViewerDefinitionApiManifest>>;\n}\n\n/**\n * Platform-wide default user-facing settings. The\n * fallback floor for anonymous / pre-login rendering: timezone, date /\n * time format (CLDR tokens) and week start come from the deployment's\n * config, not an FE-hardcoded Western default. `locale` is the default\n * locale, previously absent from the manifest.\n */\nexport interface PlatformDefaults {\n readonly locale: string;\n readonly timezone: string;\n readonly dateFormat: string;\n readonly timeFormat: '12h' | '24h';\n readonly weekStart: 'monday' | 'sunday';\n /**\n * Deployment brand accent as `#rrggbb`, or null/absent to keep the\n * stylesheet's own. Sits BELOW a user's personal accentColor.\n */\n readonly accentColor?: string | null;\n}\n\nexport interface ApiManifest {\n readonly apiBase: string;\n readonly configBase?: string; // GET /api/v1/config/{type}/{id}\n readonly auth?: AuthApiManifest;\n readonly identity?: IdentityApiManifest;\n readonly sections?: SectionApiManifest;\n readonly navi?: NaviApiManifest;\n readonly content?: ContentApiManifest;\n readonly dataGrid?: DataGridApiManifest;\n readonly terminal?: TerminalApiManifest;\n readonly media?: MediaApiManifest;\n readonly document?: DocumentApiManifest;\n readonly vfs?: VfsApiManifest;\n readonly dynamicEntity?: DynamicEntityApiManifest;\n readonly domainExplorer?: DomainExplorerApiManifest;\n readonly editor?: EditorApiManifest;\n readonly viewers?: ViewerApiManifest;\n readonly supportedLocales?: Array<{ code: string; label: string }>;\n readonly platformDefaults?: PlatformDefaults;\n}\n\nexport interface ThemeConfigResponse {\n readonly slug?: string | null;\n readonly feStack?: string | null;\n readonly spaFramework?: string | null;\n readonly assetsUrl?: string | null;\n readonly manifest: ApiManifest;\n}\n\n/**\n * Replaces {param} tokens in a URL pattern with encoded values.\n *\n * @example\n * resolvePattern(manifest.sections!.item, { id: '123' })\n * // -> '/api/v1/sections/123'\n */\nexport function resolvePattern(pattern: string, params: Record<string, string>): string {\n return Object.entries(params).reduce(\n (url, [key, value]) => url.replace(`{${key}}`, encodeURIComponent(value)),\n pattern,\n );\n}\n","// Typed contract — mirrors FormRenderDefinition PHP VOs exactly.\n// No `any` anywhere.\n\nexport type FieldType =\n | 'text' | 'email' | 'password' | 'number' | 'textarea'\n | 'select' | 'toggle' | 'date' | 'time' | 'hidden'\n | 'relation' | 'subform' | 'token-pattern' | 'richtext'\n | 'localizedText' | 'localizedTextarea' | 'optionsEditor'\n // Phone module: composite international phone field — country select\n // (localized via Intl.DisplayNames + dial codes from /api/v1/phone/countries)\n // + masked number input, composing a single E.164 string value.\n | 'intlPhone'\n // Swatch picker + hex box over one value, where EMPTY is meaningful\n // (\"inherit the deployment's colour\") rather than missing. Added for the\n // per-user admin accent; nothing about it is theming-specific.\n | 'color';\n\nexport type DataSourceType = 'static' | 'enum' | 'api' | 'repo';\n\nexport type VisibilityOperator = 'eq' | 'ne' | 'in' | 'notIn' | 'empty' | 'notEmpty';\n\nexport interface VisibilityCondition {\n readonly field: string;\n readonly operator: VisibilityOperator;\n readonly value?: unknown;\n}\n\nexport type DataSourceWidget = 'select' | 'select-search' | 'select-tree' | 'token-input' | 'media-picker';\nexport type DataSourceLoading = 'eager' | 'lazy';\n\nexport interface DataSourceOption {\n readonly value: unknown;\n readonly label: string;\n readonly parentId?: string | null; // select-tree: used for client-side tree building\n}\n\nexport interface DataSourceDefinition {\n readonly type: DataSourceType;\n readonly bindValue: string;\n readonly bindLabel: string;\n readonly multiple: boolean;\n readonly maxItems?: number;\n readonly options?: ReadonlyArray<DataSourceOption>; // static + enum: resolved by backend\n readonly url?: string; // api + repo: fetch at runtime\n readonly widget: DataSourceWidget; // rendering strategy\n readonly loading: DataSourceLoading; // fetch strategy\n /** Free-form widget-specific configuration block populated from YAML\n * `dataSource.widgetOptions`. Used by media-picker for bindTarget /\n * display / accept / recentlyUsed / hoverPreview, and reserved for\n * future custom widgets. Kept separate from `options` (which is the\n * static-option list) to avoid key collisions. */\n readonly widgetOptions?: Readonly<Record<string, unknown>>;\n}\n\nexport interface ValidatorDefinition {\n readonly type: string;\n readonly value?: unknown;\n readonly message?: string;\n}\n\nexport interface RelationDefinition {\n readonly cardinality: 'one' | 'many';\n readonly maxItems?: number;\n readonly targetFormId?: string;\n readonly dataSource?: DataSourceDefinition;\n}\n\nexport interface SubFormDefinition {\n readonly formId: string;\n readonly relation: 'one' | 'many';\n readonly maxItems?: number;\n}\n\nexport interface FieldSecurityPolicy {\n readonly read: ReadonlyArray<string>;\n readonly write: ReadonlyArray<string>;\n}\n\nexport interface FieldItem {\n readonly alias: string;\n readonly type: FieldType;\n readonly label: string;\n readonly placeholder?: string;\n readonly hint?: string;\n readonly required: boolean;\n readonly readonly: boolean;\n readonly locked: boolean;\n readonly private: boolean;\n readonly validators: ReadonlyArray<ValidatorDefinition>;\n readonly dataSource?: DataSourceDefinition;\n readonly relation?: RelationDefinition;\n readonly subForm?: SubFormDefinition;\n readonly separators?: ReadonlyArray<string>; // token-pattern field: separator chars\n readonly security?: FieldSecurityPolicy | null;\n readonly autocomplete?: string; // HTML autocomplete token (e.g. 'username', 'current-password')\n}\n\nexport interface LayoutNode {\n // A layout container, or a field alias. The `& {}` is what keeps the five\n // names meaningful: a bare `| string` absorbs them, so the union listed\n // five options the compiler had already collapsed to `string` -- no\n // completion, no checking, just documentation that looked like a type.\n readonly type: 'group' | 'grid' | 'column' | 'tabs' | 'tab' | (string & {});\n readonly name?: string;\n readonly description?: string;\n readonly compact?: boolean;\n readonly width?: number; // 1–12 grid columns\n readonly children?: ReadonlyArray<LayoutNode>;\n readonly showWhen?: VisibilityCondition;\n}\n\nexport type FormActionType = 'submit' | 'button' | 'reset';\nexport type FormActionVariant = 'primary' | 'secondary' | 'danger' | 'link';\n\n/** Terminal form button (Submit / Cancel / …) — mirrors PHP FormAction.\n * Resolved by the backend (declared `formOptions.actions`, else lifted from\n * legacy submit fields, else a default Submit). `label` is already translated. */\nexport interface FormAction {\n readonly type: FormActionType;\n readonly label: string;\n readonly name: string;\n readonly variant: FormActionVariant;\n}\n\nexport interface FormRenderDefinition {\n readonly id: string;\n readonly context: 'create' | 'edit';\n readonly layout: ReadonlyArray<LayoutNode>;\n readonly items: ReadonlyArray<FieldItem>;\n readonly actions: ReadonlyArray<FormAction>;\n readonly action?: string; // declared submit target (formOptions.action)\n}\n","import { Injectable } from '@angular/core';\nimport { State, Action, Selector } from '@ngxs/store';\nimport type { StateContext } from '@ngxs/store';\nimport { type ApiManifest, type ThemeConfigResponse, type ViewerApiManifest } from '../api/api-manifest.types';\n\n// --- Action ------------------------------------------------------------------\n\nexport class SetAppConfig {\n static readonly type = '[AppConfig] Set';\n constructor(public readonly config: ThemeConfigResponse) {}\n}\n\n// --- State -------------------------------------------------------------------\n\nexport interface AppConfigStateModel {\n config: ThemeConfigResponse | null;\n loaded: boolean;\n}\n\n@State<AppConfigStateModel>({\n name: 'appConfig',\n defaults: { config: null, loaded: false },\n})\n@Injectable()\nexport class AppConfigState {\n\n @Action(SetAppConfig)\n set(ctx: StateContext<AppConfigStateModel>, { config }: SetAppConfig): void {\n ctx.setState({ config, loaded: true });\n }\n\n @Selector()\n static manifest(state: AppConfigStateModel): ApiManifest | null {\n return state.config?.manifest ?? null;\n }\n\n /**\n * F.7 viewer manifest. Null when the backend didn't ship a viewers\n * section (no tagged providers); consumers should fall back to a\n * \"no preview\" surface.\n */\n @Selector()\n static viewers(state: AppConfigStateModel): ViewerApiManifest | null {\n return state.config?.manifest.viewers ?? null;\n }\n\n @Selector()\n static loaded(state: AppConfigStateModel): boolean {\n return state.loaded;\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Store } from '@ngxs/store';\nimport { type Observable } from 'rxjs';\n\nimport { AppConfigState } from '../state/app-config.state';\nimport type { ApiManifest } from './api-manifest.types';\nimport type { TokenResponse, UserDto } from './auth.types';\n\n/**\n * The identity endpoints core owns: the session lifecycle, plus the settings\n * read at boot.\n *\n * Carved out of the admin's `ApiService` -- 2410 lines, 118 methods and 89 DTOs\n * spanning calendars, documents, calls, VFS and the rest. Core cannot depend on\n * that and still ship beneath the UI kit: it would drag every module's wire\n * types down with it. Core called exactly FOUR of those methods.\n *\n * `logout` is the one addition, and not for symmetry: the auth lifecycle lives\n * here (state, refresh coordinator, cross-tab sync), so a core package that\n * could sign in but not out would be incomplete.\n *\n * `ApiService` keeps its own identical signatures and delegates here, so none\n * of the 94 feature files calling it changed.\n */\n@Injectable({ providedIn: 'root' })\nexport class IdentityApiClient {\n private readonly http = inject(HttpClient);\n private readonly store = inject(Store);\n\n /** URLs come from the boot manifest, which core already owns. */\n private get manifest(): ApiManifest {\n const m = this.store.selectSnapshot(AppConfigState.manifest);\n if (!m) throw new Error('ApiManifest not loaded — call AppInitService.load() first');\n return m;\n }\n\n login(identifier: string, password: string): Observable<TokenResponse> {\n return this.http.post<TokenResponse>(this.manifest.auth!.login, { identifier, password });\n }\n\n refresh(refreshToken: string): Observable<TokenResponse> {\n return this.http.post<TokenResponse>(this.manifest.auth!.refresh, { refreshToken });\n }\n\n logout(): Observable<void> {\n return this.http.post<void>(this.manifest.auth!.logout, {});\n }\n\n me(): Observable<UserDto> {\n return this.http.get<UserDto>(this.manifest.auth!.me);\n }\n\n getSettings(): Observable<Record<string, Record<string, unknown>>> {\n // Force plain JSON. Angular's default Accept carries a wildcard, which\n // makes the backend prefer application/ld+json -- and the section keys\n // are then lost inside the Hydra member array.\n return this.http.get<Record<string, Record<string, unknown>>>(\n this.manifest.identity!.settingsUrl,\n { headers: { Accept: 'application/json' } },\n );\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Store } from '@ngxs/store';\nimport { type Observable } from 'rxjs';\n\nimport { AppConfigState } from '../state/app-config.state';\nimport type { ApiManifest } from './api-manifest.types';\n\n/**\n * Response of `POST /centrifugo/connection-token`: the JWT the realtime SDK\n * opens its socket with, and what it needs to refresh before expiry.\n */\nexport interface CentrifugoConnectionTokenDto {\n token: string;\n expiresAt: number;\n ttl: number;\n wsUrl: string;\n}\n\n/**\n * Response of `POST /centrifugo/subscription-token`: a per-channel JWT. The\n * SDK asks for one before subscribing to a private namespace, so this is\n * fetched per subscription rather than once per connection.\n */\nexport interface CentrifugoSubscriptionTokenDto {\n channel: string;\n token: string;\n expiresAt: number;\n ttl: number;\n}\n\n/**\n * The two realtime endpoints, carved out for the same reason the identity ones\n * were: the UI kit's realtime client needed exactly these two of `ApiService`'s\n * 117 methods, and depending on the whole thing would have pulled the entire\n * application's wire vocabulary underneath the kit.\n *\n * They belong in core rather than in the kit because both answers are derived\n * from things core already owns -- the boot manifest for the URL, and the auth\n * interceptor for the bearer token that authorises the request. A token is\n * session state, not a widget.\n *\n * `ApiService` keeps its identical signatures and delegates here, so nothing\n * calling it had to change.\n */\n@Injectable({ providedIn: 'root' })\nexport class RealtimeTokenClient {\n private readonly http = inject(HttpClient);\n private readonly store = inject(Store);\n\n private get manifest(): ApiManifest {\n const m = this.store.selectSnapshot(AppConfigState.manifest);\n if (!m) throw new Error('ApiManifest not loaded — call AppInitService.load() first');\n return m;\n }\n\n connectionToken(): Observable<CentrifugoConnectionTokenDto> {\n return this.http.post<CentrifugoConnectionTokenDto>(\n this.manifest.apiBase + '/centrifugo/connection-token', {});\n }\n\n subscriptionToken(channel: string): Observable<CentrifugoSubscriptionTokenDto> {\n return this.http.post<CentrifugoSubscriptionTokenDto>(\n this.manifest.apiBase + '/centrifugo/subscription-token', { channel });\n }\n}\n","import { type TokenResponse, type UserDto } from '../api/auth.types';\n\nexport class Login {\n static readonly type = '[Auth] Login';\n constructor(public identifier: string, public password: string) {}\n}\n\nexport class Logout {\n static readonly type = '[Auth] Logout';\n}\n\nexport class RestoreSession {\n static readonly type = '[Auth] Restore Session';\n}\n\nexport class SetTokens {\n static readonly type = '[Auth] Set Tokens';\n constructor(public readonly response: TokenResponse) {}\n}\n\n/** Merge a partial update into the currently-stored user (e.g. after avatar change). */\nexport class PatchCurrentUser {\n static readonly type = '[Auth] Patch Current User';\n constructor(public readonly patch: Partial<UserDto>) {}\n}\n","import { DestroyRef, inject, Injectable } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { HttpClient } from '@angular/common/http';\nimport { Store } from '@ngxs/store';\nimport { Subject, debounceTime } from 'rxjs';\nimport { AppConfigState } from '../state/app-config.state';\nimport { type DataGridPreference } from './user-preferences.types';\n\n/**\n * Unified user preferences service — all preference types share one\n * localStorage key (`coolms_ui_prefs`) and one debounced server-sync pipeline.\n *\n * Key naming convention (stored as nested objects, referenced via dot-notation):\n *\n * // Grids\n * grids.{gridId}.columns\n * grids.{gridId}.columnWidths\n *\n * // Panels (ExplorerLayout persistKey values from YAML)\n * panel.{persistKey}.width\n * panel.{persistKey}.collapsed\n *\n * // Page navigation state\n * page.vfs.lastPath\n * page.vfs.viewMode\n * page.media.lastDir\n * page.media.viewMode\n *\n * // Global\n * nav.lastRoute\n * terminal.height\n * terminal.open\n */\n@Injectable({ providedIn: 'root' })\nexport class UserPreferencesService {\n private readonly http = inject(HttpClient);\n private readonly store = inject(Store);\n private readonly destroyRef = inject(DestroyRef);\n\n private readonly STORAGE_KEY = 'coolms_ui_prefs';\n private readonly SYNC_DELAY = 2000; // ms\n\n private syncSubject = new Subject<Record<string, unknown>>();\n\n constructor() {\n // Debounced sync to server — batches rapid changes (e.g. live resize)\n this.syncSubject.pipe(\n debounceTime(this.SYNC_DELAY),\n takeUntilDestroyed(this.destroyRef),\n ).subscribe(prefs => this.syncToServer(prefs));\n }\n\n // -- Core helpers ---------------------------------------------------------\n\n /**\n * Write all prefs to localStorage and schedule a debounced server sync.\n */\n private save(all: Record<string, unknown>): void {\n localStorage.setItem(this.STORAGE_KEY, JSON.stringify(all));\n this.syncSubject.next(all);\n }\n\n /**\n * Read the entire prefs object from localStorage, applying legacy key\n * migration on the first read after an upgrade.\n */\n private load(): Record<string, unknown> {\n try {\n const raw = localStorage.getItem(this.STORAGE_KEY);\n const all: Record<string, unknown> = raw ? JSON.parse(raw) : {};\n return this.migrate(all);\n } catch {\n return {};\n }\n }\n\n /**\n * One-time migration of legacy flat keys to the new nested naming convention.\n * Mutates `all` in place and re-persists only when something changed.\n */\n private migrate(all: Record<string, unknown>): Record<string, unknown> {\n let dirty = false;\n\n // terminal_height -> terminal.height\n if (typeof all['terminal_height'] === 'number') {\n const terminal = (all['terminal'] ?? {}) as Record<string, unknown>;\n terminal['height'] = all['terminal_height'];\n all['terminal'] = terminal;\n delete all['terminal_height'];\n dirty = true;\n }\n\n // media_view_mode -> page.media.viewMode\n if (typeof all['media_view_mode'] === 'string') {\n const page = (all['page'] ?? {}) as Record<string, unknown>;\n const media = (page['media'] ?? {}) as Record<string, unknown>;\n media['viewMode'] = all['media_view_mode'];\n page['media'] = media;\n all['page'] = page;\n delete all['media_view_mode'];\n dirty = true;\n }\n\n // media_collections_panel -> panel.media_panel_left (matches persistKey in media-library.yaml)\n if (all['media_collections_panel'] && typeof all['media_collections_panel'] === 'object') {\n const panel = (all['panel'] ?? {}) as Record<string, unknown>;\n panel['media_panel_left'] = all['media_collections_panel'];\n all['panel'] = panel;\n delete all['media_collections_panel'];\n dirty = true;\n }\n\n // Normalize namespace arrays to empty objects.\n // The server serialises empty namespaces as [] (JSON array) rather than {}\n // because PHP converts empty associative arrays to JSON arrays. Arrays silently\n // swallow named-property writes and produce \"[]\" on serialisation, so column/\n // panel preferences would be lost. Convert once and re-persist.\n const NAMESPACES = new Set(['grids', 'panel', 'page', 'terminal', 'nav']);\n for (const ns of NAMESPACES) {\n if (Array.isArray(all[ns])) {\n all[ns] = {};\n dirty = true;\n }\n }\n\n // Grid keys: any top-level object with `columns` or `columnWidths` -> grids.{key}\n for (const key of Object.keys(all)) {\n if (NAMESPACES.has(key)) continue;\n const val = all[key];\n if (val && typeof val === 'object' && !Array.isArray(val)) {\n const obj = val as Record<string, unknown>;\n if ('columns' in obj || 'columnWidths' in obj) {\n const grids = (all['grids'] ?? {}) as Record<string, unknown>;\n grids[key] = obj;\n all['grids'] = grids;\n delete all[key];\n dirty = true;\n }\n }\n }\n\n if (dirty) {\n localStorage.setItem(this.STORAGE_KEY, JSON.stringify(all));\n }\n\n return all;\n }\n\n // -- Server sync ----------------------------------------------------------\n\n /**\n * Seed localStorage from server preferences.\n * Called after login and on every session restore (page reload).\n *\n * Strategy:\n * - No local prefs yet (new device / clean install) -> use server prefs as-is.\n * - Local prefs already exist -> merge with local taking priority at each\n * top-level namespace. This ensures that locally-persisted state\n * (panel widths, last path, etc.) is never overwritten by the stale copy\n * that was saved in the auth token at login time.\n */\n loadFromServer(uiPrefs: Record<string, unknown>): void {\n if (Object.keys(uiPrefs).length === 0) return;\n try {\n const raw = localStorage.getItem(this.STORAGE_KEY);\n if (!raw) {\n // Fresh device — trust the server entirely\n localStorage.setItem(this.STORAGE_KEY, JSON.stringify(uiPrefs));\n } else {\n // Local prefs exist — server is the base, local namespaces win\n const local = JSON.parse(raw) as Record<string, unknown>;\n const merged = { ...uiPrefs, ...local };\n localStorage.setItem(this.STORAGE_KEY, JSON.stringify(merged));\n }\n } catch {\n localStorage.setItem(this.STORAGE_KEY, JSON.stringify(uiPrefs));\n }\n }\n\n private syncToServer(prefs: Record<string, unknown>): void {\n const manifest = this.store.selectSnapshot(AppConfigState.manifest);\n const url = manifest?.auth?.preferencesUrl;\n if (!url) return;\n\n this.http.patch(url, { uiPrefs: prefs }, {\n headers: { 'Content-Type': 'application/merge-patch+json' },\n }).subscribe({\n error: err => console.warn('Preferences sync failed:', err),\n });\n }\n\n // -- Grids ----------------------------------------------------------------\n\n /**\n * Get stored preferences for a specific grid.\n */\n getGridPref(gridId: string): DataGridPreference | null {\n try {\n const all = this.load();\n const grids = all['grids'] as Record<string, unknown> | undefined;\n if (!grids) return null;\n return (grids[gridId] as DataGridPreference) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Set visible column order for a grid.\n * Applies to localStorage instantly; server sync is debounced.\n */\n setColumns(gridId: string, columns: string[]): void {\n this.updateGrid(gridId, existing => ({ ...existing, columns }));\n }\n\n /**\n * Record a column width for a grid column.\n * Applies to localStorage instantly; server sync is debounced.\n */\n setColumnWidth(gridId: string, field: string, width: number): void {\n this.updateGrid(gridId, existing => ({\n ...existing,\n columnWidths: {\n ...(existing.columnWidths ?? {}),\n [field]: Math.max(60, width),\n },\n }));\n }\n\n /**\n * Remove all preferences for a specific grid and immediately sync to server.\n */\n resetGrid(gridId: string): void {\n const all = this.load();\n const grids = (all['grids'] ?? {}) as Record<string, unknown>;\n delete grids[gridId];\n all['grids'] = grids;\n this.save(all);\n this.syncToServer(all); // immediate sync\n }\n\n private updateGrid(\n gridId: string,\n updater: (existing: DataGridPreference) => DataGridPreference,\n ): void {\n const all = this.load();\n const grids = (all['grids'] ?? {}) as Record<string, unknown>;\n grids[gridId] = updater((grids[gridId] as DataGridPreference) ?? {});\n all['grids'] = grids;\n this.save(all);\n }\n\n // -- Terminal -------------------------------------------------------------\n\n /**\n * Get persisted terminal panel height.\n */\n getTerminalHeight(): number | null {\n const all = this.load();\n const terminal = all['terminal'] as Record<string, unknown> | undefined;\n return typeof terminal?.['height'] === 'number' ? terminal['height'] : null;\n }\n\n /**\n * Persist terminal panel height.\n */\n setTerminalHeight(height: number): void {\n const all = this.load();\n const terminal = (all['terminal'] ?? {}) as Record<string, unknown>;\n terminal['height'] = Math.round(height);\n all['terminal'] = terminal;\n this.save(all);\n }\n\n // -- Panel ----------------------------------------------------------------\n\n /**\n * Get persisted state for a resizable panel identified by key.\n * Used by ExplorerLayoutComponent to persist panel widths across sessions.\n */\n getPanelState(key: string): { width: number; collapsed: boolean } | null {\n try {\n const all = this.load();\n const panel = all['panel'] as Record<string, unknown> | undefined;\n if (!panel) return null;\n const p = panel[key];\n if (!p || typeof p !== 'object') return null;\n const { width, collapsed } = p as Record<string, unknown>;\n return typeof width === 'number' && typeof collapsed === 'boolean'\n ? { width, collapsed }\n : null;\n } catch { return null; }\n }\n\n /**\n * Persist generic panel state by key.\n * Applies to localStorage instantly; server sync is debounced.\n */\n setPanelState(key: string, width: number, collapsed: boolean): void {\n const all = this.load();\n const panel = (all['panel'] ?? {}) as Record<string, unknown>;\n panel[key] = { width: Math.round(width), collapsed };\n all['panel'] = panel;\n this.save(all);\n }\n\n // -- Page state -----------------------------------------------------------\n\n /**\n * Get all persisted state for a page namespace (e.g. 'vfs', 'media', 'nav').\n */\n getPageState<T>(pageKey: string): T | null {\n try {\n const all = this.load();\n const page = all['page'] as Record<string, unknown> | undefined;\n if (!page) return null;\n return (page[pageKey] as T) ?? null;\n } catch { return null; }\n }\n\n /**\n * Merge partial state into a page namespace.\n * Existing keys in the namespace are preserved; only provided keys are updated.\n * Applies to localStorage instantly; server sync is debounced.\n */\n setPageState(pageKey: string, state: Record<string, unknown>): void {\n const all = this.load();\n const page = (all['page'] ?? {}) as Record<string, unknown>;\n page[pageKey] = { ...(page[pageKey] ?? {}), ...state };\n all['page'] = page;\n this.save(all);\n }\n\n // -- Media (legacy pass-through — kept for compatibility) -----------------\n\n /** @deprecated Use getPageState('media') instead */\n getMediaViewMode(): string | null {\n return this.getPageState<{ viewMode?: string }>('media')?.viewMode ?? null;\n }\n\n /** @deprecated Use setPageState('media', ...) instead */\n setMediaViewMode(mode: string): void {\n this.setPageState('media', { viewMode: mode });\n }\n\n /** @deprecated Use getPanelState('media_panel_left') instead */\n getMediaCollectionsPanel(): { width: number; collapsed: boolean } | null {\n return this.getPanelState('media_panel_left');\n }\n\n /** @deprecated Use setPanelState('media_panel_left', ...) instead */\n setMediaCollectionsPanel(width: number, collapsed: boolean): void {\n this.setPanelState('media_panel_left', width, collapsed);\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { State, Action, Selector } from '@ngxs/store';\nimport type { StateContext } from '@ngxs/store';\nimport { catchError, of } from 'rxjs';\nimport { switchMap, tap } from 'rxjs/operators';\nimport { IdentityApiClient } from '../api/identity-api.client';\nimport type { TokenResponse, UserDto } from '../api/auth.types';\nimport { Login, Logout, PatchCurrentUser, RestoreSession, SetTokens } from './auth.actions';\nimport { UserPreferencesService } from '../services/user-preferences.service';\n\nexport interface AuthStateModel {\n accessToken: string | null;\n refreshToken: string | null;\n expiresAt: string | null;\n user: UserDto | null;\n}\n\nconst STORAGE_KEY = 'coolms_token';\n\n@State<AuthStateModel>({\n name: 'auth',\n defaults: { accessToken: null, refreshToken: null, expiresAt: null, user: null },\n})\n@Injectable()\nexport class AuthState {\n // `inject()` rather than constructor parameters, and the imports above are\n // VALUE imports on purpose: an injected type must survive to runtime. As a\n // constructor parameter that is invisible to `tsc`, which type-checks a\n // type-only import happily and leaves the Angular compiler to fail with\n // NG2003. Read as a value here, so the same mistake is a type error.\n private readonly api = inject(IdentityApiClient);\n private readonly prefs = inject(UserPreferencesService);\n\n @Action(Login)\n login(ctx: StateContext<AuthStateModel>, { identifier, password }: Login) {\n return this.api.login(identifier, password).pipe(\n tap((res: TokenResponse) => {\n const state: AuthStateModel = {\n accessToken: res.accessToken,\n refreshToken: res.refreshToken,\n expiresAt: res.expiresAt,\n user: res.user ?? null,\n };\n ctx.setState(state);\n localStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n }),\n // Fetch full user data (includes uiPrefs) to seed preferences\n switchMap(() => this.api.me().pipe(catchError(() => of(null)))),\n tap(me => {\n if (!me) return;\n // Update stored user with full data including uiPrefs\n const updated = { ...ctx.getState(), user: me };\n ctx.setState(updated);\n localStorage.setItem(STORAGE_KEY, JSON.stringify(updated));\n if (me.uiPrefs) {\n this.prefs.loadFromServer(me.uiPrefs);\n }\n }),\n );\n }\n\n @Action(Logout)\n logout(ctx: StateContext<AuthStateModel>) {\n ctx.setState({ accessToken: null, refreshToken: null, expiresAt: null, user: null });\n localStorage.removeItem(STORAGE_KEY);\n }\n\n @Action(RestoreSession)\n restore(ctx: StateContext<AuthStateModel>) {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return;\n\n try {\n const state = JSON.parse(raw) as AuthStateModel;\n // Restore whenever any token is present.\n // If only the access token has expired but the refresh token is still\n // valid, the HTTP interceptor will transparently refresh on the next\n // request. Discarding state here would throw away the refresh token\n // and force a full re-login unnecessarily.\n if (state.accessToken || state.refreshToken) {\n ctx.setState(state);\n // Seed preferences from previously stored user (covers page-reload case)\n if (state.user?.uiPrefs) {\n this.prefs.loadFromServer(state.user.uiPrefs);\n }\n } else {\n localStorage.removeItem(STORAGE_KEY);\n }\n } catch {\n localStorage.removeItem(STORAGE_KEY);\n }\n }\n\n @Action(SetTokens)\n setTokens(ctx: StateContext<AuthStateModel>, { response }: SetTokens): void {\n const state: AuthStateModel = {\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n expiresAt: response.expiresAt,\n user: response.user ?? ctx.getState().user,\n };\n ctx.setState(state);\n localStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n }\n\n @Action(PatchCurrentUser)\n patchCurrentUser(ctx: StateContext<AuthStateModel>, { patch }: PatchCurrentUser): void {\n const current = ctx.getState();\n if (!current.user) return;\n const updated = { ...current, user: { ...current.user, ...patch } };\n ctx.setState(updated);\n localStorage.setItem(STORAGE_KEY, JSON.stringify(updated));\n }\n\n @Selector()\n static isAuthenticated(state: AuthStateModel): boolean {\n return null !== state.accessToken;\n }\n\n @Selector()\n static accessToken(state: AuthStateModel): string | null {\n return state.accessToken;\n }\n\n @Selector()\n static refreshToken(state: AuthStateModel): string | null {\n return state.refreshToken;\n }\n\n /**\n * Sub-phase Y -- expose the access-token expiry timestamp so\n * preemptive-refresh callers (e.g., Centrifuge getToken\n * callbacks) can decide whether to rotate before issuing the\n * next protected request, instead of relying on the\n * interceptor's reactive 401-retry path.\n */\n @Selector()\n static expiresAt(state: AuthStateModel): string | null {\n return state.expiresAt;\n }\n\n @Selector()\n static currentUser(state: AuthStateModel): UserDto | null {\n return state.user;\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { HttpErrorResponse } from '@angular/common/http';\nimport { Router } from '@angular/router';\nimport { Store } from '@ngxs/store';\nimport { type Observable, catchError, defer, finalize, firstValueFrom, from, shareReplay, throwError } from 'rxjs';\n\nimport { IdentityApiClient } from '../api/identity-api.client';\nimport { AuthState } from './auth.state';\nimport { Logout, SetTokens } from './auth.actions';\n\nconst LOCK_NAME = 'coolms_auth_refresh';\nconst FRESH_TOKEN_GRACE_MS = 30_000;\n\n/**\n * Two-layer refresh coordinator: an intra-tab `shareReplay(1)`\n * mutex dedupes concurrent callers within one tab, and a\n * cross-tab `navigator.locks` wrapper ensures only one tab in\n * the browser issues the actual `POST /auth/refresh` at a time.\n *\n * Without the cross-tab layer, two tabs racing the same expired\n * refresh-token both POST `/auth/refresh`; the backend's\n * `isUsed` replay branch revokes every token for the user on\n * the second arrival and the operator is kicked to /login.\n *\n * The Web Lock body re-reads the current access-token expiry from\n * `AuthState` before issuing the HTTP call. When this tab waited\n * behind another tab's refresh, that tab's `SetTokens` dispatch\n * has already published fresh values into shared `localStorage`,\n * `CrossTabAuthSyncService` has mirrored them into this tab's\n * NGXS state, and the lock body simply returns the cached access\n * token without another network round-trip.\n *\n * `Logout` fires only when the refresh endpoint returns 401\n * (real auth failure). Transient errors (network blips, 5xx,\n * CORS, timeouts) propagate without clearing the session so a\n * momentary refresh failure does not kill a valid login.\n */\n@Injectable({ providedIn: 'root' })\nexport class AuthRefreshCoordinator {\n private readonly api = inject(IdentityApiClient);\n private readonly store = inject(Store);\n private readonly router = inject(Router);\n\n private inFlight: Observable<string> | null = null;\n\n /**\n * Return the in-flight refresh Observable, or spawn a new one\n * with the supplied refresh-token value.\n *\n * Callers subscribe via `switchMap` / `firstValueFrom` to retry\n * their original request with the resolved access token.\n */\n refresh(refreshToken: string): Observable<string> {\n if (this.inFlight) {\n return this.inFlight;\n }\n this.inFlight = defer(() => this.refreshWithCrossTabLock(refreshToken)).pipe(\n catchError(refreshErr => {\n const isAuthFailure = refreshErr instanceof HttpErrorResponse && refreshErr.status === 401;\n if (isAuthFailure) {\n this.store.dispatch(new Logout());\n if (this.router.navigated) {\n void this.router.navigate(['/login']);\n }\n }\n return throwError(() => refreshErr);\n }),\n shareReplay(1),\n finalize(() => {\n this.inFlight = null;\n }),\n );\n return this.inFlight;\n }\n\n /**\n * Run the refresh body inside `navigator.locks` when the API is\n * available; degrade to direct invocation otherwise. The lock\n * body checks for state already updated by a sibling tab before\n * issuing its own HTTP call.\n */\n private refreshWithCrossTabLock(refreshToken: string): Observable<string> {\n const lockBody = (): Promise<string> => this.executeRefresh(refreshToken);\n\n if (typeof navigator === 'undefined' || !('locks' in navigator)) {\n return from(lockBody());\n }\n return from(\n navigator.locks.request(LOCK_NAME, lockBody).then(value => {\n if (value === undefined) {\n throw new Error('Refresh lock aborted before completing.');\n }\n return value;\n }),\n );\n }\n\n /**\n * Lock body. Re-reads `AuthState.expiresAt` first: if another\n * tab published fresh tokens while we were queued, return the\n * cached access token directly. Otherwise read the latest\n * refresh-token value from state (it may have rotated while we\n * waited) and issue the HTTP refresh.\n */\n private async executeRefresh(originalRefreshToken: string): Promise<string> {\n const cachedAccess = this.tryConsumeFreshState();\n if (cachedAccess !== null) {\n return cachedAccess;\n }\n const currentRefreshToken = this.store.selectSnapshot(AuthState.refreshToken) ?? originalRefreshToken;\n const response = await firstValueFrom(this.api.refresh(currentRefreshToken));\n this.store.dispatch(new SetTokens(response));\n return response.accessToken;\n }\n\n /**\n * Return the cached access token when `AuthState.expiresAt` has\n * more than `FRESH_TOKEN_GRACE_MS` milliseconds remaining --\n * signalling that some other tab refreshed for us. Null\n * otherwise.\n */\n private tryConsumeFreshState(): string | null {\n const accessToken = this.store.selectSnapshot(AuthState.accessToken);\n const expiresAtStr = this.store.selectSnapshot(AuthState.expiresAt);\n if (accessToken === null || expiresAtStr === null) {\n return null;\n }\n const expiresAtMs = new Date(expiresAtStr).getTime();\n if (Number.isNaN(expiresAtMs)) {\n return null;\n }\n if (Date.now() < expiresAtMs - FRESH_TOKEN_GRACE_MS) {\n return accessToken;\n }\n return null;\n }\n}\n","import { inject } from '@angular/core';\nimport {\n HttpContextToken, type HttpInterceptorFn,\n HttpErrorResponse,\n} from '@angular/common/http';\nimport { Store } from '@ngxs/store';\nimport { Router } from '@angular/router';\nimport { AuthState } from './auth.state';\nimport { Logout } from './auth.actions';\nimport { AuthRefreshCoordinator } from './auth-refresh.coordinator';\nimport { AppInitService } from '../bootstrap/app-init.service';\nimport { catchError, switchMap, take, throwError } from 'rxjs';\n\n// -- Opt-out context token -----------------------------------------------------\n//\n// Set BYPASS_AUTH to true on any HttpRequest to skip adding the Authorization\n// header entirely. Used by AppInitService for the bootstrap config request so\n// that a stale localStorage token does not cause a 401 on a public endpoint.\n\nexport const BYPASS_AUTH = new HttpContextToken<boolean>(() => false);\n\n// -----------------------------------------------------------------------------\n\nexport const authInterceptor: HttpInterceptorFn = (req, next) => {\n const store = inject(Store);\n const router = inject(Router);\n const coordinator = inject(AuthRefreshCoordinator);\n const initService = inject(AppInitService);\n\n // Caller explicitly requested no auth header (e.g. the bootstrap config\n // fetch — the endpoint is public and a stale token would cause 401).\n if (req.context.get(BYPASS_AUTH)) {\n return next(req);\n }\n\n // Auth endpoints are public by design. The backend's JWT firewall rejects any\n // request that carries an invalid/expired Bearer token — even on endpoints\n // that would otherwise allow anonymous access — so never forward a stored\n // token to login or refresh.\n if (req.url.includes('/auth/login') || req.url.includes('/auth/refresh')) {\n return next(req);\n }\n\n // Queue behind AppInitService.ready$ so that token restoration from\n // localStorage (RestoreSession) is guaranteed to be in NGXS state before\n // we read it. On F5 the interceptor fires synchronously for every pending\n // request before APP_INITIALIZER has completed; without this guard the\n // token snapshot is null and every request gets a 401 -> refresh cycle even\n // for a perfectly valid session.\n //\n // ready$ is a ReplaySubject(1) that completes after load() finishes, so:\n // - requests fired during init queue here and flush the moment ready$ emits;\n // - requests fired after init pass through take(1) immediately (replayed value).\n return initService.ready$.pipe(\n take(1),\n switchMap(() => {\n const token = store.selectSnapshot(AuthState.accessToken);\n const authed = token\n ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } })\n : req;\n\n return next(authed).pipe(\n catchError((err: unknown) => {\n if (!(err instanceof HttpErrorResponse) || err.status !== 401) {\n return throwError(() => err);\n }\n\n // Avoid infinite loop — skip refresh for auth endpoints themselves.\n if (req.url.includes('/auth/refresh') || req.url.includes('/auth/login')) {\n return throwError(() => err);\n }\n\n const refreshToken = store.selectSnapshot(AuthState.refreshToken);\n if (!refreshToken) {\n store.dispatch(new Logout());\n // Only navigate programmatically once the router has already\n // completed its initial navigation. During APP_INITIALIZER the\n // router is still blocked; authGuard handles the redirect there.\n if (router.navigated) void router.navigate(['/login']);\n return throwError(() => err);\n }\n\n // Delegate refresh to the shared coordinator so the\n // Centrifuge getToken path and the interceptor share ONE\n // in-flight refresh. Without this, two parallel\n // `api.refresh(refreshToken)` calls (one from each mutex)\n // would send the same refresh-token twice and trigger the\n // backend's `isUsed` replay branch on the second arrival,\n // wiping the whole session.\n return coordinator.refresh(refreshToken).pipe(\n switchMap(newToken =>\n next(req.clone({ setHeaders: { Authorization: `Bearer ${newToken}` } })),\n ),\n );\n }),\n );\n }),\n );\n};\n","import { Injectable, inject } from '@angular/core';\nimport { Store } from '@ngxs/store';\n\nimport type { AuthStateModel } from './auth.state';\nimport { Logout, SetTokens } from './auth.actions';\nimport type { TokenResponse } from '../api/auth.types';\n\nconst STORAGE_KEY = 'coolms_token';\n\n/**\n * Bridges shared `localStorage` mutations into the NGXS auth\n * state so a refresh executed in one tab silently propagates to\n * every other open tab.\n *\n * The browser fires `storage` events in tabs OTHER than the one\n * that mutated `localStorage`. So when Tab A's\n * `AuthRefreshCoordinator` rotates the token pair and `SetTokens`\n * persists the new values, every sibling tab receives an event\n * here and dispatches `SetTokens` against its own NGXS state --\n * no extra HTTP roundtrip, no extra refresh contention.\n *\n * Pairs with the `navigator.locks` cross-tab mutex in\n * `AuthRefreshCoordinator`: locks ensure only one tab issues the\n * refresh, this listener propagates the result to the rest.\n *\n * `Logout` from any tab clears `coolms_token` (newValue === null)\n * and this listener mirrors that into the sibling tabs so the\n * shell redirects to `/login` without waiting for the next\n * protected request to 401.\n *\n * Started from `AppInitService.load()` so the listener is in\n * place before any protected HTTP fires.\n */\n@Injectable({ providedIn: 'root' })\nexport class CrossTabAuthSyncService {\n private readonly store = inject(Store);\n private listenerAttached = false;\n\n start(): void {\n if (this.listenerAttached) {\n return;\n }\n this.listenerAttached = true;\n window.addEventListener('storage', this.handleStorageEvent);\n }\n\n private readonly handleStorageEvent = (event: StorageEvent): void => {\n if (event.key !== STORAGE_KEY) {\n return;\n }\n // Sibling tab cleared the key (logout dispatch or\n // RestoreSession parse-error cleanup). Mirror the clear so\n // this tab does not keep operating against a revoked\n // server-side session.\n if (event.newValue === null) {\n this.store.dispatch(new Logout());\n return;\n }\n // Parse the new value and dispatch SetTokens so this tab's\n // in-memory NGXS state reflects what the originating tab\n // just wrote. Malformed payloads are ignored.\n let parsed: AuthStateModel;\n try {\n parsed = JSON.parse(event.newValue) as AuthStateModel;\n } catch {\n return;\n }\n if (typeof parsed.accessToken !== 'string' || typeof parsed.refreshToken !== 'string' || typeof parsed.expiresAt !== 'string') {\n return;\n }\n const tokenResponse: TokenResponse = {\n accessToken: parsed.accessToken,\n refreshToken: parsed.refreshToken,\n expiresAt: parsed.expiresAt,\n user: parsed.user ?? undefined,\n };\n this.store.dispatch(new SetTokens(tokenResponse));\n };\n}\n","import { Injectable, inject } from '@angular/core';\nimport { Location } from '@angular/common';\nimport { HttpClient, HttpContext } from '@angular/common/http';\nimport { Router } from '@angular/router';\nimport { Store } from '@ngxs/store';\nimport { catchError, firstValueFrom, map, of, ReplaySubject, tap } from 'rxjs';\nimport { Logout, RestoreSession } from '../auth/auth.actions';\nimport { AuthState } from '../auth/auth.state';\nimport { BYPASS_AUTH } from '../auth/auth.interceptor';\nimport { AuthRefreshCoordinator } from '../auth/auth-refresh.coordinator';\nimport { CrossTabAuthSyncService } from '../auth/cross-tab-auth-sync.service';\nimport { SetAppConfig } from '../state/app-config.state';\nimport { type ThemeConfigResponse } from '../api/api-manifest.types';\nimport { UserPreferencesService } from '../services/user-preferences.service';\n\n@Injectable({ providedIn: 'root' })\nexport class AppInitService {\n // Injected as values, not constructor parameters: an injection token has to\n // exist at runtime, and a type-only import of one type-checks clean while\n // the Angular compiler rejects it with NG2003.\n private readonly http = inject(HttpClient);\n private readonly store = inject(Store);\n private readonly router = inject(Router);\n private readonly location = inject(Location);\n private readonly prefs = inject(UserPreferencesService);\n private readonly crossTabSync = inject(CrossTabAuthSyncService);\n private readonly refreshCoordinator = inject(AuthRefreshCoordinator);\n\n /** The only hardcoded URL — everything else comes from the manifest. */\n private readonly configUrl = '/api/v1/theme/config';\n\n /**\n * Emits (once) when load() has fully completed — tokens settled, manifest\n * set (or swallowed on error). authGuard subscribes to this so it never\n * evaluates isAuthenticated against a partially-restored stale token.\n */\n private readonly initComplete = new ReplaySubject<void>(1);\n readonly ready$ = this.initComplete.asObservable();\n\n async load(): Promise<void> {\n // -- Step 0: cross-tab sync --------------------------------------------\n //\n // Install the storage-event listener before RestoreSession so that\n // any localStorage mutation from a sibling tab during bootstrap\n // (e.g., a parallel tab refreshing tokens just as we load) is mirrored\n // into this tab's NGXS state.\n this.crossTabSync.start();\n\n // -- Step 1: restore tokens from localStorage --------------------------\n //\n // RestoreSession is synchronous (ctx.setState from localStorage), so\n // this await resolves in the same microtask. Tokens are in NGXS state\n // before ANY subsequent HTTP request fires — the auth interceptor reads\n // the token from state when attaching Authorization headers, so this\n // ordering prevents unauthenticated requests on page reload (F5).\n await firstValueFrom(this.store.dispatch(new RestoreSession()));\n\n // -- Step 2: fetch the manifest ----------------------------------------\n //\n // BYPASS_AUTH is required here — not optional. The manifest endpoint\n // is public, but two specific failure modes make bypassing necessary:\n //\n // a) The stored access token may be expired. Without BYPASS_AUTH the\n // interceptor attaches the expired token, gets a 401, and tries to\n // refresh. But the refresh endpoint URL comes from the manifest\n // (api.refresh() reads manifest.auth.refresh), which hasn't been\n // loaded yet — triggering a null-dereference crash before the app\n // can recover.\n //\n // b) Even if the token is valid, attaching it to a public endpoint\n // that ignores auth adds unnecessary coupling.\n //\n // Consequence: every page load issues one unauthenticated config\n // request, which is intentional. All subsequent API calls carry the\n // restored (or refreshed) token normally.\n const config = await firstValueFrom(\n this.http.get<ThemeConfigResponse>(this.configUrl, {\n context: new HttpContext().set(BYPASS_AUTH, true),\n }).pipe(\n tap(cfg => this.store.dispatch(new SetAppConfig(cfg))),\n catchError(() => {\n console.warn('CoolMS: theme/config unreachable, using safe defaults');\n return of(null);\n }),\n ),\n );\n\n // -- Step 3: validate the restored session -----------------------------\n //\n // RestoreSession trusts whatever tokens are in localStorage, but they may\n // have been revoked out-of-band — most notably, signing out on the public\n // SSR site revokes the user's WHOLE token set. We MUST settle the real\n // auth state here, BEFORE step 4 signals ready$: both the auth interceptor\n // AND authGuard gate on ready$, so if we signalled first, the guard would\n // race ahead and mount the shell against the stale isAuthenticated=true\n // before this probe finished (-> half-loaded shell + \"Session expired\"\n // toasts, the exact bug this fixes). Because the probe itself cannot wait\n // on ready$ (that would deadlock), validateSession() bypasses the\n // interceptor and attaches the token / drives the refresh by hand.\n const meUrl = config?.manifest.identity?.meUrl;\n if (meUrl && this.store.selectSnapshot(AuthState.isAuthenticated)) {\n await this.validateSession(meUrl);\n }\n\n // -- Step 4: signal authGuard + unblock the interceptor ----------------\n //\n // Auth state is now settled (session confirmed, refreshed, or Logout\n // dispatched). ReplaySubject(1) replays to guards/requests that subscribe\n // afterwards, so they evaluate against the final isAuthenticated value.\n this.initComplete.next();\n this.initComplete.complete();\n\n // -- Step 5: navigate to last-visited route ----------------------------\n //\n // Only when the session survived validation. If it did not, isAuthenticated\n // is now false, we skip the saved-route navigation, and authGuard sends the\n // initial navigation to /login.\n //\n // Only restore when the user opened the bare /admin root. An explicit\n // deep link (pasted /admin/sync-fleet, a bookmark, a shared URL) must\n // win over the saved route. The router cannot tell us which one this is:\n // withEnabledBlockingInitialNavigation holds the initial navigation until\n // this initializer resolves, so router.url is still '/'. The browser\n // location is the only record of what was requested — Location.path()\n // reads it with the /admin base href stripped, so the bare root (with or\n // without trailing slash) yields ''. Anything else, including a root URL\n // carrying query params, is treated as an explicit destination.\n if (this.store.selectSnapshot(AuthState.isAuthenticated)) {\n const requested = this.location.path();\n if (requested === '' || requested === '/') {\n const saved = this.prefs.getPageState<{ lastRoute?: string }>('nav');\n if (saved?.lastRoute && !saved.lastRoute.startsWith('/login')) {\n void this.router.navigateByUrl(saved.lastRoute);\n }\n }\n }\n }\n\n /**\n * Confirm the restored session is still alive, settling AuthState before the\n * app unblocks. Runs OUTSIDE the auth interceptor (BYPASS_AUTH) because the\n * interceptor queues behind ready$, which has not fired yet at this point.\n *\n * - access token accepted -> done, session alive;\n * - access token rejected -> attempt ONE refresh (access tokens are short-lived,\n * so an expired one with a valid refresh token must\n * stay logged in). The coordinator dispatches Logout\n * on a refresh 401 and SetTokens on success; a\n * transient failure (5xx/network) is swallowed so a\n * momentary blip never kills a valid session.\n */\n private async validateSession(meUrl: string): Promise<void> {\n const token = this.store.selectSnapshot(AuthState.accessToken);\n if (await this.probe(meUrl, token)) {\n return;\n }\n const refreshToken = this.store.selectSnapshot(AuthState.refreshToken);\n if (!refreshToken) {\n this.store.dispatch(new Logout());\n return;\n }\n let refreshedToken: string | null = null;\n try {\n refreshedToken = await firstValueFrom(this.refreshCoordinator.refresh(refreshToken));\n } catch {\n // 401 -> coordinator already dispatched Logout; transient -> session kept.\n return;\n }\n // Refresh resolved — but the coordinator's fresh-state optimisation can hand\n // back the SAME access token (without a network round-trip) when its stored\n // expiry still looks fresh. For a token that was revoked but not yet expired\n // (signing out on the SSR site while the access token is still in its TTL),\n // that token is dead despite looking fresh. Re-probe with whatever we now\n // hold; a second rejection means the session is genuinely gone.\n if (!(await this.probe(meUrl, refreshedToken))) {\n this.store.dispatch(new Logout());\n }\n }\n\n /** GET an authed endpoint with an explicit Bearer header, bypassing the interceptor. */\n private probe(url: string, token: string | null): Promise<boolean> {\n return firstValueFrom(\n this.http.get(url, {\n context: new HttpContext().set(BYPASS_AUTH, true),\n headers: token ? { Authorization: `Bearer ${token}` } : {},\n }).pipe(\n map(() => true),\n catchError(() => of(false)),\n ),\n );\n }\n}\n","import { inject } from '@angular/core';\nimport { type CanActivateFn, Router } from '@angular/router';\nimport { map, take } from 'rxjs';\nimport { Store } from '@ngxs/store';\nimport { AuthState } from './auth.state';\nimport { AppInitService } from '../bootstrap/app-init.service';\n\n/**\n * Protects routes that require authentication.\n *\n * The guard is intentionally ASYNC: it waits for AppInitService.ready$ before\n * evaluating auth state. Without this, Angular's router can evaluate\n * isAuthenticated while APP_INITIALIZER is still in-flight — RestoreSession\n * will have placed a non-null (but expired) token in state, causing the guard\n * to pass even though the subsequent config/refresh requests will fail and\n * dispatch Logout. Waiting for ready$ guarantees the auth state is settled.\n */\nexport const authGuard: CanActivateFn = () => {\n const init = inject(AppInitService);\n const store = inject(Store);\n const router = inject(Router);\n\n return init.ready$.pipe(\n take(1),\n map(() => {\n if (store.selectSnapshot(AuthState.isAuthenticated)) {\n return true;\n }\n return router.createUrlTree(['/login']);\n }),\n );\n};\n","import { inject } from '@angular/core';\nimport { type CanActivateFn, Router } from '@angular/router';\nimport { map, take } from 'rxjs';\nimport { Store } from '@ngxs/store';\nimport { AuthState } from './auth.state';\nimport { AppInitService } from '../bootstrap/app-init.service';\n\n/**\n * Guards the `/login` route -- redirects already-authenticated\n * callers to admin home so a stale tab parked on `/login` cannot\n * remain mounted while another tab is logged in. When Tab A logs\n * in fresh, Tab B's `RestoreSession` (driven by APP_INITIALIZER)\n * reads the new token from shared `localStorage` and populates\n * `AuthState`; this guard then sees `isAuthenticated === true`\n * and routes Tab B to `/`.\n *\n * Same `ready$` wait as `authGuard` -- ensures `RestoreSession`\n * has run before the snapshot is read; otherwise a fresh F5 on\n * `/login` with a valid stored session would briefly evaluate\n * as anonymous, allow `/login`, and only then have the token\n * populated.\n */\nexport const loginPageGuard: CanActivateFn = () => {\n const init = inject(AppInitService);\n const store = inject(Store);\n const router = inject(Router);\n\n return init.ready$.pipe(\n take(1),\n map(() => {\n if (store.selectSnapshot(AuthState.isAuthenticated)) {\n return router.createUrlTree(['/']);\n }\n return true;\n }),\n );\n};\n","import { Component, inject } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { NgIf } from '@angular/common';\nimport { Router } from '@angular/router';\nimport { Store } from '@ngxs/store';\nimport { Login } from '../auth.actions';\n\n@Component({\n selector: 'coolms-admin-login',\n standalone: true,\n imports: [FormsModule, NgIf],\n templateUrl: './login.component.html',\n})\nexport class LoginComponent {\n identifier = '';\n password = '';\n loading = false;\n error: string | null = null;\n\n private readonly store = inject(Store);\n private readonly router = inject(Router);\n\n submit(): void {\n if (!this.identifier || !this.password) return;\n\n this.loading = true;\n this.error = null;\n\n this.store.dispatch(new Login(this.identifier, this.password)).subscribe({\n next: () => {\n // A rejected navigation used to vanish: nothing resets `loading`\n // on the success path, because the page is expected to go\n // away. If it does not, the form spins for ever with no reason\n // given, so say so instead.\n void this.router.navigate(['/']).catch(() => {\n this.loading = false;\n this.error = 'Signed in, but the admin could not be opened. Please reload.';\n });\n },\n error: (err) => {\n this.loading = false;\n this.error = err?.error?.detail ?? err?.error?.message ?? err?.message ?? 'Invalid credentials. Please try again.';\n },\n });\n }\n}\n","<div class=\"d-flex align-items-center justify-content-center min-vh-100 bg-light\">\n <div class=\"card shadow-sm\" style=\"width: 360px\">\n <div class=\"card-body p-4\">\n <h1 class=\"h5 mb-1\">CoolMS Admin</h1>\n <p class=\"text-muted small mb-4\">Sign in to continue</p>\n\n <div *ngIf=\"error\" class=\"alert alert-danger py-2 small\">{{ error }}</div>\n\n <form (ngSubmit)=\"submit()\" #loginForm=\"ngForm\">\n <div class=\"mb-3\">\n <label class=\"form-label\">Email or username</label>\n <input\n type=\"text\"\n class=\"form-control\"\n [(ngModel)]=\"identifier\"\n name=\"identifier\"\n required\n autocomplete=\"username\"\n />\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label\">Password</label>\n <input\n type=\"password\"\n class=\"form-control\"\n [(ngModel)]=\"password\"\n name=\"password\"\n required\n autocomplete=\"current-password\"\n />\n </div>\n <button\n type=\"submit\"\n class=\"cms-btn cms-btn-primary w-100 justify-content-center\"\n [disabled]=\"loading || loginForm.invalid\"\n >\n {{ loading ? 'Signing in…' : 'Sign in' }}\n </button>\n </form>\n </div>\n </div>\n</div>\n","import { inject, Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Store } from '@ngxs/store';\nimport { map, type Observable, shareReplay } from 'rxjs';\nimport { AppConfigState } from '../state/app-config.state';\n\n/**\n * Layout config DTO -- the shape served from\n * `GET /api/v1/config/layout/{id}`. Mirrors the YAML at\n * `config/modules/{module}/layout/*.yaml`.\n *\n * The optional fields below are the page-level contract\n * every admin SPA page resolves through. The base contract (id /\n * template / title / icon / slots) is the legacy list shape and stays\n * untouched. Existing 17 list YAMLs render identically when the new\n * fields are absent.\n *\n * New optional fields:\n * - `subtitle` one-line page description rendered under the title\n * - `sections` ordered map of body sections, each with its own slot graph\n * (replaces single-slot `slots:` for multi-section pages)\n * - `headerActions` buttons displayed in the cms-page-header action bar\n * - `permissions` hint for clients about who this page targets; real gating\n * lives on the data APIs the slot components consume\n * (the layout endpoint itself is public by design --\n * layouts carry only structure, never data)\n *\n * `[key: string]: unknown` index signature stays so existing per-page\n * keys (e.g. `media:library`'s `naviGraph:` slot shorthand) keep working\n * without further interface changes.\n */\nexport interface LayoutHeaderAction {\n id: string;\n label?: string;\n icon?: string;\n title?: string;\n primary?: boolean;\n danger?: boolean;\n disabled?: boolean;\n /**\n * Optional capability gate evaluated FE-side against runtime state\n * (e.g. `administer` / `delete`) — the config declares WHICH actions\n * exist + their gate; the FE decides if THIS user/row qualifies. Absent\n * = always shown. Used by detail pages whose actions are config-driven\n * (see `web:section-detail`).\n *\n * For a gate that depends on the RECORD rather than the user, prefer\n * `showWhen` below: `requires` needs a page to interpret the token, so\n * every new value costs a branch in TypeScript.\n */\n requires?: string;\n /**\n * Conditions on the page's published context, same grammar and same\n * evaluator as a NaviGraph toolbar node, applied\n * by {@link LayoutActionsService}:\n *\n * showWhen — the action does not APPLY, so it is absent.\n * disabledWhen — temporarily UNAVAILABLE: stays put and greys out.\n * busyWhen — the action is RUNNING: greys out too, and may relabel.\n * busyLabel — label shown while `busyWhen` holds (\"Saving…\").\n * activeWhen — pressed/active styling.\n *\n * Two carriers (a layout config and a NaviGraph tree) but ONE vocabulary:\n * a page that moves between them should not have to relearn how to say\n * \"not now\".\n */\n showWhen?: Record<string, unknown>;\n disabledWhen?: Record<string, unknown>;\n busyWhen?: Record<string, unknown>;\n busyLabel?: string;\n activeWhen?: Record<string, unknown>;\n}\n\nexport interface LayoutSection {\n title?: string;\n /**\n * When true, the layout shell pins the section to the top of the\n * scroll container (CSS `position: sticky`). Used by inspector /\n * filter pages where an input form should stay visible while the\n * operator scrolls through results below. Currently honoured by\n * cms-inspector-layout; cms-detail-layout will follow when it\n * lands. Default false.\n */\n sticky?: boolean;\n slots?: Record<string, { component?: string; [key: string]: unknown }>;\n [key: string]: unknown;\n}\n\nexport interface LayoutConfig {\n id?: string;\n template?: string;\n title?: string;\n subtitle?: string;\n icon?: string;\n slots?: Record<string, unknown>;\n sections?: Record<string, LayoutSection>;\n headerActions?: LayoutHeaderAction[];\n /**\n * Actions rendered in the page's fixed bottom bar (`<cms-detail-footer>`)\n * — primary / destructive actions kept out of the cramped header.\n * Same shape as `headerActions`; gated per-item via `requires`.\n */\n footerActions?: LayoutHeaderAction[];\n permissions?: string[];\n [key: string]: unknown;\n}\nexport interface DialogConfig { [key: string]: unknown; }\nexport interface NavigraphConfig { [key: string]: unknown; }\nexport interface FormConfig { [key: string]: unknown; }\nexport interface DatagridConfig { [key: string]: unknown; }\n\n/**\n * Fetches config YAMLs (served as JSON) from GET /api/v1/config/{type}/{id}.\n *\n * Responses are cached for the lifetime of the service (Map + shareReplay(1))\n * so repeated calls never re-fetch the same resource.\n *\n * configBase is read from the API manifest (manifest.configBase) and falls\n * back to '/api/v1/config' when the manifest is not yet loaded.\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfigService {\n private readonly http = inject(HttpClient);\n private readonly store = inject(Store);\n private readonly cache = new Map<string, Observable<unknown>>();\n\n layout(id: string): Observable<LayoutConfig> { return this.fetch<LayoutConfig>('layout', id); }\n dialog(id: string): Observable<DialogConfig> { return this.fetch<DialogConfig>('dialog', id); }\n navigraph(slug: string): Observable<NavigraphConfig> { return this.fetch<NavigraphConfig>('navigraph', slug); }\n form(id: string): Observable<FormConfig> { return this.fetch<FormConfig>('form', id); }\n datagrid(id: string): Observable<DatagridConfig> { return this.fetch<DatagridConfig>('datagrid', id); }\n\n private fetch<T>(type: string, id: string): Observable<T> {\n const key = `${type}/${id}`;\n\n if (!this.cache.has(key)) {\n const base = this.store.selectSnapshot(AppConfigState.manifest)?.configBase\n ?? '/api/v1/config';\n // The config endpoint wraps the YAML payload in a `data` field:\n // { type, id, data: { ...yaml content... } }\n // Unwrap so callers always receive the config payload directly.\n const obs = this.http.get<{ data?: T } & T>(`${base}/${type}/${id}`).pipe(\n map(r => (r.data ?? r) as T),\n shareReplay(1),\n );\n this.cache.set(key, obs);\n }\n\n return this.cache.get(key) as Observable<T>;\n }\n}\n","import { Injectable } from '@angular/core';\nimport { HttpErrorResponse } from '@angular/common/http';\n\n/**\n * Converts any caught error into a human-readable message.\n *\n * Priority order for backend errors:\n * 1. error.detail (RFC 7807 problem detail)\n * 2. error['hydra:description'] (Hydra validation errors)\n * 3. error.message (generic)\n * 4. error.violations[] (constraint violations)\n * 5. Status-based fallback\n */\n@Injectable({ providedIn: 'root' })\nexport class ErrorHandlerService {\n humanize(err: unknown): string {\n if (!(err instanceof HttpErrorResponse)) {\n return err instanceof Error ? err.message : 'An unexpected error occurred.';\n }\n\n const body = err.error as Record<string, unknown> | null;\n if (body && typeof body === 'object') {\n const detail = body['detail'] ?? body['hydra:description'] ?? body['message'];\n if (typeof detail === 'string' && detail.trim()) {\n return detail.trim();\n }\n\n if (Array.isArray(body['violations'])) {\n const msgs = (body['violations'] as Array<{ message: string }>)\n .map(v => v.message)\n .filter(Boolean);\n if (msgs.length) return msgs.join(' ');\n }\n }\n\n return this.statusMessage(err.status);\n }\n\n private statusMessage(status: number): string {\n switch (status) {\n case 0: return 'Network error. Check your connection.';\n case 400: return 'Invalid request.';\n case 401: return 'Session expired. Please sign in again.';\n case 403: return 'Access denied.';\n case 404: return 'Resource not found.';\n case 409: return 'Conflict — resource already exists.';\n case 422: return 'Validation failed.';\n case 429: return 'Too many requests. Please wait a moment.';\n case 500: return 'Server error. Please try again later.';\n case 503: return 'Service unavailable. Please try again later.';\n default: return `Unexpected error (${status}).`;\n }\n }\n}\n","import { computed, effect, inject, Injectable, signal } from '@angular/core';\nimport { type Observable, of } from 'rxjs';\nimport { catchError, map, shareReplay, tap } from 'rxjs/operators';\nimport { Store } from '@ngxs/store';\n\nimport { IdentityApiClient } from '../api/identity-api.client';\nimport { AppConfigState } from '../state/app-config.state';\n\n/** What the user PICKED. `system` defers to the OS. */\nexport type ThemeChoice = 'light' | 'dark' | 'system';\n\n/** What that resolves to right now — the only two the stylesheet knows. */\nexport type ResolvedTheme = 'light' | 'dark';\n\nconst CHOICES: readonly ThemeChoice[] = ['light', 'dark', 'system'];\n\n/**\n * A CACHE, never a source of truth.\n *\n * The authoritative value is `preferences.theme` in `/auth/me/settings`, which\n * the Profile -> Preferences tab already writes. This copy exists only so the\n * first paint of a reload is the right colour: the settings request is async,\n * so without it every load would start light and flip. It is deliberately NOT\n * stored via UserPreferencesService, which syncs its own bag to the server —\n * that would give one setting two server-side homes.\n */\nconst CACHE_KEY = 'coolms_theme';\nconst ACCENT_CACHE_KEY = 'coolms_accent';\n\n/**\n * Six-digit hex only, checked again HERE even though the server already vets it\n * on write. This value is substituted into a `--cms-*` custom property,\n * and a stored setting is data from the network like any other — the write-side\n * guard protects what the admin stores, this one protects what it renders.\n */\nconst HEX = /^#[0-9a-fA-F]{6}$/;\n\nfunction isChoice(v: unknown): v is ThemeChoice {\n return typeof v === 'string' && (CHOICES as readonly string[]).includes(v);\n}\n\nfunction isAccent(v: unknown): v is string {\n return typeof v === 'string' && HEX.test(v);\n}\n\n/**\n * Applies the user's theme by setting `data-theme` on the document element.\n *\n * The stylesheet does the rest: `:root[data-theme='dark']` re-points the\n * `--cms-*` palette and every colour in the admin arrives through those names.\n * Nothing here knows a single colour, which is the point — a second\n * theme is a block of tokens, not a code change.\n *\n * Follows the shape of UserCalendarPreferencesService and\n * CallOverlayPreferencesService: lazy one-shot load of `/auth/me/settings`,\n * cached for the SPA lifetime, with `update()` called by the Profile page after\n * a save so the change lands without a refetch.\n */\n@Injectable({ providedIn: 'root' })\nexport class ThemeService {\n private readonly api = inject(IdentityApiClient);\n private readonly store = inject(Store);\n\n private readonly _choice = signal<ThemeChoice>(ThemeService.readCache());\n private readonly _systemDark = signal(false);\n private readonly _userAccent = signal<string | null>(ThemeService.readAccentCache());\n private readonly _platformAccent = signal<string | null>(null);\n\n private loadOnce$?: Observable<ThemeChoice>;\n\n /** The user's stored choice, including `system`. */\n readonly choice = this._choice.asReadonly();\n\n /** This user's personal override, independent of the deployment's. */\n readonly userAccent = this._userAccent.asReadonly();\n\n /** The deployment's brand accent from the API manifest, if it set one. */\n readonly platformAccent = this._platformAccent.asReadonly();\n\n /**\n * The colour actually painted: personal override, else the deployment's,\n * else null — which leaves the stylesheet's own accent in place.\n *\n * Three rungs and each is a real state. A user who has chosen nothing is\n * NOT the same as one who chose the deployment's colour: clear the\n * deployment's brand and the first user follows it, the second does not.\n */\n readonly accent = computed<string | null>(() => this._userAccent() ?? this._platformAccent());\n\n /** The choice with `system` resolved against the OS setting. */\n readonly resolved = computed<ResolvedTheme>(() => {\n const c = this._choice();\n\n return c === 'system' ? (this._systemDark() ? 'dark' : 'light') : c;\n });\n\n constructor() {\n // `matchMedia` is guarded because the unit suite and any SSR-ish\n // rendering path may not provide it; absent it, `system` means light.\n const mq = typeof window !== 'undefined' && window.matchMedia\n ? window.matchMedia('(prefers-color-scheme: dark)')\n : null;\n\n if (mq) {\n this._systemDark.set(mq.matches);\n // The OS can flip while the SPA is open, and `system` must follow it\n // live rather than only at load.\n mq.addEventListener('change', e => this._systemDark.set(e.matches));\n }\n\n effect(() => this.applyToDocument(this.resolved()));\n effect(() => this.applyAccent(this.accent()));\n }\n\n /**\n * One-shot load of the stored preference. Safe to call more than once and\n * safe for anonymous users — a failure leaves the cached/system value in\n * place rather than forcing light, so the login screen still matches the OS.\n */\n ensureLoaded(): Observable<ThemeChoice> {\n if (this.loadOnce$) return this.loadOnce$;\n\n // Read the deployment's colour FIRST and synchronously, so it is in\n // place whether or not the settings request succeeds — an anonymous\n // visitor on the login screen still sees the deployment's brand.\n this.readPlatformAccent();\n\n this.loadOnce$ = this.api.getSettings().pipe(\n map(all => {\n const prefs = all['preferences'] as Record<string, unknown> | undefined;\n // The accent rides along on the same response — it is a field of\n // the same section, so it costs no extra request.\n this.setAccent(isAccent(prefs?.['accentColor']) ? prefs['accentColor'] : null);\n\n return isChoice(prefs?.['theme']) ? prefs['theme'] : this._choice();\n }),\n tap(choice => this.set(choice)),\n catchError(() => of(this._choice())),\n shareReplay({ bufferSize: 1, refCount: false }),\n );\n\n return this.loadOnce$;\n }\n\n /**\n * Called by the Profile page after the Preferences tab saves, so the admin\n * re-themes on the spot. Ignores anything that is not a known choice —\n * the section PATCH returns the whole merged bag, not just this field.\n */\n update(value: unknown): void {\n if (isChoice(value)) this.set(value);\n }\n\n /**\n * Companion to {@link update} for the accent field of the same save.\n * An explicit null clears the override; anything malformed is ignored\n * rather than applied, so a bad value can never blank the admin's accent.\n */\n updateAccent(value: unknown): void {\n if (null === value || '' === value) this.setAccent(null);\n else if (isAccent(value)) this.setAccent(value);\n }\n\n private set(choice: ThemeChoice): void {\n this._choice.set(choice);\n try {\n localStorage.setItem(CACHE_KEY, choice);\n } catch {\n // A blocked or full localStorage costs the pre-paint hint, nothing\n // more — the server value still arrives and applies.\n }\n }\n\n /**\n * The manifest is loaded at bootstrap, well before the authenticated shell\n * calls this, so a snapshot read is enough and no subscription is needed.\n * A malformed value is ignored rather than applied — the container refuses\n * to build with one, but the manifest crosses the network all the same.\n */\n private readPlatformAccent(): void {\n const value = this.store.selectSnapshot(AppConfigState.manifest)?.platformDefaults?.accentColor;\n this._platformAccent.set(isAccent(value) ? value : null);\n }\n\n private setAccent(accent: string | null): void {\n this._userAccent.set(accent);\n try {\n if (accent) localStorage.setItem(ACCENT_CACHE_KEY, accent);\n else localStorage.removeItem(ACCENT_CACHE_KEY);\n } catch {\n // Same as the theme cache: losing it costs the pre-paint hint only.\n }\n }\n\n /**\n * Writes the override onto the document element, where an inline style\n * outranks every stylesheet rule — including the dark block — so one\n * declaration re-points the accent in both themes.\n *\n * Only --cms-accent is set, not the -hover/-light/-text members of the\n * family. Deriving those from an arbitrary user colour needs a colour model\n * the palette does not have yet, and guessing them would produce hover\n * states that clash with the very colour the user chose. Until then the\n * override moves the brand fill and leaves its supporting tones alone.\n */\n private applyAccent(accent: string | null): void {\n const root = document.documentElement;\n if (accent && HEX.test(accent)) root.style.setProperty('--cms-accent', accent);\n else root.style.removeProperty('--cms-accent');\n }\n\n private applyToDocument(theme: ResolvedTheme): void {\n // Written for BOTH values rather than only removing the attribute for\n // light, so the attribute is a reliable signal for anything that wants\n // to read the active theme, and so a future `[data-theme='light']`\n // block has something to hang on.\n document.documentElement.setAttribute('data-theme', theme);\n }\n\n private static readCache(): ThemeChoice {\n try {\n const raw = localStorage.getItem(CACHE_KEY);\n\n return isChoice(raw) ? raw : 'system';\n } catch {\n return 'system';\n }\n }\n\n private static readAccentCache(): string | null {\n try {\n const raw = localStorage.getItem(ACCENT_CACHE_KEY);\n\n return isAccent(raw) ? raw : null;\n } catch {\n return null;\n }\n }\n}\n","import { ChangeDetectionStrategy, Component, input } from '@angular/core';\n\n/**\n * The platform's loading indicator: the exclamation mark from Cool!MS,\n * drawing itself.\n *\n * ## Why a mark and not a spinner\n *\n * A spinner says \"something is happening\" and nothing else; every product has\n * one and none of them are yours. The bang is already the one glyph in the\n * wordmark that carries the brand, so a loader built from it says whose\n * software is thinking — for free, in the place a user is already looking.\n *\n * ## Why one component rather than a snippet per surface\n *\n * It is meant for every wait long enough to notice: a dashboard assembling its\n * cards, an editor paginating a document, an explorer listing a folder. Those\n * are different teams' files, and a copied SVG in each is how three loaders\n * that no longer match each other happen.\n *\n * ## The animation\n *\n * The stem wipes upward and the dot lands after it, on a loop — the shape being\n * WRITTEN rather than spun. It is deliberately calm: a loader is background\n * furniture, and anything with a hard beat gets irritating on the third viewing.\n * Under `prefers-reduced-motion` it holds still and only breathes, because\n * motion sickness is not a stylistic preference.\n */\n@Component({\n selector: 'cms-loader',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"cms-loader\"\n [class.cms-loader--overlay]=\"overlay()\"\n [class.cms-loader--inline]=\"inline()\"\n role=\"status\"\n [attr.aria-label]=\"label() || 'Loading'\">\n <svg class=\"cms-loader__mark\" viewBox=\"0 0 24 48\" aria-hidden=\"true\">\n <defs>\n <clipPath [attr.id]=\"clipId\">\n <rect class=\"cms-loader__wipe\" x=\"0\" y=\"0\" width=\"24\" height=\"34\" />\n </clipPath>\n </defs>\n <!-- Ghost beneath: the mark stays legible as a SHAPE while the\n wipe crosses it, so the loader never looks broken mid-cycle. -->\n <rect class=\"cms-loader__ghost\" x=\"8\" y=\"2\" width=\"8\" height=\"30\" rx=\"4\" />\n <circle class=\"cms-loader__ghost\" cx=\"12\" cy=\"42\" r=\"4\" />\n\n <rect class=\"cms-loader__stem\" x=\"8\" y=\"2\" width=\"8\" height=\"30\" rx=\"4\"\n [attr.clip-path]=\"'url(#' + clipId + ')'\" />\n <circle class=\"cms-loader__dot\" cx=\"12\" cy=\"42\" r=\"4\" />\n </svg>\n @if (label()) {\n <span class=\"cms-loader__label\">{{ label() }}</span>\n }\n </div>\n `,\n styles: [`\n .cms-loader {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n padding: 24px;\n color: var(--cms-text-muted);\n }\n /* Fills whatever it is dropped into and paints the surface behind it,\n which is what makes it usable as a COVER for content that is not\n ready to be seen rather than only as a placeholder in empty space. */\n .cms-loader--overlay {\n position: absolute;\n inset: 0;\n z-index: 5;\n background: var(--cms-surface);\n }\n /* Inline: the mark sits BESIDE its label at text scale, for the waits\n that happen inside a row, a status bar or a button rather than in an\n empty panel. Same mark, so a page does not switch identities between\n its big wait and its small one. */\n .cms-loader--inline {\n flex-direction: row;\n gap: 8px;\n padding: 0;\n }\n .cms-loader--inline .cms-loader__mark {\n width: var(--cms-loader-size, 14px);\n }\n .cms-loader__mark {\n width: var(--cms-loader-size, 40px);\n height: auto;\n overflow: visible;\n }\n .cms-loader__ghost {\n fill: var(--cms-border);\n }\n .cms-loader__stem, .cms-loader__dot {\n fill: var(--cms-accent);\n }\n .cms-loader__wipe {\n animation: cms-loader-wipe 1.6s cubic-bezier(.65, 0, .35, 1) infinite;\n transform-origin: 12px 32px;\n }\n .cms-loader__dot {\n animation: cms-loader-dot 1.6s cubic-bezier(.65, 0, .35, 1) infinite;\n transform-origin: 12px 42px;\n }\n /* The stem is written from the base up: scaled about its own foot, so\n it grows out of the baseline instead of sliding into place. */\n @keyframes cms-loader-wipe {\n 0% { transform: scaleY(0); }\n 45%, 70% { transform: scaleY(1); }\n 100% { transform: scaleY(0); }\n }\n /* The dot lands after the stem has finished, then leaves with it. */\n @keyframes cms-loader-dot {\n 0%, 40% { opacity: 0; transform: scale(.4); }\n 55%, 70% { opacity: 1; transform: scale(1); }\n 100% { opacity: 0; transform: scale(.4); }\n }\n .cms-loader__label {\n font-size: .8125rem;\n }\n /* Motion sickness is not a stylistic preference: the mark holds its\n shape and only breathes. */\n @media (prefers-reduced-motion: reduce) {\n .cms-loader__wipe { animation: none; transform: scaleY(1); }\n .cms-loader__dot { animation: cms-loader-breathe 2s ease-in-out infinite; opacity: 1; }\n }\n @keyframes cms-loader-breathe {\n 0%, 100% { opacity: .35; }\n 50% { opacity: 1; }\n }\n `],\n})\nexport class CmsLoaderComponent {\n /** Optional caption. Absent renders the mark alone, which suits a small inline wait. */\n readonly label = input<string>('');\n\n /** Cover the positioned ancestor rather than sitting in the flow. */\n readonly overlay = input<boolean>(false);\n\n /**\n * Row layout at text scale, for a wait inside a row, a status bar or a\n * button. Override `--cms-loader-size` to tune the mark.\n */\n readonly inline = input<boolean>(false);\n\n /**\n * A clip-path needs a document-unique id, and this component is used more\n * than once per page — two loaders sharing an id makes the second one clip\n * against the first one's rectangle and stop animating.\n */\n protected readonly clipId = 'cms-loader-' + Math.random().toString(36).slice(2, 9);\n}\n","import { Injectable, signal } from '@angular/core';\n\n/**\n * Sidebar collapse state -- two independent dimensions:\n *\n * - `collapsed`: whole-sidebar icon-only rail toggle (the chevron at\n * the bottom of the sidebar). Per-device localStorage.\n * - `collapsedSections`: per-section collapse, keyed by the section\n * separator's node id. Used to fold a section's items under their\n * header so the nav doesn't endless-scroll once a tenant has lots\n * of modules. Per-device localStorage.\n * - `collapsedItems`: per-item inline-expand collapse, keyed by the\n * nav node's id. Mirrors `collapsedSections` but for sub-tree items\n * (a top-level item with children, e.g. Reports -> Process Report).\n * Absent id = expanded (children visible); present = collapsed.\n * Per-device localStorage.\n *\n * Storage failures (private mode, quota, disabled cookies) fall back\n * to defaulting un-collapsed -- the toggles still work for the session,\n * just don't persist.\n */\n@Injectable({ providedIn: 'root' })\nexport class SidebarStateService {\n private static readonly STORAGE_KEY = 'coolms.admin.sidebar.collapsed';\n private static readonly STORAGE_KEY_SECTIONS = 'coolms.admin.sidebar.collapsedSections';\n private static readonly STORAGE_KEY_ITEMS = 'coolms.admin.sidebar.collapsedItems';\n\n readonly collapsed = signal<boolean>(this.readPersisted());\n readonly collapsedSections = signal<Set<string>>(this.readSectionsPersisted());\n readonly collapsedItems = signal<Set<string>>(this.readItemsPersisted());\n\n toggle(): void {\n const next = !this.collapsed();\n this.collapsed.set(next);\n this.persist(next);\n }\n\n isSectionCollapsed(id: string): boolean {\n return this.collapsedSections().has(id);\n }\n\n toggleSection(id: string): void {\n const next = new Set(this.collapsedSections());\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n this.collapsedSections.set(next);\n this.persistSections(next);\n }\n\n /**\n * Force a section to be expanded. Used when navigation lands on\n * a route inside a manually-collapsed section -- it would be\n * confusing to leave the active item hidden. The user can\n * collapse the section again afterwards.\n */\n ensureExpanded(id: string): void {\n if (!this.collapsedSections().has(id)) return;\n const next = new Set(this.collapsedSections());\n next.delete(id);\n this.collapsedSections.set(next);\n this.persistSections(next);\n }\n\n // --- Per-item inline-expand (sub-tree items, e.g. a section's children) --\n\n isItemCollapsed(id: string): boolean {\n return this.collapsedItems().has(id);\n }\n\n toggleItem(id: string): void {\n const next = new Set(this.collapsedItems());\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n this.collapsedItems.set(next);\n this.persistItems(next);\n }\n\n private readPersisted(): boolean {\n try {\n return localStorage.getItem(SidebarStateService.STORAGE_KEY) === 'true';\n } catch {\n return false;\n }\n }\n\n private persist(value: boolean): void {\n try {\n localStorage.setItem(SidebarStateService.STORAGE_KEY, String(value));\n } catch {\n // Non-persistence acceptable; toggle still works in-session.\n }\n }\n\n private readSectionsPersisted(): Set<string> {\n try {\n const raw = localStorage.getItem(SidebarStateService.STORAGE_KEY_SECTIONS);\n if (raw === null) return new Set();\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return new Set();\n return new Set(parsed.filter((v): v is string => typeof v === 'string'));\n } catch {\n return new Set();\n }\n }\n\n private persistSections(value: Set<string>): void {\n try {\n localStorage.setItem(\n SidebarStateService.STORAGE_KEY_SECTIONS,\n JSON.stringify(Array.from(value)),\n );\n } catch {\n // Non-persistence acceptable; toggle still works in-session.\n }\n }\n\n private readItemsPersisted(): Set<string> {\n try {\n const raw = localStorage.getItem(SidebarStateService.STORAGE_KEY_ITEMS);\n if (raw === null) return new Set();\n const parsed: unknown = JSON.parse(raw);\n if (!Array.isArray(parsed)) return new Set();\n return new Set(parsed.filter((v): v is string => typeof v === 'string'));\n } catch {\n return new Set();\n }\n }\n\n private persistItems(value: Set<string>): void {\n try {\n localStorage.setItem(\n SidebarStateService.STORAGE_KEY_ITEMS,\n JSON.stringify(Array.from(value)),\n );\n } catch {\n // Non-persistence acceptable; toggle still works in-session.\n }\n }\n}\n","import { HttpClient, HttpParams } from '@angular/common/http';\nimport { Injectable, inject } from '@angular/core';\nimport { type Observable } from 'rxjs';\n\n/**\n * One row returned by the `/api/entity-search` endpoint. `id` is\n * what the picker emits via its `valueChange` output (and what the\n * template's persisted context carries). `label` is the primary\n * display line. `secondary` is an optional second line for\n * disambiguation (email, slug, etc.) — the backend omits the key\n * when there is nothing to show; receiving `null` from a custom\n * resolver is normalized to `undefined` here.\n */\nexport interface EntitySearchResult {\n readonly id: string | number;\n readonly label: string;\n readonly secondary?: string;\n}\n\n/**\n * HTTP client for the Phase 2a `/api/entity-search` endpoint.\n * Returns a stream of search results for the given entity FQCN.\n * Permission filtering happens at the backend resolver layer —\n * this service is a thin RPC.\n */\n@Injectable({ providedIn: 'root' })\nexport class EntitySearchService {\n private readonly http = inject(HttpClient);\n\n /**\n * @param entityType Fully-qualified PHP class name of the entity\n * being searched (e.g. the backend's User entity).\n * @param query Free-text search input. Empty string is\n * valid — the backend returns the default\n * listing for that entity type.\n * @param limit Max rows to return; clamped server-side to\n * [1, 100].\n */\n search(entityType: string, query: string, limit = 20): Observable<EntitySearchResult[]> {\n const params = new HttpParams()\n .set('type', entityType)\n .set('q', query)\n .set('limit', String(limit));\n\n return this.http.get<EntitySearchResult[]>('/api/entity-search', { params });\n }\n}\n","import { inject, Injectable, signal } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { Router } from '@angular/router';\nimport { Store } from '@ngxs/store';\nimport { catchError, map, type Observable, of } from 'rxjs';\nimport { Logout } from '../auth/auth.actions';\nimport { type NaviGraphNode, type NaviGraphNodeFlat } from './navi-graph.types';\nimport { ErrorHandlerService } from '../errors/error-handler.service';\n\n/**\n * Loads, caches, and drives admin NaviGraph trees.\n *\n * Usage:\n * naviGraphService.loadAdminNav(url).subscribe();\n * const items = naviGraphService.adminNav(); // signal<NaviGraphNode[]>\n * naviGraphService.handleClick(node);\n */\n@Injectable({ providedIn: 'root' })\nexport class NaviGraphService {\n private readonly http = inject(HttpClient);\n private readonly router = inject(Router);\n private readonly store = inject(Store);\n private readonly errors = inject(ErrorHandlerService);\n\n /** Resolved root nodes for navi.admin (sidebar). */\n readonly adminNav = signal<NaviGraphNode[]>([]);\n\n /** Resolved root nodes for navi.admin.topbar. */\n readonly topbarNav = signal<NaviGraphNode[]>([]);\n\n private readonly cache = new Map<string, NaviGraphNode[]>();\n\n // -------------------------------------------------------------------------\n\n loadAdminNav(url: string): Observable<NaviGraphNode[]> {\n return this.loadTree(url).pipe(\n map(tree => { this.adminNav.set(tree); return tree; }),\n );\n }\n\n loadTopbarNav(url: string): Observable<NaviGraphNode[]> {\n return this.loadTree(url).pipe(\n map(tree => { this.topbarNav.set(tree); return tree; }),\n );\n }\n\n // -------------------------------------------------------------------------\n\n /**\n * Handle a nav-node click.\n *\n * Routing logic based on meta.target:\n * 'action.logout' — dispatch Logout\n * '_blank' — window.open (uses node.path as href)\n * default — router.navigate with meta.routerLink or node.path\n */\n handleClick(node: NaviGraphNode): void {\n const target = node.meta.target;\n\n if (target === 'action.logout') {\n this.store.dispatch(new Logout()).subscribe(() => {\n void this.router.navigate(['/login']);\n });\n return;\n }\n\n if (target === '_blank') {\n window.open(node.meta.routerLink ?? node.path, '_blank', 'noopener');\n return;\n }\n\n const link = node.meta.routerLink ?? node.path;\n void this.router.navigate([link]);\n }\n\n // -------------------------------------------------------------------------\n\n /**\n * Evaluate `showWhen` meta condition against a record.\n * Nodes with no `showWhen` are always visible.\n * Supports nested AND/OR logic: { and: [...] } / { or: [...] }\n */\n isVisible(node: NaviGraphNode, record: Record<string, unknown>): boolean {\n const showWhen = node.meta['showWhen'] as Record<string, unknown> | undefined;\n if (!showWhen) return true;\n return this.evalCondition(showWhen, record);\n }\n\n /**\n * Standalone `showWhen` evaluator for callers that don't have a\n * full `NaviGraphNode` (e.g. a grid's row context menu — a\n * `rowAction.showWhen` predicate is evaluated against the row's\n * own projection). `null`/`undefined` predicates default to\n * visible, mirroring `isVisible`'s \"no rule = always shown\"\n * semantics.\n */\n matchesShowWhen(showWhen: Record<string, unknown> | undefined | null, record: Record<string, unknown>): boolean {\n if (!showWhen) return true;\n return this.evalCondition(showWhen, record);\n }\n\n private evalCondition(cond: Record<string, unknown>, record: Record<string, unknown>): boolean {\n if ('and' in cond) {\n return (cond['and'] as Record<string, unknown>[])\n .every(c => this.evalCondition(c, record));\n }\n if ('or' in cond) {\n return (cond['or'] as Record<string, unknown>[])\n .some(c => this.evalCondition(c, record));\n }\n // Strict missing-field semantics. A leaf predicate\n // referencing a field absent from the record evaluates to\n // false (fail-loud) instead of the prior op-dependent lax\n // behavior that returned true for ne/nin/unknown ops. Aligns\n // with CSS attribute selectors / JSONPath / React conditional\n // rendering conventions.\n const field = cond['field'] as string;\n if (!(field in record)) return false;\n const val = record[field];\n switch (cond['op']) {\n case 'eq': return val === cond['value'];\n case 'ne': return val !== cond['value'];\n case 'in': return Array.isArray(cond['value']) && (cond['value'] as unknown[]).includes(val);\n case 'nin': return Array.isArray(cond['value']) && !(cond['value'] as unknown[]).includes(val);\n // Prefix match for strings — primary use case is filtering\n // actions by MIME-type major (e.g., \"image/\" matches all\n // image MIMEs without enumerating each subtype).\n case 'startsWith':\n return typeof val === 'string'\n && typeof cond['value'] === 'string'\n && val.startsWith(cond['value']);\n // Strict: unknown / typo op (e.g. 'equals' instead of 'eq')\n // never matches.\n default: return false;\n }\n }\n\n /**\n * Fetch a graph endpoint and return a nested tree.\n * Handles both compact JSON-LD IRIs (`member`) and\n * the legacy Hydra key (`hydra:member`).\n * Results are cached by URL for the lifetime of the service instance.\n */\n loadTree(url: string): Observable<NaviGraphNode[]> {\n if (this.cache.has(url)) {\n return of(this.cache.get(url)!);\n }\n\n return this.http.get<Record<string, unknown>>(url, {\n headers: { Accept: 'application/ld+json' },\n }).pipe(\n map(r => {\n const raw = r['member'] ?? r['hydra:member'] ?? [];\n const flat: NaviGraphNodeFlat[] = Array.isArray(raw) ? raw as NaviGraphNodeFlat[] : [];\n const tree = this.buildTree(flat);\n this.cache.set(url, tree);\n return tree;\n }),\n catchError(err => {\n console.error('[NaviGraph] loadTree failed for', url, this.errors.humanize(err));\n return of([]);\n }),\n );\n }\n\n /**\n * Build a nested tree from a flat array of nodes.\n * Nodes are sorted by sortOrder at each level.\n */\n private buildTree(flat: NaviGraphNodeFlat[]): NaviGraphNode[] {\n if (!flat.length) {\n return [];\n }\n\n const map = new Map<string, NaviGraphNode>(\n flat.map(n => [n.id, { ...n, children: [] }]),\n );\n const roots: NaviGraphNode[] = [];\n\n for (const node of map.values()) {\n if (node.parentId && map.has(node.parentId)) {\n map.get(node.parentId)!.children.push(node);\n } else {\n roots.push(node);\n }\n }\n\n const sort = (nodes: NaviGraphNode[]): void => {\n nodes.sort((a, b) => a.sortOrder - b.sortOrder);\n nodes.forEach(n => n.children?.length && sort(n.children));\n };\n sort(roots);\n\n return roots;\n }\n}\n","// --- NaviGraph API types ------------------------------------------------------\n// Mirror the PHP NaviGraphNodeResource DTO exactly. No `any` allowed.\n\n/**\n * Well-known click target values embedded in meta.target.\n * 'action.logout' — dispatch Logout action\n * 'route' — navigate via routerLink (default when target absent)\n * '_blank' — open in a new tab (hrefOverride must be set)\n */\n// `& {}` rather than a bare `| string`, which absorbs the three literals and\n// leaves the type meaning \"any string\" -- the docblock above would then be\n// describing a union the compiler had already erased.\nexport type NaviGraphTarget = 'action.logout' | 'route' | '_blank' | (string & {});\n\nexport interface NaviGraphMeta {\n readonly component?: string; // e.g. 'identity.signout'\n readonly icon?: string; // icon name hint for the renderer\n readonly routerLink?: string; // Angular router path, e.g. 'navi'\n readonly target?: NaviGraphTarget; // click behaviour override\n readonly requiredRole?: string; // backend-side role guard\n readonly voterAttribute?: string; // PHP-side Voter guard\n readonly contributor?: string; // set by NaviGraphSeeder (read-only)\n readonly [key: string]: unknown;\n}\n\n/** Flat node as returned from GET /navi/trees/{slug}/graph */\nexport interface NaviGraphNodeFlat {\n readonly id: string;\n readonly path: string;\n readonly title: string;\n readonly parentId: string | null;\n readonly sortOrder: number;\n readonly isActive: boolean;\n readonly isVisible: boolean;\n readonly meta: NaviGraphMeta;\n}\n\n/** Same node enriched with resolved children after client-side tree build */\nexport interface NaviGraphNode extends NaviGraphNodeFlat {\n readonly children: NaviGraphNode[];\n}\n","import { Injectable, type Type } from '@angular/core';\n\n/**\n * Registry mapping string keys to Angular component classes.\n *\n * Backed by a static Map so components registered at module load time\n * (e.g. in app.config.ts) are visible to all injected instances.\n *\n * Usage — static (app.config.ts / bootstrap time):\n * ComponentRegistry.register('MediaLibraryPage', MediaLibraryPage);\n *\n * Usage — injected (SlotComponent / runtime):\n * private readonly registry = inject(ComponentRegistry);\n * const cls = this.registry.get('MediaLibraryPage');\n */\n@Injectable({ providedIn: 'root' })\nexport class ComponentRegistry {\n private static readonly map = new Map<string, Type<unknown>>();\n\n // -- Static API (bootstrap / app.config.ts) -------------------------------\n\n static register(key: string, component: Type<unknown>): void {\n ComponentRegistry.map.set(key, component);\n }\n\n static get(key: string): Type<unknown> | undefined {\n return ComponentRegistry.map.get(key);\n }\n\n static has(key: string): boolean {\n return ComponentRegistry.map.has(key);\n }\n\n static keys(): string[] {\n return Array.from(ComponentRegistry.map.keys());\n }\n\n // -- Instance API (injectable) ---------------------------------------------\n\n register(key: string, component: Type<unknown>): void {\n ComponentRegistry.register(key, component);\n }\n\n get(key: string): Type<unknown> | null {\n return ComponentRegistry.get(key) ?? null;\n }\n\n has(key: string): boolean {\n return ComponentRegistry.has(key);\n }\n\n keys(): string[] {\n return ComponentRegistry.keys();\n }\n}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * The one fact the section interceptor needs: which site the operator is\n * currently working in.\n *\n * `core` is auth, config, errors and interceptors -- the layer everything else\n * is built on -- so it must not import a feature. The obvious-looking fix,\n * moving `SectionState` into core, is the wrong one: sections are a CMS domain\n * concept, and hoisting domain state into the base layer trades one bad\n * direction for another. So core declares the little it needs and the module\n * that owns the state provides it, bound in the composition root.\n *\n * Read SYNCHRONOUSLY on purpose. An interceptor decides whether to stamp a\n * header while building the request; it cannot wait on a stream.\n */\nexport interface CurrentSectionPort {\n /** Slug of the active section, or null when the operator picked none. */\n currentSlug(): string | null;\n}\n\n/**\n * Optional by design: an application assembled without a Sections module binds\n * nothing and simply sends no `X-CoolMS-Section` header, which is exactly what\n * a single-site install wants.\n */\nexport const CURRENT_SECTION = new InjectionToken<CurrentSectionPort>(\n 'coolms.current-section',\n);\n","import { inject } from '@angular/core';\nimport { type HttpInterceptorFn } from '@angular/common/http';\nimport { CURRENT_SECTION } from '../section/current-section.port';\n\n/**\n * Phase H7 -- admin Site Selector.\n *\n * Stamps `X-CoolMS-Section: <slug>` on outgoing `/api/v1/*` requests when\n * the admin has picked a section from the Site Selector dropdown. The backend\n * honours it for AUTHENTICATED requests only -- anonymous traffic cannot pivot\n * the active section.\n *\n * What the header actually reaches, counted rather than intended: exactly two\n * readers act on it, `CreatePageProcessor` and `CreateCollectionProcessor`,\n * each choosing WHICH SITE a newly created page or collection lands in -- and,\n * for a page, that section's default locale and slug-naming policy. Nothing\n * else is scoped by it. Media spaces list every active section regardless, and\n * every other reader of `_coolms_section` sits on the public SSR surface,\n * which resolves from host+path and never sees this header.\n *\n * This block used to say the backend \"scopes site-specific API providers\n * (pages, media spaces, etc.)\". That described where was heading --\n * H4/H5, multisite Document and Media, never landed -- not what it does. Left\n * recorded because a docstring naming an intended destination reads exactly\n * like one naming a shipped feature, and this one misdescribed the control for\n * three months.\n *\n * Skipped:\n * - non-API URLs (no section context needed for SSR/static)\n * - `/auth/*` endpoints (login/refresh are pre-session; the header would\n * be ignored by the backend anyway, but skipping keeps wire traffic clean)\n * - requests that already carry the header (programmatic overrides win)\n */\nexport const sectionInterceptor: HttpInterceptorFn = (req, next) => {\n if (!shouldStamp(req.url)) {\n return next(req);\n }\n if (req.headers.has('X-CoolMS-Section')) {\n return next(req);\n }\n\n // Optional: no Sections module installed means no section to stamp.\n const slug = inject(CURRENT_SECTION, { optional: true })?.currentSlug() ?? null;\n if (!slug) return next(req);\n\n return next(req.clone({ setHeaders: { 'X-CoolMS-Section': slug } }));\n};\n\nfunction shouldStamp(url: string): boolean {\n // Strip protocol/host so absolute and relative URLs are treated alike.\n const path = url.replace(/^https?:\\/\\/[^/]+/, '');\n if (!path.startsWith('/api/v1/')) return false;\n if (path.startsWith('/api/v1/auth/')) return false;\n return true;\n}\n","/**\n * `@coolms/core-angular` -- the CoolMS client runtime for Angular.\n *\n * Everything a CoolMS front-end needs before it has any UI: the session and its\n * refresh/cross-tab machinery, the boot manifest and app config, theme and user\n * preferences, error handling, the HTTP interceptors, and the wire types the\n * backend's form-render and navi-graph endpoints emit.\n *\n * It is deliberately NOT \"the admin's core\": nothing here is admin chrome. It is\n * also not a general Angular library -- every endpoint it speaks is a CoolMS\n * one, so it is worthless without a CoolMS backend. The layering is\n *\n * @coolms/core-angular -> @coolms/admin-ui-angular -> @coolms/x-ui-angular\n *\n * and the reason it must be a package rather than app code is federation: the\n * kit and every remote need this at runtime as ONE `singleton`, and a remote\n * cannot import from its host.\n *\n * This barrel is the whole public surface. Nothing outside `core/` may deep-link\n * past it -- eslint enforces that, so this file is what \"core exports\" MEANS. A\n * symbol not listed here is internal, and adding one is a deliberate act.\n *\n * The single component (`LoginComponent`) is here on purpose: core owns the auth\n * lifecycle, so it ships a working sign-in rather than leaving every consumer to\n * rebuild one against endpoints only core knows.\n */\n\n// -- Wire types + the API client core owns ------------------------------------\nexport * from './api/api-manifest.types';\nexport * from './api/auth.types';\nexport * from './api/form-render.types';\nexport * from './api/hydra.types';\nexport * from './api/identity-api.client';\nexport * from './api/realtime-token.client';\n\n// -- Session ------------------------------------------------------------------\nexport * from './auth/auth.actions';\nexport * from './auth/auth.state';\nexport * from './auth/auth.guard';\nexport * from './auth/login-page.guard';\nexport * from './auth/auth.interceptor';\nexport * from './auth/auth-refresh.coordinator';\nexport * from './auth/cross-tab-auth-sync.service';\nexport * from './auth/login/login.component';\n\n// -- Boot + configuration -----------------------------------------------------\nexport * from './bootstrap/app-init.service';\nexport * from './config/config.service';\nexport * from './state/app-config.state';\n\n// -- Cross-cutting services ---------------------------------------------------\nexport * from './errors/error-handler.service';\nexport * from './theme/theme.service';\n// The platform's loader mark. It lives here rather than in the UI kit\n// because the kit is not the lowest layer that needs it: the editor sits\n// ABOVE the kit and still has to show it, and a second copy of a brand\n// mark is worse than a component in a runtime package.\nexport * from './loader/cms-loader.component';\nexport * from './services/user-preferences.service';\nexport * from './services/user-preferences.types';\nexport * from './sidebar/sidebar-state.service';\nexport * from './entity-search/entity-search.service';\n\n// -- Navigation graph ---------------------------------------------------------\nexport * from './navi-graph/navi-graph.service';\nexport * from './navi-graph/navi-graph.types';\nexport * from './navi-graph/component-registry';\n\n// -- Section scoping ----------------------------------------------------------\n// The interceptor stamps `X-CoolMS-Section`; the port is how the app tells it\n// which section is active without core naming a feature.\nexport * from './interceptors/section.interceptor';\nexport * from './section/current-section.port';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["STORAGE_KEY","switchMap","tap","map","catchError","shareReplay"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@coolms/core-angular",
|
|
3
|
+
"version": "2.0.0-alpha.2",
|
|
4
|
+
"description": "The CoolMS client runtime for Angular: session and token refresh, boot manifest and app configuration, theme, user preferences, error handling, HTTP interceptors, and the wire types the CoolMS API emits.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Dmitry Popov",
|
|
8
|
+
"email": "d.popov@coolms.com"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"@angular/common": "^22.0.0",
|
|
13
|
+
"@angular/core": "^22.0.0",
|
|
14
|
+
"@angular/forms": "^22.0.0",
|
|
15
|
+
"@angular/router": "^22.0.0",
|
|
16
|
+
"@ngxs/store": "^22.0.0",
|
|
17
|
+
"rxjs": "^7.8.0"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": "^22.22.3 || ^24.15.0 || >=26"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"coolms",
|
|
24
|
+
"angular",
|
|
25
|
+
"cms",
|
|
26
|
+
"client",
|
|
27
|
+
"runtime"
|
|
28
|
+
],
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/coolms/core-angular.git"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"module": "fesm2022/coolms-core-angular.mjs",
|
|
37
|
+
"typings": "types/coolms-core-angular.d.ts",
|
|
38
|
+
"exports": {
|
|
39
|
+
"./package.json": {
|
|
40
|
+
"default": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
".": {
|
|
43
|
+
"types": "./types/coolms-core-angular.d.ts",
|
|
44
|
+
"default": "./fesm2022/coolms-core-angular.mjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"sideEffects": false,
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"tslib": "^2.3.0"
|
|
50
|
+
}
|
|
51
|
+
}
|