export type DomainNodeType = 'LOCAL_TERMINAL_NODE' | 'CLOUD_RESIDENT_NODE' export type PublicDomainStatus = 'PUBLIC_PREVIEW' | 'RESTRICTED_PREVIEW' | 'UNAVAILABLE' export interface PublicThemePreview { assetRef: string description: string } export interface PublicDomainVestibule { accessModes: DomainNodeType[] displayName: string domainId: string formalName: string publicStatus: PublicDomainStatus purpose: string responsibleParty: string themePreview: PublicThemePreview | null } export interface DomainManifestProvenance { digest: string repositoryId: string signature: string signerId: string sourceCommit: string } export interface DomainRuntimeDescriptor { backendVersion: string channelIds: string[] forbiddenDataScopes: string[] frontendVersion: string healthCheckRef: string moduleIds: string[] rollbackVersion: string routeRef: string themePackageRef: string } export interface VerifiedDomainManifest { public: PublicDomainVestibule provenance: DomainManifestProvenance runtime: DomainRuntimeDescriptor schema: 'gh-aios.domain-manifest/v1' verification: { manifestDigest: string state: 'verified' verifiedAt: number } } export interface DomainSessionCapability { capabilityId: string domainId: string expiresAt: number nodeId: string scopes: string[] } export interface DomainConnectionReceipt { connectionId: string domainId: string manifestDigest: string nodeId: string receiptId: string state: 'online' } export interface LighthouseState { stage: 'lighthouse' } export interface VestibuleState { domain: PublicDomainVestibule stage: 'vestibule' } export interface AccessState { manifest: VerifiedDomainManifest nodeType: DomainNodeType receipt: DomainConnectionReceipt | null session: DomainSessionCapability | null stage: 'access' } export interface RuntimeState { manifest: VerifiedDomainManifest mode: 'connected' | 'disconnected-readonly' nodeType: DomainNodeType receipt: DomainConnectionReceipt session: DomainSessionCapability stage: 'runtime' } export type DomainAccessState = LighthouseState | VestibuleState | AccessState | RuntimeState export class DomainContractError extends Error { readonly code: string constructor(code: string) { super(code) this.code = code this.name = 'DomainContractError' } } const SHA256 = /^[a-f0-9]{64}$/ const SOURCE_COMMIT = /^[a-f0-9]{40,64}$/ const REQUIRED_ENTER_SCOPE = 'domain:enter' function required(value: string, code: string): string { if (!value.trim()) throw new DomainContractError(code) return value } function publicDomain(domain: PublicDomainVestibule): PublicDomainVestibule { required(domain.domainId, 'domain_manifest_public_id_missing') required(domain.formalName, 'domain_manifest_formal_name_missing') required(domain.displayName, 'domain_manifest_display_name_missing') required(domain.purpose, 'domain_manifest_public_purpose_missing') required(domain.responsibleParty, 'domain_manifest_responsible_party_missing') if (!domain.accessModes.length) { throw new DomainContractError('domain_manifest_access_modes_missing') } if (domain.accessModes.some(mode => mode !== 'LOCAL_TERMINAL_NODE' && mode !== 'CLOUD_RESIDENT_NODE')) { throw new DomainContractError('domain_manifest_access_mode_invalid') } if (domain.themePreview) { required(domain.themePreview.assetRef, 'domain_manifest_theme_preview_ref_missing') required(domain.themePreview.description, 'domain_manifest_theme_preview_description_missing') } return { accessModes: [...domain.accessModes], displayName: domain.displayName, domainId: domain.domainId, formalName: domain.formalName, publicStatus: domain.publicStatus, purpose: domain.purpose, responsibleParty: domain.responsibleParty, themePreview: domain.themePreview ? { ...domain.themePreview } : null, } } export function assertVerifiedDomainManifest( manifest: VerifiedDomainManifest, ): VerifiedDomainManifest { if (manifest.schema !== 'gh-aios.domain-manifest/v1') { throw new DomainContractError('domain_manifest_schema_unsupported') } publicDomain(manifest.public) if (manifest.verification.state !== 'verified' || !Number.isFinite(manifest.verification.verifiedAt)) { throw new DomainContractError('domain_manifest_not_verified') } if (!SHA256.test(manifest.provenance.digest) || manifest.verification.manifestDigest !== manifest.provenance.digest) { throw new DomainContractError('domain_manifest_digest_invalid') } if (!SOURCE_COMMIT.test(manifest.provenance.sourceCommit)) { throw new DomainContractError('domain_manifest_source_commit_invalid') } required(manifest.provenance.repositoryId, 'domain_manifest_repository_missing') required(manifest.provenance.signerId, 'domain_manifest_signer_missing') required(manifest.provenance.signature, 'domain_manifest_signature_missing') required(manifest.runtime.routeRef, 'domain_manifest_route_missing') required(manifest.runtime.themePackageRef, 'domain_manifest_theme_package_missing') required(manifest.runtime.healthCheckRef, 'domain_manifest_health_check_missing') required(manifest.runtime.rollbackVersion, 'domain_manifest_rollback_version_missing') return manifest } export function projectPublicDomainVestibule( manifest: VerifiedDomainManifest, ): PublicDomainVestibule { return publicDomain(assertVerifiedDomainManifest(manifest).public) } export const INITIAL_DOMAIN_ACCESS_STATE: LighthouseState = { stage: 'lighthouse' } export function selectPublicDomain( state: LighthouseState | VestibuleState, domain: PublicDomainVestibule, ): VestibuleState { void state return { domain: publicDomain(domain), stage: 'vestibule' } } export function beginDomainAccess( state: VestibuleState, manifest: VerifiedDomainManifest, nodeType: DomainNodeType, ): AccessState { const verified = assertVerifiedDomainManifest(manifest) if (verified.public.domainId !== state.domain.domainId) { throw new DomainContractError('domain_manifest_selected_domain_mismatch') } if (!verified.public.accessModes.includes(nodeType)) { throw new DomainContractError('domain_node_type_not_allowed') } return { manifest: verified, nodeType, receipt: null, session: null, stage: 'access', } } export function acceptDomainSession( state: AccessState, session: DomainSessionCapability, now: number, ): AccessState { if (session.domainId !== state.manifest.public.domainId) { throw new DomainContractError('domain_session_domain_mismatch') } if (session.expiresAt <= now) { throw new DomainContractError('domain_session_expired') } if (!session.scopes.includes(REQUIRED_ENTER_SCOPE)) { throw new DomainContractError('domain_session_enter_scope_missing') } required(session.capabilityId, 'domain_session_capability_id_missing') required(session.nodeId, 'domain_session_node_id_missing') return { ...state, session: { ...session, scopes: [...session.scopes] } } } export function acceptDomainConnectionReceipt( state: AccessState, receipt: DomainConnectionReceipt, ): AccessState { if (!state.session) { throw new DomainContractError('domain_connection_session_missing') } if (receipt.domainId !== state.manifest.public.domainId) { throw new DomainContractError('domain_connection_domain_mismatch') } if (receipt.nodeId !== state.session.nodeId) { throw new DomainContractError('domain_connection_node_mismatch') } if (receipt.manifestDigest !== state.manifest.provenance.digest) { throw new DomainContractError('domain_connection_manifest_mismatch') } required(receipt.connectionId, 'domain_connection_id_missing') required(receipt.receiptId, 'domain_connection_receipt_id_missing') return { ...state, receipt: { ...receipt } } } export function enterDomainRuntime(state: AccessState, now: number): RuntimeState { if (!state.session) throw new DomainContractError('domain_runtime_session_missing') if (!state.receipt) throw new DomainContractError('domain_runtime_connection_receipt_missing') if (state.session.expiresAt <= now) throw new DomainContractError('domain_session_expired') return { manifest: state.manifest, mode: 'connected', nodeType: state.nodeType, receipt: state.receipt, session: state.session, stage: 'runtime', } } export function disconnectDomainRuntime(state: RuntimeState): RuntimeState { return { ...state, mode: 'disconnected-readonly' } } export function returnToLighthouse(): LighthouseState { return INITIAL_DOMAIN_ACCESS_STATE }