/** Same-origin endpoint descriptors for the future HUX-05 backend. */ import { ACTIVITY_TIMELINE_FLAG, AUTONOMY_FLAG, FOUNDATION_FLAG } from "./model.ts"; import { isOpaqueId, normalizeIdentity, sameIdentity } from "./security.ts"; import type { AutonomyEndpoint, AutonomyEndpointContract, HuxIdentity } from "./types.ts"; interface FoundationClient { apiVersion: string; identity: HuxIdentity; enabled(flag: string): boolean; endpoint(path: string): string; } function endpoint(method: AutonomyEndpoint["method"], path: string, responseSchema: string, requiredBody?: readonly string[]): AutonomyEndpoint { return Object.freeze({method, path, responseSchema, ...(requiredBody ? {requiredBody} : {})}); } /** Describe, but never call, the tenant-scoped HUX-05 interface. */ export function createAutonomyEndpointContract(client: FoundationClient): AutonomyEndpointContract | null { if (client.apiVersion !== "hux.v1" || ![FOUNDATION_FLAG, ACTIVITY_TIMELINE_FLAG, AUTONOMY_FLAG].every((flag) => client.enabled(flag))) return null; const identity = normalizeIdentity(client.identity); if (!identity || !sameIdentity(identity, client.identity)) throw new TypeError("Scoped HUX identity required"); const scoped = (root: string, id: string, prefix: string): string => { if (!isOpaqueId(id, prefix)) throw new TypeError(`Opaque ${prefix} id required`); return client.endpoint(`${root}/${encodeURIComponent(id)}`); }; return Object.freeze({ identity: Object.freeze({...identity}), policy: endpoint("GET", client.endpoint("/autonomy/policy"), "hux.policy.v1"), updatePolicy: endpoint("PUT", client.endpoint("/autonomy/policy"), "hux.policy.v1", ["expected_policy_id", "expected_updated_at", "autonomy", "grants", "budgets", "guardrails"]), approvals: endpoint("GET", client.endpoint("/approvals?status=pending&limit=100"), "hux.approval_page.v1"), decideApproval(approvalId: string) { return endpoint("POST", `${scoped("/approvals", approvalId, "apr")}/decision`, "hux.approval.v1", ["expected_run_id", "expected_conversation_id", "expected_capability", "expected_requested_at", "choice"]); }, stop(runId: string) { if (!/^run_[A-Za-z0-9._-]{1,116}$/.test(runId)) throw new TypeError("Exact run id required"); return endpoint("POST", client.endpoint(`/runs/${encodeURIComponent(runId)}/stop`), "hux.cancel_receipt.v1", ["conversation_id"]); }, release: Object.freeze({schema: "hux.release.v1" as const, requiredState: "live_verified" as const, featureFlags: Object.freeze([FOUNDATION_FLAG, ACTIVITY_TIMELINE_FLAG, AUTONOMY_FLAG])}), }); }