import type { InheritableApproval } from "../src/kernel/approval.ts"; import type { Capability } from "../src/kernel/resolve.ts"; import type { ApprovalOutcome } from "./approvals.ts"; export interface ChainApprovalAudit { sources: Map; scopes: Map; expiresAt: Map; uses: Map; } export function newChainApprovalAudit(): ChainApprovalAudit { return { sources: new Map(), scopes: new Map(), expiresAt: new Map(), uses: new Map() }; } export function rememberChainApproval( audit: ChainApprovalAudit, capability: Capability, subject: string, outcome: ApprovalOutcome, ): void { const key = `${capability}@${subject}`; const source = outcome.sources[capability]; const scope = outcome.recordedScopes[capability]; if (source) audit.sources.set(key, source); if (scope) audit.scopes.set(key, scope); const expiresAt = outcome.expiresAt[capability]; if (expiresAt) audit.expiresAt.set(key, expiresAt); const uses = outcome.uses[capability]; if (uses) audit.uses.set(key, uses); } export function chainApprovalFacts( audit: ChainApprovalAudit, available: InheritableApproval[], subject: string, ): Pick { const entries = available.filter((approval) => approval.subject === subject); const values = (map: Map) => Object.fromEntries( entries.flatMap((approval) => { const value = map.get(`${approval.capability}@${approval.subject}`); return value === undefined ? [] : [[approval.capability, value]]; }), ); return { approved: entries.map((approval) => approval.capability), sources: values(audit.sources), scopes: values(audit.scopes), expiresAt: values(audit.expiresAt), uses: values(audit.uses), humanDenied: false, }; }