import { sign } from '@@/jwt'; import type { CredentialScope } from '@@/auth-token'; import { PORT, OFFICER_API_URL } from '../../officer-url.mjs'; const { PUBLIC_URL } = process.env; const PUBLIC_HOST = (() => { try { return PUBLIC_URL ? new URL(PUBLIC_URL).host : undefined; } catch { return undefined; } })(); type TaskApiUser = { id: number; email: string; username?: string | null; /** * The narrowing carried by the credential that ASKED for this run, or null/absent for a full-authority * caller (a browser session, the context menu, a job started by hand). * * It has to propagate or the narrowing is decorative. A commander holding a key limited to `tasks` can * write a task and run it; if the token handed to that script were unnarrowed, the script would come * back through the API with the owner's full authority and the limit would have bought nothing. The * script gets exactly what its caller had — never more. */ scope?: CredentialScope | null; }; // Environment that lets a script task call Officer's own API instead of reimplementing server-side // work (transcription, for one — `plugins/transcribe/tasks/transcribe-audio-file/index.ts` uses exactly // this to reach the transcribe plugin's own route rather than talking to Whisper itself). // // Requests go to 127.0.0.1 so a task never depends on DNS or the reverse proxy being up. Origin // validation matches the Host header against PUBLIC_URL though, so a bare localhost request is // rejected — hence OFFICER_API_HOST, which scripts must pass as an explicit Host header: // // curl -H "Authorization: Bearer $OFFICER_AUTH_TOKEN" -H "Host: $OFFICER_API_HOST" \ // "$OFFICER_API_URL/api/transcribe/transcribe" export async function buildTaskApiEnv(user: TaskApiUser): Promise> { const token = await sign( { id: user.id, email: user.email, username: user.username ?? '', // Only when narrowed. An absent claim is what every ordinary run already signs, and `resolveAuthToken` // spreads the payload onto the identity, so this reaches both doors with no further wiring. ...(user.scope ? { scope: user.scope } : {}), }, '12h', ); return { OFFICER_API_URL, OFFICER_API_HOST: PUBLIC_HOST ?? `127.0.0.1:${PORT}`, OFFICER_AUTH_TOKEN: token, }; }