export type DomainAccessStage = 'checking' | 'login-required' | 'identity-verified' | 'runtime-ready'; export interface VerifiedDomainRuntimePolicyProjection { allowedSessionScopes: readonly string[]; forbiddenDataScopes: readonly string[]; manifestDigest: string; permissionPolicyRef: string; routeRef: string; themeOwner: 'domain-team' | 'fifth-domain'; themePackageRef: string; } export interface DomainAccessProjection { blockers: string[]; domainId?: string; nodeId?: string; nodeType?: 'local-terminal' | 'cloud-resident'; runtimePolicy?: VerifiedDomainRuntimePolicyProjection; runtimeReady: boolean; stage: DomainAccessStage; trustSource?: { reason?: 'ANCHOR_INVALID' | 'REGISTRY_INVALID' | 'SOURCE_UNAVAILABLE'; registryVersion: string | null; signerCount: number; sourceCommit: string | null; status: 'CURRENT' | 'DEGRADED_LAST_KNOWN_GOOD' | 'UNAVAILABLE'; }; } export interface DomainConnectionStep { id: 'identity' | 'manifest' | 'capability' | 'receipt'; label: string; state: 'checking' | 'blocked' | 'verified'; detail: string; } export interface DomainRuntimePolicyReceiptRow { label: string; value: string; } const blockerToStep: Record = { account_identity_missing: 'identity', verified_node_registration_missing: 'identity', verified_domain_manifest_missing: 'manifest', scoped_session_capability_missing: 'capability', matching_connection_receipt_missing: 'receipt', desktop_runtime_required: 'identity', domain_access_probe_failed: 'identity', }; const stepCopy: Record = { identity: { label: '账户与登记节点', pending: '需要由已登记的本地终端节点或云常驻节点完成身份证明', verified: '账户声明和节点编号已经验证', }, manifest: { label: '目标域签名清单', pending: '等待目标域可信签名人签发并验证域 manifest', verified: '目标域 manifest 与可信签名来源一致', }, capability: { label: '域会话能力', pending: '等待签发仅允许进入当前域的短期会话能力', verified: '当前节点持有有效的 domain:enter 能力', }, receipt: { label: '在线连接回执', pending: '等待目标域运行体返回与节点、清单一致的在线回执', verified: '连接回执已回读并与当前会话一致', }, }; export function projectDomainConnectionSteps(access: DomainAccessProjection): DomainConnectionStep[] { const blockers = new Set(access.blockers.map(blocker => blockerToStep[blocker]).filter(Boolean)); const ordered: DomainConnectionStep['id'][] = ['identity', 'manifest', 'capability', 'receipt']; return ordered.map(id => { const copy = stepCopy[id]; const verified = access.runtimeReady || (!blockers.has(id) && access.stage !== 'checking'); let detail = verified ? copy.verified : copy.pending; if (!verified && id === 'manifest' && access.trustSource) { if (access.trustSource.status === 'UNAVAILABLE') { detail = '当前无法回读灯塔的可信签名人登记表;系统保持关闭,不使用缓存猜测域权限'; } else if (access.trustSource.status === 'DEGRADED_LAST_KNOWN_GOOD') { detail = '当前只能回读上一次可信签名人快照;实时来源恢复前不签发新的域权限'; } else if (access.trustSource.signerCount === 0) { detail = '灯塔登记表已回读为当前版本,但尚未登记任何目标域签名人'; } } return { id, label: copy.label, state: access.stage === 'checking' ? 'checking' : verified ? 'verified' : 'blocked', detail: access.stage === 'checking' ? '正在核对当前接入证据' : detail, }; }); } export function projectDomainTrustSource(access: DomainAccessProjection): string { const source = access.trustSource; if (!source) return '可信清单来源尚未由桌面运行时回读'; if (source.status === 'UNAVAILABLE') return '可信清单来源不可用 · 域入口保持关闭'; const commit = source.sourceCommit ? source.sourceCommit.slice(0, 8) : '未知提交'; const version = source.registryVersion ?? '未知版本'; const health = source.status === 'CURRENT' ? '当前' : '上次可信快照'; return `可信清单 ${health} · v${version} · ${commit} · 已登记签名人 ${source.signerCount}`; } export function projectDomainRuntimePolicyReceipt(access: DomainAccessProjection): DomainRuntimePolicyReceiptRow[] { const policy = access.runtimeReady ? access.runtimePolicy : undefined; if (!policy) return []; return [ { label: '主题包', value: policy.themePackageRef }, { label: '运行路线', value: policy.routeRef }, { label: '权限策略', value: policy.permissionPolicyRef }, { label: '允许会话', value: policy.allowedSessionScopes.join(' · ') }, { label: '禁止数据', value: policy.forbiddenDataScopes.join(' · ') }, { label: '清单摘要', value: `${policy.manifestDigest.slice(0, 12)}…${policy.manifestDigest.slice(-8)}` }, ]; }