{"version":3,"file":"brokerHost-BzffXeb2.cjs","names":["timingSafeEqual","https","http","randomBytes","fs","path","os"],"sources":["../src/services/brokerRoutes/index.ts","../src/services/brokerServer/index.ts","../src/services/brokerHost/index.ts"],"sourcesContent":["export interface BrokerRoute {\n  /** Pi provider name, which is also the broker's first path segment. */\n  provider: string;\n  /** Upstream origin plus any base path Pi's own provider data carries. */\n  upstream: string;\n  /** Host environment variables that may hold the real credential, in priority order. */\n  hostKeyEnv: readonly string[];\n}\n\n/**\n * Providers the broker can terminate, mirroring Pi's own provider data.\n *\n * Curated rather than derived: Pi keeps base URLs in package-internal JSON that\n * carries no stability promise. A provider missing here is simply not brokered,\n * and its credential stays on the host.\n */\nconst ROUTES: readonly BrokerRoute[] = [\n  { provider: 'anthropic', upstream: 'https://api.anthropic.com', hostKeyEnv: ['ANTHROPIC_API_KEY'] },\n  { provider: 'openai', upstream: 'https://api.openai.com/v1', hostKeyEnv: ['OPENAI_API_KEY'] },\n  { provider: 'google', upstream: 'https://generativelanguage.googleapis.com/v1beta', hostKeyEnv: ['GEMINI_API_KEY'] },\n  { provider: 'groq', upstream: 'https://api.groq.com/openai/v1', hostKeyEnv: ['GROQ_API_KEY'] },\n  { provider: 'xai', upstream: 'https://api.x.ai/v1', hostKeyEnv: ['XAI_API_KEY'] },\n  { provider: 'openrouter', upstream: 'https://openrouter.ai/api/v1', hostKeyEnv: ['OPENROUTER_API_KEY'] },\n  { provider: 'deepseek', upstream: 'https://api.deepseek.com', hostKeyEnv: ['DEEPSEEK_API_KEY'] },\n  { provider: 'mistral', upstream: 'https://api.mistral.ai', hostKeyEnv: ['MISTRAL_API_KEY'] },\n  { provider: 'together', upstream: 'https://api.together.ai/v1', hostKeyEnv: ['TOGETHER_API_KEY'] },\n  { provider: 'cerebras', upstream: 'https://api.cerebras.ai/v1', hostKeyEnv: ['CEREBRAS_API_KEY'] },\n  { provider: 'moonshotai', upstream: 'https://api.moonshot.ai/v1', hostKeyEnv: ['MOONSHOT_API_KEY'] },\n  { provider: 'zai', upstream: 'https://api.z.ai/api/coding/paas/v4', hostKeyEnv: ['ZAI_API_KEY'] },\n];\n\nexport function brokerRoutes(): readonly BrokerRoute[] {\n  return ROUTES;\n}\n\nexport function findBrokerRoute(provider: string): BrokerRoute | undefined {\n  return ROUTES.find((route) => route.provider === provider);\n}\n\nexport interface ResolvedCredential {\n  route: BrokerRoute;\n  /** Environment variable the container would otherwise have received. */\n  envName: string;\n  value: string;\n}\n\n/** Selects the providers this host can actually broker for a session. */\nexport function resolveBrokeredCredentials(\n  environment: Readonly<Record<string, string | undefined>>,\n): ResolvedCredential[] {\n  const resolved: ResolvedCredential[] = [];\n  for (const route of ROUTES) {\n    for (const envName of route.hostKeyEnv) {\n      const value = environment[envName]?.trim();\n      if (value) {\n        resolved.push({ route, envName, value });\n        break;\n      }\n    }\n  }\n  return resolved;\n}\n","import { timingSafeEqual } from 'node:crypto';\nimport http from 'node:http';\nimport https from 'node:https';\n\nimport type { ResolvedCredential } from '../brokerRoutes';\n\n/** Headers a provider SDK may carry its credential in. */\nconst CREDENTIAL_HEADERS = ['x-api-key', 'authorization', 'x-goog-api-key'] as const;\n/** Query parameter some Google clients use instead of a header. */\nconst CREDENTIAL_QUERY = 'key';\nconst BEARER_PREFIX = 'bearer ';\n/** Connection-scoped headers that must not cross to the upstream request. */\nconst HOP_BY_HOP = new Set([\n  'connection',\n  'keep-alive',\n  'proxy-authenticate',\n  'proxy-authorization',\n  'te',\n  'trailer',\n  'transfer-encoding',\n  'upgrade',\n  'host',\n  'content-length',\n]);\nconst PATH_PATTERN = /^\\/([^/?]+)(.*)$/;\n\nexport interface BrokerServerOptions {\n  /** Providers this session may reach, keyed by Pi provider name. */\n  credentials: ReadonlyMap<string, ResolvedCredential>;\n  /** Secret the container presents in place of a real credential. */\n  token: string;\n  /** Receives one line per rejected request, for host-side visibility. */\n  onDenied?: (reason: string) => void;\n  /** Seam for tests; defaults to the real https transport. */\n  requestUpstream?: typeof https.request;\n}\n\nfunction matchesToken(candidate: string, token: string): boolean {\n  const left = Buffer.from(candidate);\n  const right = Buffer.from(token);\n  return left.length === right.length && timingSafeEqual(left, right);\n}\n\nfunction credentialValue(headerValue: string): string {\n  return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? headerValue.slice(BEARER_PREFIX.length) : headerValue;\n}\n\nfunction withCredential(headerValue: string, realKey: string): string {\n  return headerValue.toLowerCase().startsWith(BEARER_PREFIX) ? `Bearer ${realKey}` : realKey;\n}\n\n/**\n * Rewrites the request's credential, proving the caller holds the session token.\n *\n * Which header carries the key differs per provider SDK, so every candidate is\n * checked rather than assumed. Returns undefined when nothing presented the\n * token, which is what makes an unauthenticated caller indistinguishable from a\n * misrouted one.\n */\nfunction swapCredential(\n  headers: http.IncomingHttpHeaders,\n  search: URLSearchParams,\n  token: string,\n  realKey: string,\n): http.OutgoingHttpHeaders | undefined {\n  const forwarded: http.OutgoingHttpHeaders = {};\n  let authenticated = false;\n\n  for (const [name, value] of Object.entries(headers)) {\n    if (value === undefined || HOP_BY_HOP.has(name)) continue;\n    const single = Array.isArray(value) ? value[0] : value;\n    if ((CREDENTIAL_HEADERS as readonly string[]).includes(name) && single !== undefined) {\n      if (!matchesToken(credentialValue(single), token)) return undefined;\n      forwarded[name] = withCredential(single, realKey);\n      authenticated = true;\n      continue;\n    }\n    forwarded[name] = value;\n  }\n\n  const queryKey = search.get(CREDENTIAL_QUERY);\n  if (queryKey !== null) {\n    if (!matchesToken(queryKey, token)) return undefined;\n    search.set(CREDENTIAL_QUERY, realKey);\n    authenticated = true;\n  }\n\n  return authenticated ? forwarded : undefined;\n}\n\nfunction reject(response: http.ServerResponse, status: number, message: string): void {\n  response.writeHead(status, { 'content-type': 'application/json' });\n  response.end(JSON.stringify({ error: { type: 'doompi_broker', message } }));\n}\n\n/**\n * Terminates provider calls from a sandboxed session on the host.\n *\n * The container never holds a real credential: it presents the session token,\n * and only a request that proves possession of it is forwarded upstream with\n * the host's key attached. Bodies stream in both directions so token-by-token\n * responses are not buffered.\n */\nexport function createBrokerServer(options: BrokerServerOptions): http.Server {\n  const requestUpstream = options.requestUpstream ?? https.request;\n\n  return http.createServer((request, response) => {\n    const match = PATH_PATTERN.exec(request.url ?? '');\n    const provider = match?.[1];\n    const credential = provider ? options.credentials.get(provider) : undefined;\n    if (!match || !credential) {\n      options.onDenied?.(`unroutable provider path ${request.url ?? ''}`);\n      reject(response, 404, 'Unknown provider for this sandbox session.');\n      return;\n    }\n\n    const target = new URL(`${credential.route.upstream}${match[2] || ''}`);\n    const headers = swapCredential(request.headers, target.searchParams, options.token, credential.value);\n    if (!headers) {\n      options.onDenied?.(`missing or invalid session token for ${credential.route.provider}`);\n      reject(response, 401, 'This sandbox session did not present its broker token.');\n      return;\n    }\n\n    const upstream = requestUpstream(\n      target,\n      { method: request.method, headers: { ...headers, host: target.host } },\n      (upstreamResponse) => {\n        response.writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers);\n        upstreamResponse.pipe(response);\n      },\n    );\n    upstream.on('error', (error: Error) => {\n      options.onDenied?.(`upstream ${credential.route.provider} failed: ${error.message}`);\n      if (!response.headersSent) reject(response, 502, 'The provider could not be reached from the host.');\n      else response.destroy();\n    });\n    request.on('aborted', () => upstream.destroy());\n    request.pipe(upstream);\n  });\n}\n","import { randomBytes } from 'node:crypto';\nimport fs from 'node:fs';\nimport type http from 'node:http';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport type { BrokerEndpoint } from '../../types/sandboxHarness';\nimport { resolveBrokeredCredentials } from '../brokerRoutes';\nimport { createBrokerServer } from '../brokerServer';\n\nconst SOCKET_DIRECTORY_PREFIX = 'doompi-broker-';\nconst SOCKET_FILE_NAME = 'broker.sock';\nconst OWNER_ONLY_DIRECTORY = 0o700;\nconst TOKEN_BYTES = 32;\nconst LOOPBACK = '127.0.0.1';\nconst LINUX_PLATFORM = 'linux';\nconst EPHEMERAL_PORT = 0;\n\nexport interface RunningBroker {\n  /** How a container reaches this broker. */\n  endpoint: BrokerEndpoint;\n  /** Secret the container presents instead of any real credential. */\n  token: string;\n  /** Pi provider names the session may reach. */\n  providers: string[];\n  /** Host environment variables whose value the container receives as the token. */\n  withheldEnv: string[];\n  stop(): Promise<void>;\n}\n\nexport interface StartBrokerOptions {\n  environment: Readonly<Record<string, string | undefined>>;\n  onDenied?: (reason: string) => void;\n  /** Seam for tests; defaults to this host's platform. */\n  platform?: string;\n  /**\n   * Fixed directory to hold the socket instead of a fresh temporary one.\n   *\n   * A reused container keeps the mounts it was created with, so a dev\n   * container has to find the socket at the same path on every launch.\n   */\n  socketDirectory?: string;\n  /** Forces the loopback transport even where a socket would work. */\n  forceLoopback?: boolean;\n}\n\n/**\n * Starts the host-side provider broker for one sandboxed session.\n *\n * Answers undefined when the host holds no brokerable credential, which keeps\n * a session that authenticates some other way on the unbrokered path instead\n * of failing it.\n */\nexport async function startBroker(options: StartBrokerOptions): Promise<RunningBroker | undefined> {\n  const resolved = resolveBrokeredCredentials(options.environment);\n  if (resolved.length === 0) return undefined;\n\n  const token = randomBytes(TOKEN_BYTES).toString('base64url');\n  const credentials = new Map(resolved.map((credential) => [credential.route.provider, credential]));\n  const server = createBrokerServer({ credentials, token, onDenied: options.onDenied });\n  const platform = options.platform ?? process.platform;\n\n  const useSocket = platform === LINUX_PLATFORM && options.forceLoopback !== true;\n  const { endpoint, dispose } = useSocket\n    ? await listenOnSocket(server, options.socketDirectory)\n    : await listenOnLoopback(server);\n\n  return {\n    endpoint,\n    token,\n    providers: resolved.map((credential) => credential.route.provider),\n    withheldEnv: resolved.map((credential) => credential.envName),\n    stop: () => stopBroker(server, dispose),\n  };\n}\n\n/**\n * Native Linux shares a kernel with the container, so a bind-mounted socket\n * needs no port and is reachable as an ordinary file.\n */\nasync function listenOnSocket(\n  server: http.Server,\n  fixedDirectory?: string,\n): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n  const socketDirectory = fixedDirectory ?? fs.mkdtempSync(path.join(os.tmpdir(), SOCKET_DIRECTORY_PREFIX));\n  fs.mkdirSync(socketDirectory, { recursive: true });\n  fs.chmodSync(socketDirectory, OWNER_ONLY_DIRECTORY);\n  const socketPath = path.join(socketDirectory, SOCKET_FILE_NAME);\n  // A previous session that died without closing leaves the node behind, and\n  // bind fails on an existing path.\n  fs.rmSync(socketPath, { force: true });\n  await new Promise<void>((resolve, reject) => {\n    server.once('error', reject);\n    server.listen(socketPath, () => resolve());\n  });\n  return {\n    endpoint: { transport: 'unix', socketDirectory },\n    // A fixed directory outlives the session that borrowed it.\n    dispose: () =>\n      fixedDirectory\n        ? fs.rmSync(socketPath, { force: true })\n        : fs.rmSync(socketDirectory, { recursive: true, force: true }),\n  };\n}\n\n/**\n * Everywhere else the container runs in its own virtual machine, which cannot\n * connect to a host unix socket even when the file is shared through: the\n * connect fails with ENOTSUP. Loopback keeps the broker off the network while\n * still being reachable through the engine's host gateway, and the session\n * token is what stops another local process from using it.\n */\nasync function listenOnLoopback(server: http.Server): Promise<{ endpoint: BrokerEndpoint; dispose: () => void }> {\n  await new Promise<void>((resolve, reject) => {\n    server.once('error', reject);\n    server.listen(EPHEMERAL_PORT, LOOPBACK, () => resolve());\n  });\n  const address = server.address();\n  if (address === null || typeof address === 'string') throw new Error('The broker did not report a listening port.');\n  return { endpoint: { transport: 'tcp', port: address.port }, dispose: () => undefined };\n}\n\nasync function stopBroker(server: http.Server, dispose: () => void): Promise<void> {\n  await new Promise<void>((resolve) => {\n    server.close(() => resolve());\n    // An in-flight provider stream would otherwise hold the listener open past\n    // the session that owns it.\n    server.closeAllConnections();\n  });\n  dispose();\n}\n"],"mappings":"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"}