import { Injectable, inject } from '@angular/core'; import { Result, ok, err } from '@shared/kernel/fp'; import { ApiClient } from '@shared/infrastructure/api-client'; import type { AuthzAuditDto } from '@shared/infrastructure/api-client'; import { AuditEntry } from '@beheer/domain/audit-entry'; /** * Infrastructure adapter for the admin authz/PII-reveal audit trail (`GET /admin/audit`, * WP-41). The single place the ApiClient lives for audit; the store parses at the boundary. */ @Injectable({ providedIn: 'root' }) export class AuditAdapter { private client = inject(ApiClient); list(): Promise { return this.client.audit(); } } /** Trust-boundary parse of the audit rows. */ export function parseAuditEntries(json: unknown): Result { if (!Array.isArray(json)) return err('audit: not an array'); const out: AuditEntry[] = []; for (const item of json) { if (typeof item !== 'object' || item === null) return err('audit: row not an object'); const d = item as AuthzAuditDto; if ( typeof d.at !== 'string' || typeof d.action !== 'string' || typeof d.resource !== 'string' || typeof d.role !== 'string' || typeof d.correlationId !== 'string' ) return err('audit: missing fields'); out.push({ at: d.at, action: d.action, resource: d.resource, decision: d.decision === 'allow' ? 'allow' : 'deny', role: d.role, correlationId: d.correlationId, }); } return ok(out); }