@nick3/copilot-api 1.10.8 → 1.10.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +141 -46
  2. package/README.zh-CN.md +141 -46
  3. package/dist/{account-COtMmvzU.js → account-DpW8RaT6.js} +3 -3
  4. package/dist/{account-COtMmvzU.js.map → account-DpW8RaT6.js.map} +1 -1
  5. package/dist/admin/AGENTS.md +19 -0
  6. package/dist/auth-nO-eHeO_.js +327 -0
  7. package/dist/auth-nO-eHeO_.js.map +1 -0
  8. package/dist/{check-usage-DdevqHE5.js → check-usage-ZifYvA3w.js} +4 -42
  9. package/dist/check-usage-ZifYvA3w.js.map +1 -0
  10. package/dist/config-CmhIPHn_.js +578 -0
  11. package/dist/config-CmhIPHn_.js.map +1 -0
  12. package/dist/{debug-BMo6ltbp.js → debug-DvpksqEL.js} +18 -7
  13. package/dist/debug-DvpksqEL.js.map +1 -0
  14. package/dist/main.js +5 -10
  15. package/dist/main.js.map +1 -1
  16. package/dist/mcp-http-BhELuvog.js +2 -0
  17. package/dist/mcp-http-DI4Vz01p.js +82 -0
  18. package/dist/mcp-http-DI4Vz01p.js.map +1 -0
  19. package/dist/mcp-http-config-DMdUDz1D.js +39 -0
  20. package/dist/mcp-http-config-DMdUDz1D.js.map +1 -0
  21. package/dist/mcp-pLTPS0tO.js +79 -0
  22. package/dist/mcp-pLTPS0tO.js.map +1 -0
  23. package/dist/{tool-search-BrN7M0Dd.js → mcp-server-DEqHrXFq.js} +25 -2
  24. package/dist/mcp-server-DEqHrXFq.js.map +1 -0
  25. package/dist/{paths-CclKwouX.js → paths-Bpsb62LK.js} +3 -1
  26. package/dist/paths-Bpsb62LK.js.map +1 -0
  27. package/dist/{poll-access-token-BAgM2-7k.js → poll-access-token-GzVkiTH8.js} +71 -4
  28. package/dist/poll-access-token-GzVkiTH8.js.map +1 -0
  29. package/dist/{request-outbound-BJjWS_jF.js → request-outbound-BkEA8Wgb.js} +1 -1
  30. package/dist/{request-outbound-Pu1kp2x8.js → request-outbound-DZTxxtcx.js} +3 -3
  31. package/dist/{request-outbound-Pu1kp2x8.js.map → request-outbound-DZTxxtcx.js.map} +1 -1
  32. package/dist/{proxy-_U-hgwIn.js → responses-bridge-registry-BJ5Sbh6-.js} +116 -577
  33. package/dist/responses-bridge-registry-BJ5Sbh6-.js.map +1 -0
  34. package/dist/{server-DulP9mYd.js → server-DJ3_UGc4.js} +339 -168
  35. package/dist/server-DJ3_UGc4.js.map +1 -0
  36. package/dist/start-DaB0AcjZ.js +526 -0
  37. package/dist/start-DaB0AcjZ.js.map +1 -0
  38. package/dist/token-DrFDLVxa.js +365 -0
  39. package/dist/token-DrFDLVxa.js.map +1 -0
  40. package/package.json +1 -1
  41. package/dist/auth-B0y-2njL.js +0 -226
  42. package/dist/auth-B0y-2njL.js.map +0 -1
  43. package/dist/check-usage-DdevqHE5.js.map +0 -1
  44. package/dist/debug-BMo6ltbp.js.map +0 -1
  45. package/dist/get-copilot-token-8Rm-rVsp.js +0 -17
  46. package/dist/get-copilot-token-8Rm-rVsp.js.map +0 -1
  47. package/dist/mcp-9Hgepkc5.js +0 -37
  48. package/dist/mcp-9Hgepkc5.js.map +0 -1
  49. package/dist/paths-CclKwouX.js.map +0 -1
  50. package/dist/poll-access-token-BAgM2-7k.js.map +0 -1
  51. package/dist/proxy-_U-hgwIn.js.map +0 -1
  52. package/dist/server-DulP9mYd.js.map +0 -1
  53. package/dist/start-CtEoE2gt.js +0 -274
  54. package/dist/start-CtEoE2gt.js.map +0 -1
  55. package/dist/tool-search-BrN7M0Dd.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"poll-access-token-GzVkiTH8.js","names":["COPILOT_WEBSOCKET_VERSION","get"],"sources":["../src/lib/compact.ts","../src/lib/opencode.ts","../src/lib/request-context.ts","../src/lib/state.ts","../src/lib/api-config.ts","../src/lib/error.ts","../src/lib/proxy.ts","../src/services/github/get-copilot-token.ts","../src/services/github/get-copilot-usage.ts","../src/services/github/get-device-code.ts","../src/services/github/get-user.ts","../src/services/get-vscode-version.ts","../src/lib/deviceid.ts","../src/lib/utils.ts","../src/services/github/poll-access-token.ts"],"sourcesContent":["export const COMPACT_REQUEST = 1 as const\nexport const COMPACT_AUTO_CONTINUE = 2 as const\n\nexport const compactSystemPromptStart =\n \"You are a helpful AI assistant tasked with summarizing conversations\"\nexport const compactOpenCodeSystemPromptStart =\n \"You are an anchored context summarization assistant for coding sessions.\"\nexport const compactSystemPromptStarts = [\n compactSystemPromptStart,\n compactOpenCodeSystemPromptStart,\n] as const\nexport const compactTextOnlyGuard =\n \"CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.\"\nexport const compactSummaryPromptStart =\n \"Your task is to create a detailed summary of the conversation so far\"\nexport const compactAutoContinueClaudeCodePromptStart =\n \"This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.\"\nexport const compactAutoContinueOpenCodePromptStart =\n \"Continue if you have next steps, or stop and ask for clarification if you are unsure how to proceed.\"\nexport const compactAutoContinueOpenCodePromptStart2 =\n \"The previous request exceeded the provider's size limit due to large media attachments. The conversation was compacted and media files were removed from context.\"\nexport const compactAutoContinuePromptStarts = [\n compactAutoContinueClaudeCodePromptStart,\n compactAutoContinueOpenCodePromptStart,\n compactAutoContinueOpenCodePromptStart2,\n] as const\nexport const compactMessageSections = [\n \"Pending Tasks:\",\n \"Current Work:\",\n] as const\n\nexport type CompactType =\n | 0\n | typeof COMPACT_REQUEST\n | typeof COMPACT_AUTO_CONTINUE\n","import consola from \"consola\"\nimport { exec } from \"node:child_process\"\nimport { readFile } from \"node:fs/promises\"\nimport path from \"node:path\"\n\nconst execAsync = (command: string): Promise<string> => {\n return new Promise((resolve, reject) => {\n exec(command, (error, stdout) => {\n if (error) {\n reject(error)\n return\n }\n\n resolve(stdout)\n })\n })\n}\n\nlet opencodeVersionCache: string | undefined\n\nconst getGlobalNpmRoot = async (): Promise<string> => {\n const stdout = await execAsync(\"npm root -g\")\n return stdout.trim()\n}\n\nasync function resolveOpencodeVersion(): Promise<void> {\n try {\n const npmRootPath = await getGlobalNpmRoot()\n const opencodePackagePath = path.join(\n npmRootPath,\n \"opencode-ai\",\n \"package.json\",\n )\n const packageJson = await readFile(opencodePackagePath, \"utf8\")\n const { version } = JSON.parse(packageJson) as { version: string }\n opencodeVersionCache = version\n } catch (error) {\n consola.warn(`Failed to resolve opencode version`, error)\n }\n}\n\nexport const initOpencodeVersion = (): Promise<void> => {\n if (process.env.COPILOT_API_OAUTH_APP?.trim() !== \"opencode\") {\n return Promise.resolve()\n }\n return resolveOpencodeVersion()\n}\n\nexport const getCachedOpencodeVersion = (): string | undefined => {\n return opencodeVersionCache\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\"\n\nexport interface OutboundHeadersSnapshot {\n xRequestId?: string\n xAgentTaskId?: string\n xInteractionId?: string\n xInteractionType?: string\n openaiIntent?: string\n userAgent?: string\n}\n\nexport interface RequestContext {\n traceId: string\n startTime: number\n userAgent: string\n sessionAffinity: string | undefined\n parentSessionId: string | undefined\n outboundHeaders?: OutboundHeadersSnapshot\n fetchImpl?: typeof fetch\n}\n\nconst TRACE_ID_MAX_LENGTH = 64\nconst TRACE_ID_PATTERN = /^\\w[\\w.-]*$/\n\nconst asyncLocalStorage = new AsyncLocalStorage<RequestContext>()\n\nexport const requestContext = {\n getStore: () => asyncLocalStorage.getStore(),\n run: <T>(context: RequestContext, callback: () => T) =>\n asyncLocalStorage.run(context, callback),\n}\n\nexport function generateTraceId(): string {\n const timestamp = Date.now().toString(36)\n const random = Math.random().toString(36).slice(2, 8)\n return `${timestamp}-${random}`\n}\n\nfunction buildOutboundHeadersSnapshot(\n headers: Record<string, string>,\n): OutboundHeadersSnapshot {\n const snapshot: OutboundHeadersSnapshot = {\n xRequestId: undefined,\n xAgentTaskId: undefined,\n xInteractionId: undefined,\n xInteractionType: undefined,\n openaiIntent: undefined,\n userAgent: undefined,\n }\n\n for (const [name, value] of Object.entries(headers)) {\n switch (name.toLowerCase()) {\n case \"x-request-id\": {\n snapshot.xRequestId = value\n break\n }\n case \"x-agent-task-id\": {\n snapshot.xAgentTaskId = value\n break\n }\n case \"x-interaction-id\": {\n snapshot.xInteractionId = value\n break\n }\n case \"x-interaction-type\": {\n snapshot.xInteractionType = value\n break\n }\n case \"openai-intent\": {\n snapshot.openaiIntent = value\n break\n }\n case \"user-agent\": {\n snapshot.userAgent = value\n break\n }\n default: {\n break\n }\n }\n }\n\n return snapshot\n}\n\nexport function captureOutboundHeadersSnapshot(\n headers: Record<string, string>,\n): void {\n const store = asyncLocalStorage.getStore()\n if (!store) return\n\n store.outboundHeaders = buildOutboundHeadersSnapshot(headers)\n}\n\nexport function getOutboundHeadersSnapshot():\n | OutboundHeadersSnapshot\n | undefined {\n return asyncLocalStorage.getStore()?.outboundHeaders\n}\n\nexport function consumeOutboundHeadersSnapshot():\n | OutboundHeadersSnapshot\n | undefined {\n const store = asyncLocalStorage.getStore()\n const snapshot = store?.outboundHeaders\n\n if (store) {\n store.outboundHeaders = undefined\n }\n\n return snapshot\n}\n\nexport function resolveTraceId(traceId: string | null | undefined): string {\n const candidate = traceId?.trim()\n\n if (\n !candidate\n || candidate.length > TRACE_ID_MAX_LENGTH\n || !TRACE_ID_PATTERN.test(candidate)\n ) {\n return generateTraceId()\n }\n\n return candidate\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport type { AccountContext, AccountType } from \"./types/account\"\n\nexport interface State {\n githubToken?: string\n userName?: string\n copilotToken?: string\n codexAccessToken?: string\n codexRefreshToken?: string\n codexExpiresAt?: number\n codexAccountId?: string\n\n accountType: AccountType\n vsCodeVersion?: string\n\n macMachineId?: string\n vsCodeSessionId?: string\n vsCodeDeviceId: string\n\n manualApprove: boolean\n rateLimitWait: boolean\n showToken: boolean\n\n // Rate limiting configuration\n rateLimitSeconds?: number\n lastRequestTimestamp?: number\n verbose: boolean\n\n copilotApiUrl?: string\n}\n\nexport const state: State = {\n accountType: \"individual\",\n manualApprove: false,\n rateLimitWait: false,\n showToken: false,\n verbose: false,\n vsCodeDeviceId: randomUUID(),\n}\n\n/**\n * Create an AccountContext from the current global state.\n * This is a compatibility layer for transitioning to multi-account support.\n * @throws Error if githubToken is not set in state\n */\nexport function accountFromState(): AccountContext {\n if (!state.githubToken) {\n throw new Error(\"GitHub token not set in state\")\n }\n return {\n githubToken: state.githubToken,\n copilotToken: state.copilotToken,\n ...(state.copilotApiUrl !== undefined ?\n { copilotApiUrl: state.copilotApiUrl }\n : {}),\n accountType: state.accountType,\n vsCodeVersion: state.vsCodeVersion,\n clientDeviceId: state.vsCodeDeviceId,\n clientMachineId: state.macMachineId,\n clientSessionId: state.vsCodeSessionId,\n }\n}\n","import { randomUUID } from \"node:crypto\"\n\nimport { COMPACT_REQUEST, type CompactType } from \"./compact\"\nimport type { AccountContext } from \"./types/account\"\n\nimport { getCachedOpencodeVersion } from \"./opencode\"\nimport { requestContext } from \"./request-context\"\nimport { state } from \"./state\"\n\nexport const isOpencodeOauthApp = (): boolean => {\n return process.env.COPILOT_API_OAUTH_APP?.trim() === \"opencode\"\n}\n\nexport const normalizeDomain = (input: string): string => {\n return input\n .trim()\n .replace(/^https?:\\/\\//u, \"\")\n .replace(/\\/+$/u, \"\")\n}\n\nexport const getEnterpriseDomain = (): string | null => {\n const raw = (process.env.COPILOT_API_ENTERPRISE_URL ?? \"\").trim()\n if (!raw) return null\n const normalized = normalizeDomain(raw)\n return normalized || null\n}\n\nexport const getGitHubBaseUrl = (): string => {\n const resolvedDomain = getEnterpriseDomain()\n return resolvedDomain ? `https://${resolvedDomain}` : GITHUB_BASE_URL\n}\n\nexport const getGitHubApiBaseUrl = (): string => {\n const resolvedDomain = getEnterpriseDomain()\n return resolvedDomain ? `https://api.${resolvedDomain}` : GITHUB_API_BASE_URL\n}\n\nconst getOpencodeOauthHeaders = (): Record<string, string> => {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": getOpencodeVersion(),\n }\n}\n\nconst getOpencodeLLMHeaders = (): Record<string, string> => {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": OPENCODE_LLM_USER_AGENT,\n }\n}\n\nconst normalizeOpencodeUserAgent = (userAgent: string): string => {\n const candidate = userAgent.trim()\n const opencodeProduct = candidate.match(/^opencode\\/[^\\s,]+/u)?.[0]\n\n if (!opencodeProduct || candidate.includes(`, ${opencodeProduct}`)) {\n return candidate\n }\n\n return `${candidate}, ${opencodeProduct}`\n}\n\nexport const getOauthUrls = (): {\n deviceCodeUrl: string\n accessTokenUrl: string\n} => {\n const githubBaseUrl = getGitHubBaseUrl()\n\n return {\n deviceCodeUrl: `${githubBaseUrl}/login/device/code`,\n accessTokenUrl: `${githubBaseUrl}/login/oauth/access_token`,\n }\n}\n\ninterface OauthAppConfig {\n clientId: string\n headers: Record<string, string>\n scope: string\n}\n\nexport const getOauthAppConfig = (): OauthAppConfig => {\n if (isOpencodeOauthApp()) {\n return {\n clientId: OPENCODE_GITHUB_CLIENT_ID,\n headers: getOpencodeOauthHeaders(),\n scope: GITHUB_APP_SCOPES,\n }\n }\n\n return {\n clientId: GITHUB_CLIENT_ID,\n headers: standardHeaders(),\n scope: GITHUB_APP_SCOPES,\n }\n}\n\nexport const prepareForCompact = (\n headers: Record<string, string>,\n compactType?: CompactType,\n) => {\n if (compactType) {\n headers[\"x-initiator\"] = \"agent\"\n if (!isOpencodeOauthApp() && compactType === COMPACT_REQUEST) {\n headers[\"x-interaction-type\"] = \"conversation-compaction\"\n headers[\"openai-intent\"] = \"conversation-agent\"\n }\n }\n}\n\nexport const prepareInteractionHeaders = (\n sessionId: string | undefined,\n isSubagent: boolean,\n headers: Record<string, string>,\n) => {\n const sendInteractionHeaders = !isOpencodeOauthApp()\n\n if (isSubagent) {\n headers[\"x-initiator\"] = \"agent\"\n if (sendInteractionHeaders) {\n headers[\"x-interaction-type\"] = \"conversation-subagent\"\n }\n }\n\n if (sessionId && sendInteractionHeaders) {\n headers[\"x-interaction-id\"] = sessionId\n }\n}\n\nexport const standardHeaders = () => ({\n \"content-type\": \"application/json\",\n accept: \"application/json\",\n})\n\nexport const getOpencodeVersion = () => {\n const version = getCachedOpencodeVersion()\n if (version) {\n return \"opencode/\" + version\n }\n return OPENCODE_VERSION\n}\n\nconst OPENCODE_VERSION = \"opencode/1.14.29\"\nconst OPENCODE_LLM_USER_AGENT =\n \"opencode/1.14.29 ai-sdk/provider-utils/4.0.23 runtime/bun/1.3.13, opencode/1.14.29\"\n\nconst COPILOT_VERSION = \"0.50.1\"\nconst EDITOR_PLUGIN_VERSION = `copilot-chat/${COPILOT_VERSION}`\nconst USER_AGENT = `GitHubCopilotChat/${COPILOT_VERSION}`\nconst CLAUDE_AGENT_USER_AGENT =\n \"vscode_claude_code/2.1.112 (external, sdk-ts, agent-sdk/0.2.112)\"\nconst COPILOT_WEBSOCKET_VERSION = COPILOT_VERSION\nconst EDITOR_WEBSOCKET_PLUGIN_VERSION = `copilot-chat/${COPILOT_WEBSOCKET_VERSION}`\n\nconst API_VERSION = \"2026-01-09\"\nconst WEBSOCKET_API_VERSION = API_VERSION\n\nexport const copilotBaseUrl = (account: AccountContext): string => {\n const enterpriseDomain = getEnterpriseDomain()\n if (enterpriseDomain) {\n return `https://copilot-api.${enterpriseDomain}`\n }\n\n if (isOpencodeOauthApp()) {\n return \"https://api.githubcopilot.com\"\n }\n\n if (account.copilotApiUrl) {\n return account.copilotApiUrl\n }\n\n return account.accountType === \"individual\" ?\n \"https://api.githubcopilot.com\"\n : `https://api.${account.accountType}.githubcopilot.com`\n}\n\nexport const prepareMessageProxyHeaders = (headers: Record<string, string>) => {\n if (isOpencodeOauthApp()) {\n return\n }\n\n // vscode copilot claude agent regenerates request id for\n // each request, keeping it consistent\n const requestIdValue = randomUUID()\n headers[\"x-agent-task-id\"] = requestIdValue\n headers[\"x-request-id\"] = requestIdValue\n\n // Consistent with vscode copilot claude agent\n headers[\"x-interaction-type\"] = \"messages-proxy\"\n headers[\"openai-intent\"] = \"messages-proxy\"\n headers[\"user-agent\"] = CLAUDE_AGENT_USER_AGENT\n\n delete headers[\"copilot-integration-id\"]\n}\n\nexport const githubUserHeaders = (\n account: AccountContext,\n): Record<string, string> => {\n if (isOpencodeOauthApp()) {\n return {\n Authorization: `Bearer ${account.githubToken}`,\n \"User-Agent\": getOpencodeVersion(),\n }\n }\n\n return {\n accept: \"application/vnd.github+json\",\n authorization: `token ${account.githubToken}`,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": \"2022-11-28\",\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n }\n}\n\nexport const copilotModelsHeaders = (\n account: AccountContext,\n): Record<string, string> => {\n if (isOpencodeOauthApp()) {\n const token = account.copilotToken ?? account.githubToken\n return {\n Authorization: `Bearer ${token}`,\n \"User-Agent\": getOpencodeVersion(),\n }\n }\n const headers = githubCopilotHeaders(account)\n headers[\"x-interaction-type\"] = \"model-access\"\n headers[\"openai-intent\"] = \"model-access\"\n delete headers[\"x-interaction-id\"]\n delete headers[\"content-type\"]\n return headers\n}\n\nexport const copilotHeaders = (\n account: AccountContext,\n vision: boolean = false,\n requestId?: string,\n): Record<string, string> => {\n if (isOpencodeOauthApp()) {\n const token = account.copilotToken ?? account.githubToken\n const headers: Record<string, string> = {\n Authorization: `Bearer ${token}`,\n ...getOpencodeLLMHeaders(),\n \"Openai-Intent\": \"conversation-edits\",\n }\n\n const store = requestContext.getStore()\n const userAgent = store?.userAgent.trim()\n // Real opencode traffic already carries a versioned opencode/* UA,\n // so prefer the inbound header to keep upstream behavior aligned.\n if (userAgent?.startsWith(\"opencode/\")) {\n headers[\"User-Agent\"] = normalizeOpencodeUserAgent(userAgent)\n }\n\n if (store?.sessionAffinity) {\n headers[\"x-session-affinity\"] = store.sessionAffinity\n }\n\n if (store?.parentSessionId) {\n headers[\"x-parent-session-id\"] = store.parentSessionId\n }\n\n if (vision) headers[\"Copilot-Vision-Request\"] = \"true\"\n\n return headers\n }\n\n return githubCopilotHeaders(account, vision, requestId)\n}\n\nexport const copilotWebSocketHeaders = (\n preparedHeaders: Record<string, string>,\n) => {\n if (isOpencodeOauthApp()) {\n return omitHeader(preparedHeaders, \"x-initiator\")\n }\n\n const requestId =\n getPreparedHeader(preparedHeaders, \"x-request-id\") ?? randomUUID()\n const source = createHeaderResolver(preparedHeaders)\n const headers: Record<string, string> = {\n Authorization: source(\"authorization\"),\n \"X-Request-Id\": requestId,\n \"OpenAI-Intent\": source(\"openai-intent\", \"conversation-agent\"),\n \"X-GitHub-Api-Version\": source(\n \"x-github-api-version\",\n WEBSOCKET_API_VERSION,\n ),\n \"X-Interaction-Id\": source(\"x-interaction-id\", requestId),\n \"X-Interaction-Type\": source(\"x-interaction-type\", \"conversation-agent\"),\n \"X-Agent-Task-Id\": source(\"x-agent-task-id\", requestId),\n }\n\n setPreparedHeader(\n headers,\n \"VScode-SessionId\",\n preparedHeaders,\n \"vscode-sessionid\",\n )\n\n setPreparedHeader(\n headers,\n \"VScode-MachineId\",\n preparedHeaders,\n \"vscode-machineid\",\n )\n\n Object.assign(headers, {\n \"Editor-Device-Id\": source(\"editor-device-id\"),\n \"Editor-Plugin-Version\": source(\n \"editor-plugin-version\",\n EDITOR_WEBSOCKET_PLUGIN_VERSION,\n ),\n \"Editor-Version\": source(\"editor-version\"),\n \"Copilot-Integration-Id\": source(\"copilot-integration-id\", \"vscode-chat\"),\n })\n\n setPreparedHeader(\n headers,\n \"Copilot-Vision-Request\",\n preparedHeaders,\n \"copilot-vision-request\",\n )\n\n headers[\"user-agent\"] = \"node\"\n\n return headers\n}\n\nconst createHeaderResolver =\n (headers: Record<string, string>) =>\n (headerName: string, fallback: string = \"\"): string =>\n getPreparedHeader(headers, headerName) ?? fallback\n\nconst getPreparedHeader = (\n headers: Record<string, string>,\n headerName: string,\n): string | undefined => {\n const normalizedHeaderName = headerName.toLowerCase()\n const match = Object.entries(headers).find(\n ([key]) => key.toLowerCase() === normalizedHeaderName,\n )\n\n return match?.[1]\n}\n\nconst setPreparedHeader = (\n target: Record<string, string>,\n targetHeaderName: string,\n source: Record<string, string>,\n sourceHeaderName: string,\n): void => {\n const value = getPreparedHeader(source, sourceHeaderName)\n if (value) {\n target[targetHeaderName] = value\n }\n}\n\nconst omitHeader = (\n headers: Record<string, string>,\n headerName: string,\n): Record<string, string> => {\n const normalizedHeaderName = headerName.toLowerCase()\n return Object.fromEntries(\n Object.entries(headers).filter(\n ([key]) => key.toLowerCase() !== normalizedHeaderName,\n ),\n )\n}\n\nconst githubCopilotHeaders = (\n account: AccountContext,\n vision: boolean = false,\n requestId?: string,\n): Record<string, string> => {\n const resolvedRequestId = requestId ?? randomUUID()\n const resolvedDeviceId = account.clientDeviceId ?? state.vsCodeDeviceId\n const resolvedMachineId = account.clientMachineId ?? state.macMachineId\n const resolvedSessionId = account.clientSessionId ?? state.vsCodeSessionId\n const headers: Record<string, string> = {\n Authorization: `Bearer ${account.copilotToken}`,\n \"content-type\": standardHeaders()[\"content-type\"],\n \"copilot-integration-id\": \"vscode-chat\",\n \"editor-version\": `vscode/${account.vsCodeVersion}`,\n \"editor-device-id\": resolvedDeviceId,\n \"editor-plugin-version\": EDITOR_PLUGIN_VERSION,\n \"user-agent\": USER_AGENT,\n \"openai-intent\": \"conversation-agent\",\n \"x-github-api-version\": API_VERSION,\n \"x-request-id\": resolvedRequestId,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n \"x-agent-task-id\": resolvedRequestId,\n \"x-interaction-type\": \"conversation-agent\",\n }\n\n if (vision) headers[\"copilot-vision-request\"] = \"true\"\n\n if (resolvedMachineId) {\n headers[\"vscode-machineid\"] = resolvedMachineId\n }\n\n if (resolvedSessionId) {\n headers[\"vscode-sessionid\"] = resolvedSessionId\n }\n\n return headers\n}\n\nexport const GITHUB_API_BASE_URL = \"https://api.github.com\"\nexport const githubHeaders = (\n account: AccountContext,\n): Record<string, string> => {\n if (isOpencodeOauthApp()) {\n return {\n Authorization: `Bearer ${account.githubToken}`,\n ...getOpencodeOauthHeaders(),\n }\n }\n\n return {\n authorization: `token ${account.githubToken}`,\n \"user-agent\": USER_AGENT,\n \"x-github-api-version\": API_VERSION,\n \"x-vscode-user-agent-library-version\": \"electron-fetch\",\n }\n}\n\nexport const GITHUB_BASE_URL = \"https://github.com\"\nexport const GITHUB_CLIENT_ID = \"Iv1.b507a08c87ecfe98\"\nexport const GITHUB_APP_SCOPES = [\"read:user\"].join(\" \")\nexport const OPENCODE_GITHUB_CLIENT_ID = \"Ov23li8tweQw6odWQebz\"\n","import type { Context } from \"hono\"\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\"\n\nimport consola from \"consola\"\n\nexport class HTTPError extends Error {\n response: Response\n\n constructor(message: string, response: Response) {\n super(message)\n this.response = response\n }\n}\n\nexport class CancelledError extends Error {}\n\nfunction getFallbackHttpErrorMessage(error: HTTPError): string {\n return error.message || `HTTP ${error.response.status}`\n}\n\nasync function readHttpErrorText(error: HTTPError): Promise<string> {\n try {\n const text = await error.response.text()\n return text || getFallbackHttpErrorMessage(error)\n } catch (readError) {\n consola.warn(\"Failed to read HTTP error response body:\", readError)\n return getFallbackHttpErrorMessage(error)\n }\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message || \"Unknown error\"\n }\n\n if (typeof error === \"string\") {\n return error\n }\n\n if (\n typeof error === \"number\"\n || typeof error === \"boolean\"\n || typeof error === \"bigint\"\n ) {\n return `${error}`\n }\n\n return \"Unknown error\"\n}\n\nexport async function forwardError(\n c: Context,\n error: unknown,\n): Promise<Response> {\n consola.error(\"Error occurred:\", error)\n\n if (error instanceof HTTPError) {\n if (error.response.status === 429) {\n for (const [name, value] of error.response.headers) {\n const lowerName = name.toLowerCase()\n if (lowerName === \"retry-after\" || lowerName.startsWith(\"x-\")) {\n c.header(name, value)\n }\n }\n }\n\n const errorText = await readHttpErrorText(error)\n let errorJson: unknown\n try {\n errorJson = JSON.parse(errorText)\n } catch {\n errorJson = errorText\n }\n consola.error(\"HTTP error:\", errorJson)\n return c.json(\n {\n error: {\n message: errorText,\n type: \"error\",\n },\n },\n error.response.status as ContentfulStatusCode,\n )\n }\n\n return c.json(\n {\n error: {\n message: getErrorMessage(error),\n type: \"error\",\n },\n },\n 500,\n )\n}\n","import consola from \"consola\"\nimport { getProxyForUrl } from \"proxy-from-env\"\nimport { Agent, ProxyAgent, setGlobalDispatcher, type Dispatcher } from \"undici\"\n\nlet proxyEnvDispatcher: Dispatcher | undefined\n\nexport function getProxyEnvDispatcher(): Dispatcher | undefined {\n return proxyEnvDispatcher\n}\n\nexport function initProxyFromEnv(): void {\n try {\n const direct = new Agent()\n const proxies = new Map<string, ProxyAgent>()\n\n // We only need a minimal dispatcher that implements `dispatch` at runtime.\n // Typing the object as `Dispatcher` forces TypeScript to require many\n // additional methods. Instead, keep a plain object and cast when passing\n // to `setGlobalDispatcher`.\n const dispatcher = {\n dispatch(\n options: Dispatcher.DispatchOptions,\n handler: Dispatcher.DispatchHandler,\n ) {\n try {\n const origin =\n typeof options.origin === \"string\" ?\n new URL(options.origin)\n : (options.origin as URL)\n const get = getProxyForUrl as unknown as (\n u: string,\n ) => string | undefined\n const raw = get(origin.toString())\n const proxyUrl = raw && raw.length > 0 ? raw : undefined\n if (!proxyUrl) {\n consola.debug(`HTTP proxy bypass: ${origin.hostname}`)\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n let agent = proxies.get(proxyUrl)\n if (!agent) {\n agent = new ProxyAgent(proxyUrl)\n proxies.set(proxyUrl, agent)\n }\n let label = proxyUrl\n try {\n const u = new URL(proxyUrl)\n label = `${u.protocol}//${u.host}`\n } catch {\n /* noop */\n }\n consola.debug(`HTTP proxy route: ${origin.hostname} via ${label}`)\n return agent.dispatch(options, handler)\n } catch {\n return (direct as unknown as Dispatcher).dispatch(options, handler)\n }\n },\n close() {\n return direct.close()\n },\n destroy() {\n return direct.destroy()\n },\n }\n\n proxyEnvDispatcher = dispatcher as unknown as Dispatcher\n\n if (typeof Bun !== \"undefined\") {\n consola.debug(\"WebSocket proxy configured from environment (per-URL)\")\n return\n }\n\n setGlobalDispatcher(proxyEnvDispatcher)\n consola.debug(\"HTTP proxy configured from environment (per-URL)\")\n } catch (err) {\n consola.debug(\"Proxy setup skipped:\", err)\n }\n}\n","import consola from \"consola\"\n\nimport type { AccountContext } from \"~/lib/types/account\"\n\nimport { getGitHubApiBaseUrl, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { accountFromState } from \"~/lib/state\"\n\nexport const getCopilotToken = async (account?: AccountContext) => {\n const ctx = account ?? accountFromState()\n const response = await fetch(\n `${getGitHubApiBaseUrl()}/copilot_internal/v2/token`,\n {\n headers: githubHeaders(ctx),\n },\n )\n\n if (!response.ok) {\n const errorText = await response.clone().text()\n consola.error(\"Failed to get Copilot token response body\", errorText)\n\n throw new HTTPError(\"Failed to get Copilot token\", response)\n }\n\n return (await response.json()) as GetCopilotTokenResponse\n}\n\n// Trimmed for the sake of simplicity\nexport interface GetCopilotTokenResponse {\n expires_at: number\n refresh_in: number\n token: string\n}\n","import type { AccountContext } from \"~/lib/types/account\"\n\nimport { getGitHubApiBaseUrl, githubHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { accountFromState } from \"~/lib/state\"\n\nexport const getCopilotUsage = async (\n account?: AccountContext,\n): Promise<CopilotUsageResponse> => {\n const ctx = account ?? accountFromState()\n const response = await fetch(\n `${getGitHubApiBaseUrl()}/copilot_internal/user`,\n {\n headers: githubHeaders(ctx),\n },\n )\n\n if (!response.ok) {\n throw new HTTPError(\"Failed to get Copilot usage\", response)\n }\n\n return (await response.json()) as CopilotUsageResponse\n}\n\nexport interface QuotaDetail {\n entitlement: number\n overage_count: number\n overage_permitted: boolean\n percent_remaining: number\n quota_id: string\n quota_remaining: number\n remaining: number\n unlimited: boolean\n}\n\ninterface QuotaSnapshots {\n chat: QuotaDetail\n completions: QuotaDetail\n premium_interactions: QuotaDetail\n}\n\ninterface CopilotUsageResponse {\n login: string\n access_type_sku: string\n analytics_tracking_id: string\n assigned_date: string\n can_signup_for_limited: boolean\n chat_enabled: boolean\n copilot_plan?: string\n organization_login_list: Array<unknown>\n organization_list: Array<unknown>\n quota_reset_date: string\n quota_snapshots: QuotaSnapshots\n endpoints: {\n api: string\n telemetry: string\n }\n}\n","import { getOauthAppConfig, getOauthUrls } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\n\nexport interface DeviceCodeOptions {\n overrideUrls?: {\n deviceCodeUrl: string\n accessTokenUrl: string\n }\n}\n\nexport async function getDeviceCode(\n options?: DeviceCodeOptions,\n): Promise<DeviceCodeResponse> {\n const { clientId, headers, scope } = getOauthAppConfig()\n const { deviceCodeUrl } = options?.overrideUrls ?? getOauthUrls()\n\n const response = await fetch(deviceCodeUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n client_id: clientId,\n scope,\n }),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get device code\", response)\n\n return (await response.json()) as DeviceCodeResponse\n}\n\nexport interface DeviceCodeResponse {\n device_code: string\n user_code: string\n verification_uri: string\n expires_in: number\n interval: number\n}\n","import type { AccountContext } from \"~/lib/types/account\"\n\nimport { getGitHubApiBaseUrl, githubUserHeaders } from \"~/lib/api-config\"\nimport { HTTPError } from \"~/lib/error\"\nimport { accountFromState, state } from \"~/lib/state\"\n\nconst resolveGitHubUserAccount = (account?: AccountContext): AccountContext => {\n if (account) {\n return account\n }\n\n if (!state.githubToken) {\n throw new Error(\"GitHub token not set\")\n }\n\n return accountFromState()\n}\n\nexport async function getGitHubUser(account?: AccountContext) {\n const resolvedAccount = resolveGitHubUserAccount(account)\n\n const response = await fetch(`${getGitHubApiBaseUrl()}/user`, {\n headers: githubUserHeaders(resolvedAccount),\n })\n\n if (!response.ok) throw new HTTPError(\"Failed to get GitHub user\", response)\n\n return (await response.json()) as GithubUserResponse\n}\n\n// Trimmed for the sake of simplicity\nexport interface GithubUserResponse {\n login: string\n}\n","const FALLBACK = \"1.122.1\"\n\nexport async function getVSCodeVersion() {\n await Promise.resolve()\n return FALLBACK\n}\n","import consola from \"consola\"\nimport { randomUUID } from \"node:crypto\"\nimport path from \"node:path\"\n\nconst WINDOWS_DEVICE_ID_KEY = String.raw`\\SOFTWARE\\Microsoft\\DeveloperTools`\nconst WINDOWS_DEVICE_ID_NAME = \"deviceid\"\n\ntype RegistryArch = \"x86\" | \"x64\"\n\ninterface WinregConstructor {\n new (options: {\n hive: string\n key: string\n arch?: RegistryArch\n }): WinregRegistry\n HKCU: string\n REG_SZ: string\n}\n\ninterface WinregRegistry {\n get(\n name: string,\n callback: (error: RegistryError | null, item: RegistryItem | null) => void,\n ): void\n set(\n name: string,\n type: string,\n value: string,\n callback: (error: RegistryError | null) => void,\n ): void\n}\n\ninterface RegistryItem {\n value?: string\n}\n\ninterface RegistryError extends Error {\n code?: number | string\n}\n\nconst windows64Architectures = new Set([\"AMD64\", \"ARM64\", \"IA64\"])\n\nconst getPosixHomeDir = (): string => {\n if (!process.env.HOME) {\n throw new Error(\"Home directory not found\")\n }\n\n return process.env.HOME\n}\n\nconst getDeviceIdFilePath = (): string => {\n let folder: string\n\n switch (process.platform) {\n case \"darwin\": {\n folder = path.posix.join(\n getPosixHomeDir(),\n \"Library\",\n \"Application Support\",\n )\n break\n }\n case \"linux\": {\n folder =\n process.env.XDG_CACHE_HOME\n ?? path.posix.join(getPosixHomeDir(), \".cache\")\n break\n }\n default: {\n throw new Error(\"Unsupported platform\")\n }\n }\n\n return path.posix.join(folder, \"Microsoft\", \"DeveloperTools\", \"deviceid\")\n}\n\nconst isMissingFileError = (error: unknown): error is NodeJS.ErrnoException => {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\"\n}\n\nconst readStoredDeviceIdFile = async (\n filePath: string,\n): Promise<string | undefined> => {\n const { readFile } = await import(\"node:fs/promises\")\n\n try {\n return await readFile(filePath, \"utf8\")\n } catch (error) {\n if (isMissingFileError(error)) {\n return undefined\n }\n\n throw error\n }\n}\n\nconst writeStoredDeviceIdFile = async (\n filePath: string,\n deviceId: string,\n): Promise<void> => {\n const { mkdir, writeFile } = await import(\"node:fs/promises\")\n\n await mkdir(path.posix.dirname(filePath), { recursive: true })\n await writeFile(filePath, deviceId, \"utf8\")\n}\n\nconst getWindowsRegistryArch = (): RegistryArch | undefined => {\n const architecture = (\n process.env.PROCESSOR_ARCHITEW6432 ?? process.env.PROCESSOR_ARCHITECTURE\n )?.toUpperCase()\n\n return architecture && windows64Architectures.has(architecture) ?\n \"x64\"\n : undefined\n}\n\nconst loadWinreg = async (): Promise<WinregConstructor> => {\n const module = await import(\"winreg\")\n const winreg =\n \"default\" in module ? (module.default as unknown) : (module as unknown)\n\n return winreg as WinregConstructor\n}\n\nconst isMissingRegistryError = (error: RegistryError | null): boolean => {\n if (!error) {\n return false\n }\n\n const errorCode = Number(error.code)\n\n return Number.isFinite(errorCode) && errorCode === 1\n}\n\nconst createWindowsRegistry = async (): Promise<{\n registry: WinregRegistry\n regSz: string\n}> => {\n const Winreg = await loadWinreg()\n\n return {\n registry: new Winreg({\n hive: Winreg.HKCU,\n key: WINDOWS_DEVICE_ID_KEY,\n arch: getWindowsRegistryArch(),\n }),\n regSz: Winreg.REG_SZ,\n }\n}\n\nconst readRegistryString = async (\n registry: WinregRegistry,\n name: string,\n): Promise<string | undefined> => {\n return new Promise((resolve, reject) => {\n registry.get(name, (error, item) => {\n if (isMissingRegistryError(error)) {\n resolve(undefined)\n return\n }\n\n if (error) {\n reject(\n error instanceof Error ? error : new Error(\"Unknown registry error\"),\n )\n return\n }\n\n resolve(item?.value)\n })\n })\n}\n\nconst writeRegistryString = async ({\n registry,\n regSz,\n name,\n value,\n}: {\n registry: WinregRegistry\n regSz: string\n name: string\n value: string\n}): Promise<void> => {\n return new Promise((resolve, reject) => {\n registry.set(name, regSz, value, (error) => {\n if (error) {\n reject(\n error instanceof Error ? error : new Error(\"Unknown registry error\"),\n )\n return\n }\n\n resolve()\n })\n })\n}\n\nexport const getStoredVSCodeDeviceId = async (): Promise<\n string | undefined\n> => {\n switch (process.platform) {\n case \"win32\": {\n const { registry } = await createWindowsRegistry()\n\n return readRegistryString(registry, WINDOWS_DEVICE_ID_NAME)\n }\n case \"darwin\":\n case \"linux\": {\n return readStoredDeviceIdFile(getDeviceIdFilePath())\n }\n default: {\n throw new Error(\"Unsupported platform\")\n }\n }\n}\n\nconst setStoredVSCodeDeviceId = async (deviceId: string): Promise<void> => {\n switch (process.platform) {\n case \"win32\": {\n const { registry, regSz } = await createWindowsRegistry()\n\n await writeRegistryString({\n registry,\n regSz,\n name: WINDOWS_DEVICE_ID_NAME,\n value: deviceId,\n })\n return\n }\n case \"darwin\":\n case \"linux\": {\n await writeStoredDeviceIdFile(getDeviceIdFilePath(), deviceId)\n return\n }\n default: {\n throw new Error(\"Unsupported platform\")\n }\n }\n}\n\nconst createVSCodeDeviceId = (): string => randomUUID().toLowerCase()\n\nexport async function getVSCodeDeviceId(): Promise<string> {\n let deviceId: string | undefined\n\n try {\n deviceId = await getStoredVSCodeDeviceId()\n } catch (error) {\n consola.debug(\"Failed to read VSCode device id\", error)\n }\n\n if (deviceId) {\n return deviceId\n }\n\n const newDeviceId = createVSCodeDeviceId()\n\n try {\n await setStoredVSCodeDeviceId(newDeviceId)\n } catch (error) {\n consola.warn(\n \"Failed to persist VSCode device id, using ephemeral id\",\n error,\n )\n }\n\n return newDeviceId\n}\n","import type { Context } from \"hono\"\n\nimport consola from \"consola\"\nimport { createHash, randomUUID } from \"node:crypto\"\nimport { networkInterfaces } from \"node:os\"\n\nimport type { AnthropicMessagesPayload } from \"~/routes/messages/anthropic-types\"\n\nimport { getVSCodeVersion } from \"~/services/get-vscode-version\"\n\nimport { getVSCodeDeviceId } from \"./deviceid\"\nimport { state } from \"./state\"\n\nexport const sleep = (ms: number) =>\n new Promise((resolve) => {\n setTimeout(resolve, ms)\n })\n\nexport const isNullish = (value: unknown): value is null | undefined =>\n value === null || value === undefined\n\nexport const cacheVSCodeVersion = async () => {\n const response = await getVSCodeVersion()\n state.vsCodeVersion = response\n\n consola.info(`Using VSCode version: ${response}`)\n}\n\nconst invalidMacAddresses = new Set([\n \"00:00:00:00:00:00\",\n \"ff:ff:ff:ff:ff:ff\",\n \"ac:de:48:00:11:22\",\n])\n\nfunction validateMacAddress(candidate: string): boolean {\n const tempCandidate = candidate.replaceAll(\"-\", \":\").toLowerCase()\n return !invalidMacAddresses.has(tempCandidate)\n}\n\nexport function getMac(): string | null {\n const ifaces = networkInterfaces()\n // eslint-disable-next-line guard-for-in\n for (const name in ifaces) {\n const networkInterface = ifaces[name]\n if (networkInterface) {\n for (const { mac } of networkInterface) {\n if (validateMacAddress(mac)) {\n return mac\n }\n }\n }\n }\n return null\n}\n\nexport const cacheMacMachineId = () => {\n const macAddress = getMac() ?? randomUUID()\n state.macMachineId = createHash(\"sha256\")\n .update(macAddress, \"utf8\")\n .digest(\"hex\")\n consola.debug(`Using machine ID: ${state.macMachineId}`)\n}\n\nexport const cacheVsCodeDeviceId = async () => {\n state.vsCodeDeviceId = await getVSCodeDeviceId()\n consola.debug(`Using VSCode device ID: ${state.vsCodeDeviceId}`)\n}\n\nconst SESSION_REFRESH_BASE_MS = 60 * 60 * 1000\nconst SESSION_REFRESH_JITTER_MS = 20 * 60 * 1000\nlet vsCodeSessionRefreshTimer: ReturnType<typeof setTimeout> | null = null\n\nconst generateSessionId = () => {\n state.vsCodeSessionId = randomUUID() + Date.now().toString()\n consola.debug(`Generated VSCode session ID: ${state.vsCodeSessionId}`)\n}\n\nexport const stopVsCodeSessionRefreshLoop = () => {\n if (vsCodeSessionRefreshTimer) {\n clearTimeout(vsCodeSessionRefreshTimer)\n vsCodeSessionRefreshTimer = null\n }\n}\n\nconst scheduleSessionIdRefresh = () => {\n const randomDelay = Math.floor(Math.random() * SESSION_REFRESH_JITTER_MS)\n const delay = SESSION_REFRESH_BASE_MS + randomDelay\n consola.debug(\n `Scheduling next VSCode session ID refresh in ${Math.round(\n delay / 1000,\n )} seconds`,\n )\n\n stopVsCodeSessionRefreshLoop()\n vsCodeSessionRefreshTimer = setTimeout(() => {\n try {\n generateSessionId()\n } catch (error) {\n consola.error(\"Failed to refresh session ID, rescheduling...\", error)\n } finally {\n scheduleSessionIdRefresh()\n }\n }, delay)\n}\n\nexport const cacheVsCodeSessionId = () => {\n stopVsCodeSessionRefreshLoop()\n generateSessionId()\n scheduleSessionIdRefresh()\n}\n\ninterface PayloadMessage {\n role?: string\n content?: string | Array<{ type?: string; text?: string }> | null\n type?: string\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null\n\nconst getUserIdJsonField = (\n userIdPayload: Record<string, unknown> | null,\n field: string,\n): string | null => {\n const value = userIdPayload?.[field]\n return typeof value === \"string\" && value.length > 0 ? value : null\n}\n\nconst parseJsonUserId = (userId: string): Record<string, unknown> | null => {\n try {\n const parsed: unknown = JSON.parse(userId)\n return isRecord(parsed) ? parsed : null\n } catch {\n return null\n }\n}\n\nexport const parseUserIdMetadata = (\n userId: string | undefined,\n): { safetyIdentifier: string | null; sessionId: string | null } => {\n if (!userId || typeof userId !== \"string\") {\n return { safetyIdentifier: null, sessionId: null }\n }\n\n const legacySafetyIdentifier =\n userId.match(/user_([^_]+)_account/)?.[1] ?? null\n const legacySessionId = userId.match(/_session_(.+)$/)?.[1] ?? null\n\n const parsedUserId =\n legacySafetyIdentifier && legacySessionId ? null : parseJsonUserId(userId)\n\n const safetyIdentifier =\n legacySafetyIdentifier\n ?? getUserIdJsonField(parsedUserId, \"device_id\")\n ?? getUserIdJsonField(parsedUserId, \"account_uuid\")\n const sessionId =\n legacySessionId ?? getUserIdJsonField(parsedUserId, \"session_id\")\n\n return { safetyIdentifier, sessionId }\n}\n\nconst findLastUserContent = (\n messages: Array<PayloadMessage>,\n): string | null => {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]\n if (msg.role === \"user\" && msg.content) {\n if (typeof msg.content === \"string\") {\n return msg.content\n } else if (Array.isArray(msg.content)) {\n const array = msg.content\n .filter((n) => n.type !== \"tool_result\")\n .map((n) => ({ ...n, cache_control: undefined }))\n if (array.length > 0) {\n return JSON.stringify(array)\n }\n }\n }\n }\n return null\n}\n\nexport const generateRequestIdFromPayload = (\n payload: {\n messages: string | Array<PayloadMessage> | undefined\n },\n sessionId?: string,\n): string => {\n const messages = payload.messages\n if (messages) {\n const lastUserContent =\n typeof messages === \"string\" ? messages : findLastUserContent(messages)\n\n if (lastUserContent) {\n return getUUID((sessionId ?? \"\") + lastUserContent)\n }\n }\n\n return randomUUID()\n}\n\nexport const normalizeStableSessionId = (\n sessionId?: string | null,\n): string | undefined => {\n const trimmedSessionId = sessionId?.trim()\n return trimmedSessionId ? getUUID(trimmedSessionId) : undefined\n}\n\nexport const getRootSessionId = (\n anthropicPayload: AnthropicMessagesPayload,\n c: Context,\n): string | undefined => {\n const userId = anthropicPayload.metadata?.user_id\n const sessionId =\n userId ?\n parseUserIdMetadata(userId).sessionId || undefined\n : c.req.header(\"x-session-id\")\n\n return normalizeStableSessionId(sessionId)\n}\n\nexport const getUUID = (content: string): string => {\n const uuidBytes = createHash(\"sha256\")\n .update(content)\n .digest()\n .subarray(0, 16)\n\n uuidBytes[6] = (uuidBytes[6] & 0x0f) | 0x40\n uuidBytes[8] = (uuidBytes[8] & 0x3f) | 0x80\n\n const uuidHex = uuidBytes.toString(\"hex\")\n\n return `${uuidHex.slice(0, 8)}-${uuidHex.slice(8, 12)}-${uuidHex.slice(12, 16)}-${uuidHex.slice(16, 20)}-${uuidHex.slice(20)}`\n}\n\nexport type AffinityKeySource =\n | \"prompt_cache_key\"\n | \"metadata_session_id\"\n | \"x_session_id\"\n | \"upstream_request_id_fallback\"\n\nexport interface ResolvedAffinityKey {\n requestId: string\n affinityKeyUsed: string\n affinityKeySource: AffinityKeySource\n}\n\n/**\n * Unified affinity key resolution with fixed priority:\n * 1. payload.prompt_cache_key (used as-is)\n * 2. metadata.user_id.session_id (normalized via getUUID)\n * 3. x-session-id header (normalized via getUUID)\n * 4. generateRequestIdFromPayload fallback (used as-is)\n */\nexport const resolveAffinityKey = (params: {\n promptCacheKey?: string | null\n metadataSessionId?: string | null\n headerSessionId?: string | null\n upstreamRequestId: string\n}): ResolvedAffinityKey => {\n const {\n promptCacheKey,\n metadataSessionId,\n headerSessionId,\n upstreamRequestId,\n } = params\n\n if (promptCacheKey) {\n return {\n requestId: promptCacheKey,\n affinityKeyUsed: promptCacheKey,\n affinityKeySource: \"prompt_cache_key\",\n }\n }\n\n if (metadataSessionId) {\n return {\n requestId: getUUID(metadataSessionId),\n affinityKeyUsed: metadataSessionId,\n affinityKeySource: \"metadata_session_id\",\n }\n }\n\n if (headerSessionId) {\n return {\n requestId: getUUID(headerSessionId),\n affinityKeyUsed: headerSessionId,\n affinityKeySource: \"x_session_id\",\n }\n }\n\n return {\n requestId: upstreamRequestId,\n affinityKeyUsed: upstreamRequestId,\n affinityKeySource: \"upstream_request_id_fallback\",\n }\n}\n","import consola from \"consola\"\n\nimport { getOauthAppConfig, getOauthUrls } from \"~/lib/api-config\"\nimport { CancelledError } from \"~/lib/error\"\nimport { sleep } from \"~/lib/utils\"\n\nimport type { DeviceCodeResponse } from \"./get-device-code\"\n\nexport interface PollAccessTokenOptions {\n overrideUrls?: {\n deviceCodeUrl: string\n accessTokenUrl: string\n }\n signal?: AbortSignal\n}\n\nexport async function pollAccessToken(\n deviceCode: DeviceCodeResponse,\n options?: PollAccessTokenOptions,\n): Promise<string> {\n const { clientId, headers } = getOauthAppConfig()\n const { accessTokenUrl } = options?.overrideUrls ?? getOauthUrls()\n\n // Interval is in seconds, we need to multiply by 1000 to get milliseconds\n // I'm also adding another second, just to be safe\n const sleepDuration = (deviceCode.interval + 1) * 1000\n consola.debug(`Polling access token with interval of ${sleepDuration}ms`)\n\n while (true) {\n if (options?.signal?.aborted) {\n throw new CancelledError(\"Authentication cancelled\")\n }\n\n const response = await fetch(accessTokenUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify({\n client_id: clientId,\n device_code: deviceCode.device_code,\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n }),\n signal: options?.signal,\n })\n\n if (!response.ok) {\n await sleep(sleepDuration)\n consola.error(\"Failed to poll access token:\", await response.text())\n\n continue\n }\n\n const json = await response.json()\n consola.debug(\"Polling access token response:\", json)\n\n const { access_token } = json as AccessTokenResponse\n\n if (access_token) {\n return access_token\n } else {\n await sleep(sleepDuration)\n }\n }\n}\n\ninterface AccessTokenResponse {\n access_token: string\n token_type: string\n scope: string\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { i as getRequestOutboundStore } from "./request-outbound-Pu1kp2x8.js";
1
+ import { i as getRequestOutboundStore } from "./request-outbound-DZTxxtcx.js";
2
2
  export { getRequestOutboundStore };
@@ -1,8 +1,8 @@
1
- import { t as PATHS } from "./paths-CclKwouX.js";
1
+ import { t as PATHS } from "./paths-Bpsb62LK.js";
2
2
  import consola from "consola";
3
3
  import path from "node:path";
4
- import { Database } from "bun:sqlite";
5
4
  import fs from "node:fs";
5
+ import { Database } from "bun:sqlite";
6
6
  //#region src/lib/admin-db.ts
7
7
  const DEFAULT_DB_PATH = path.join(PATHS.APP_DIR, "admin.sqlite");
8
8
  let sharedDb = null;
@@ -515,4 +515,4 @@ function getRequestOutboundStore() {
515
515
  //#endregion
516
516
  export { redactHeaders as a, getAdminDbUserVersion as c, getRequestOutboundStore as i, createRequestOutboundStore as n, getAdminDb as o, getRedactedHeaderKeys as r, getAdminDbPath as s, SENSITIVE_HEADER_PATTERNS as t };
517
517
 
518
- //# sourceMappingURL=request-outbound-Pu1kp2x8.js.map
518
+ //# sourceMappingURL=request-outbound-DZTxxtcx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-outbound-Pu1kp2x8.js","names":[],"sources":["../src/lib/admin-db.ts","../src/lib/request-outbound.ts"],"sourcesContent":["import { Database } from \"bun:sqlite\"\nimport consola from \"consola\"\nimport fs from \"node:fs\"\nimport path from \"node:path\"\n\nimport { PATHS } from \"./paths\"\n\nconst ADMIN_DB_FILENAME = \"admin.sqlite\"\nconst DEFAULT_DB_PATH = path.join(PATHS.APP_DIR, ADMIN_DB_FILENAME)\n\nlet sharedDb: Database | null = null\nlet initialized = false\n\nconst INIT_WARN_THROTTLE_MS = 30_000\n\nlet lastInitWarnAtMs = 0\nlet suppressedInitWarnCount = 0\n\nfunction warnAdminDbInitFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastInitWarnAtMs < INIT_WARN_THROTTLE_MS) {\n suppressedInitWarnCount++\n return\n }\n\n const suppressed = suppressedInitWarnCount\n suppressedInitWarnCount = 0\n lastInitWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(\n `Failed to initialize admin DB; admin features disabled${suffix}`,\n error,\n )\n}\n\nexport function getAdminDbPath(): string {\n return DEFAULT_DB_PATH\n}\n\nexport function openAdminDb(filePath: string = DEFAULT_DB_PATH): Database {\n if (filePath !== \":memory:\") {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n }\n\n return new Database(filePath)\n}\n\nexport function initAdminDb(db: Database): void {\n // Pragmas: prefer WAL for concurrent reads, keep writes fast.\n // Note: journal_mode=WAL is per-database and persists in the DB file.\n db.run(\"PRAGMA journal_mode = WAL;\")\n db.run(\"PRAGMA synchronous = NORMAL;\")\n db.run(\"PRAGMA busy_timeout = 3000;\")\n db.run(\"PRAGMA foreign_keys = ON;\")\n\n migrateAdminDb(db)\n}\n\nexport function getAdminDb(): Database {\n if (!sharedDb) {\n sharedDb = openAdminDb()\n }\n if (!initialized) {\n try {\n initAdminDb(sharedDb)\n initialized = true\n } catch (error) {\n // Admin DB is a best-effort feature; server should continue to run.\n warnAdminDbInitFailure(error)\n }\n }\n return sharedDb\n}\n\nexport function getAdminDbUserVersion(db: Database = getAdminDb()): number {\n try {\n const row = db.query(\"PRAGMA user_version;\").get() as {\n user_version?: number\n } | null\n return row?.user_version ?? 0\n } catch {\n return 0\n }\n}\n\nfunction hasRequestLogColumn(db: Database, columnName: string): boolean {\n return db\n .query(\"PRAGMA table_info(request_log);\")\n .all()\n .some((row) => (row as { name?: string }).name === columnName)\n}\n\nfunction migrateV1(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS request_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n request_id TEXT NOT NULL UNIQUE,\n\n started_at_ms INTEGER NOT NULL,\n finished_at_ms INTEGER,\n duration_ms INTEGER,\n ttfb_ms INTEGER,\n\n method TEXT NOT NULL,\n path TEXT NOT NULL,\n upstream_endpoint TEXT,\n stream INTEGER NOT NULL DEFAULT 0,\n\n account_id TEXT,\n account_type TEXT,\n cost_units REAL,\n client_model TEXT,\n upstream_model TEXT,\n\n client_ip TEXT,\n client_ip_source TEXT,\n user_agent TEXT,\n\n tokens_input INTEGER,\n tokens_output INTEGER,\n tokens_total INTEGER,\n tokens_cached_input INTEGER,\n usage_json TEXT,\n\n premium_remaining_before REAL,\n premium_remaining_after REAL,\n premium_remaining_diff REAL,\n premium_unlimited_before INTEGER,\n premium_unlimited_after INTEGER,\n\n http_status INTEGER,\n error_name TEXT,\n error_status INTEGER,\n error_message TEXT,\n selection_failure_reason TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_request_log_started_at\n ON request_log(started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_account_started_at\n ON request_log(account_id, started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_model_started_at\n ON request_log(upstream_model, started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_endpoint_started_at\n ON request_log(upstream_endpoint, started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_status_started_at\n ON request_log(http_status, started_at_ms DESC);\n\n PRAGMA user_version = 1;\n `)\n}\n\nfunction migrateV9(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS daily_premium_stats (\n date TEXT NOT NULL,\n account_id TEXT NOT NULL,\n request_count INTEGER NOT NULL DEFAULT 0,\n cost_units_sum REAL NOT NULL DEFAULT 0,\n tokens_total INTEGER NOT NULL DEFAULT 0,\n error_count INTEGER NOT NULL DEFAULT 0,\n updated_at_ms INTEGER NOT NULL,\n PRIMARY KEY (date, account_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_daily_premium_stats_date\n ON daily_premium_stats(date);\n `)\n\n // Backfill from existing request_log (guard: table may not exist in edge cases)\n const hasRequestLog = db\n .query(\n \"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'request_log' LIMIT 1;\",\n )\n .get()\n\n if (hasRequestLog) {\n const nowMs = Date.now()\n db.run(\n `INSERT INTO daily_premium_stats\n (date, account_id, request_count, cost_units_sum, tokens_total, error_count, updated_at_ms)\n SELECT\n date(started_at_ms / 1000, 'unixepoch', 'localtime') AS date,\n account_id,\n COUNT(*) AS request_count,\n SUM(cost_units) AS cost_units_sum,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n SUM(CASE WHEN error_name IS NOT NULL THEN 1 ELSE 0 END) AS error_count,\n ? AS updated_at_ms\n FROM request_log\n WHERE cost_units > 0\n AND account_id IS NOT NULL\n GROUP BY 1, 2\n ON CONFLICT(date, account_id) DO UPDATE SET\n request_count = excluded.request_count,\n cost_units_sum = excluded.cost_units_sum,\n tokens_total = excluded.tokens_total,\n error_count = excluded.error_count,\n updated_at_ms = excluded.updated_at_ms;`,\n [nowMs],\n )\n }\n\n db.run(\"PRAGMA user_version = 9;\")\n}\n\nfunction migrateV8(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS session_affinity (\n cache_key TEXT PRIMARY KEY,\n account_id TEXT NOT NULL,\n created_at_ms INTEGER NOT NULL,\n last_confirmed_at_ms INTEGER NOT NULL,\n last_used_at_ms INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_session_affinity_last_used\n ON session_affinity(last_used_at_ms);\n\n CREATE INDEX IF NOT EXISTS idx_session_affinity_account\n ON session_affinity(account_id);\n\n PRAGMA user_version = 8;\n `)\n}\n\nfunction migrateV10(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS quota_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n account_id TEXT NOT NULL,\n snapshot_at_ms INTEGER NOT NULL,\n remaining INTEGER NOT NULL,\n entitlement INTEGER NOT NULL,\n unlimited INTEGER NOT NULL DEFAULT 0,\n source TEXT NOT NULL DEFAULT 'refresh'\n );\n\n CREATE INDEX IF NOT EXISTS idx_quota_snapshots_account_time\n ON quota_snapshots(account_id, snapshot_at_ms);\n\n CREATE INDEX IF NOT EXISTS idx_quota_snapshots_time\n ON quota_snapshots(snapshot_at_ms);\n `)\n\n const hasRequestLog = db\n .query(\n \"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'request_log' LIMIT 1;\",\n )\n .get()\n\n if (hasRequestLog) {\n db.run(`\n INSERT INTO quota_snapshots\n (account_id, snapshot_at_ms, remaining, entitlement, unlimited, source)\n SELECT\n account_id,\n finished_at_ms,\n CAST(premium_remaining_after AS INTEGER),\n 0,\n COALESCE(premium_unlimited_after, 0),\n 'backfill'\n FROM request_log\n WHERE premium_remaining_after IS NOT NULL\n AND account_id IS NOT NULL\n AND finished_at_ms IS NOT NULL\n ORDER BY finished_at_ms;\n `)\n }\n\n db.run(\"PRAGMA user_version = 10;\")\n}\n\nfunction migrateV11(db: Database): void {\n const outboundHeaderColumns = [\n \"outbound_x_request_id\",\n \"outbound_x_agent_task_id\",\n \"outbound_x_interaction_type\",\n \"outbound_openai_intent\",\n \"outbound_user_agent\",\n ] as const\n\n for (const columnName of outboundHeaderColumns) {\n if (!hasRequestLogColumn(db, columnName)) {\n db.run(`ALTER TABLE request_log ADD COLUMN ${columnName} TEXT;`)\n }\n }\n\n db.run(`\n CREATE TABLE IF NOT EXISTS request_outbound (\n request_id TEXT PRIMARY KEY,\n captured_at_ms INTEGER NOT NULL,\n http_status INTEGER NOT NULL,\n\n upstream_url TEXT NOT NULL,\n upstream_method TEXT NOT NULL,\n\n request_headers TEXT NOT NULL,\n request_body TEXT,\n request_body_kind TEXT NOT NULL,\n\n response_status INTEGER NOT NULL,\n response_headers TEXT NOT NULL,\n response_body TEXT,\n response_body_kind TEXT NOT NULL,\n\n FOREIGN KEY (request_id) REFERENCES request_log(request_id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_request_outbound_captured_at\n ON request_outbound(captured_at_ms DESC);\n\n PRAGMA user_version = 11;\n `)\n}\n\nfunction migrateV12(db: Database): void {\n if (!hasRequestLogColumn(db, \"outbound_x_interaction_id\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN outbound_x_interaction_id TEXT;\")\n }\n\n db.run(\"PRAGMA user_version = 12;\")\n}\n\nfunction migrateV13(db: Database): void {\n if (!hasRequestLogColumn(db, \"responses_item_owner_lookup_keys_json\")) {\n db.run(\n \"ALTER TABLE request_log ADD COLUMN responses_item_owner_lookup_keys_json TEXT;\",\n )\n }\n\n if (!hasRequestLogColumn(db, \"responses_item_owner_recorded_keys_json\")) {\n db.run(\n \"ALTER TABLE request_log ADD COLUMN responses_item_owner_recorded_keys_json TEXT;\",\n )\n }\n\n db.run(\"PRAGMA user_version = 13;\")\n}\n\nfunction migrateV8ToV13(db: Database, current: number): void {\n if (current < 8) {\n migrateV8(db)\n }\n\n if (current < 9) {\n migrateV9(db)\n }\n\n if (current < 10) {\n migrateV10(db)\n }\n\n if (current < 11) {\n migrateV11(db)\n }\n\n if (current < 12) {\n migrateV12(db)\n }\n\n if (current < 13) {\n migrateV13(db)\n }\n}\n\n// eslint-disable-next-line complexity -- migration chain grows with each version\nfunction migrateAdminDb(db: Database): void {\n const row = db.query(\"PRAGMA user_version;\").get() as {\n user_version?: number\n } | null\n const current = row?.user_version ?? 0\n\n if (current >= 13) {\n if (current === 13) migrateV13(db)\n return\n }\n\n if (current === 12) {\n migrateV12(db)\n }\n\n if (current === 11) {\n migrateV11(db)\n }\n\n if (current < 1) {\n migrateV1(db)\n }\n\n if (current < 2) {\n // v2: request_log session correlation fields\n db.run(`\n ALTER TABLE request_log ADD COLUMN user_id TEXT;\n ALTER TABLE request_log ADD COLUMN safety_identifier TEXT;\n ALTER TABLE request_log ADD COLUMN prompt_cache_key TEXT;\n ALTER TABLE request_log ADD COLUMN initiator TEXT;\n ALTER TABLE request_log ADD COLUMN upstream_request_id TEXT;\n\n PRAGMA user_version = 2;\n `)\n }\n\n if (current < 3) {\n // v3: index for session lookup\n db.run(`\n CREATE INDEX IF NOT EXISTS idx_request_log_session_finished\n ON request_log(\n prompt_cache_key,\n safety_identifier,\n finished_at_ms DESC\n )\n WHERE finished_at_ms IS NOT NULL\n AND tokens_input IS NOT NULL;\n\n PRAGMA user_version = 3;\n `)\n }\n\n if (current < 4) {\n // v4: index for session lookup by client model\n db.run(`\n CREATE INDEX IF NOT EXISTS idx_request_log_session_finished_by_client_model\n ON request_log(\n prompt_cache_key,\n safety_identifier,\n client_model,\n finished_at_ms DESC\n )\n WHERE finished_at_ms IS NOT NULL\n AND tokens_input IS NOT NULL;\n\n PRAGMA user_version = 4;\n `)\n }\n\n if (current < 5) {\n // v5: account affinity tracking columns\n db.run(`\n ALTER TABLE request_log ADD COLUMN affinity_hit INTEGER;\n ALTER TABLE request_log ADD COLUMN affinity_cache_key TEXT;\n\n PRAGMA user_version = 5;\n `)\n }\n\n if (current < 6) {\n // v6: explicit subagent request tracking column\n if (!hasRequestLogColumn(db, \"is_subagent\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN is_subagent INTEGER;\")\n }\n\n db.run(\"PRAGMA user_version = 6;\")\n }\n\n if (current < 7) {\n // v7: request-level affinity and upstream error observability columns\n if (!hasRequestLogColumn(db, \"affinity_key_used\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN affinity_key_used TEXT;\")\n }\n\n if (!hasRequestLogColumn(db, \"affinity_key_source\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN affinity_key_source TEXT;\")\n }\n\n if (!hasRequestLogColumn(db, \"selection_reason\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN selection_reason TEXT;\")\n }\n\n if (!hasRequestLogColumn(db, \"upstream_error_message_raw\")) {\n db.run(\n \"ALTER TABLE request_log ADD COLUMN upstream_error_message_raw TEXT;\",\n )\n }\n\n db.run(\"PRAGMA user_version = 7;\")\n }\n\n migrateV8ToV13(db, current)\n}\n","import type { Database } from \"bun:sqlite\"\n\nimport consola from \"consola\"\n\nimport { getAdminDb, getAdminDbPath, getAdminDbUserVersion } from \"./admin-db\"\n\nconst INSERT_WARN_THROTTLE_MS = 30_000\nconst STORE_INIT_WARN_THROTTLE_MS = 30_000\nconst STORE_INIT_RETRY_DELAY_MS = 30_000\n\nlet lastInsertWarnAtMs = 0\nlet suppressedInsertWarnCount = 0\nlet lastStoreInitWarnAtMs = 0\nlet suppressedStoreInitWarnCount = 0\nlet nextStoreRetryAtMs = 0\n\nexport const SENSITIVE_HEADER_PATTERNS = [\n /^authorization$/i,\n /^x-github-token$/i,\n /^cookie$/i,\n /^set-cookie$/i,\n /^proxy-authorization$/i,\n /^x-api-key$/i,\n /-token$/i,\n /-secret$/i,\n] as const\n\nfunction warnInsertFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastInsertWarnAtMs < INSERT_WARN_THROTTLE_MS) {\n suppressedInsertWarnCount++\n return\n }\n\n const suppressed = suppressedInsertWarnCount\n suppressedInsertWarnCount = 0\n lastInsertWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Failed to insert request outbound${suffix}`, error)\n}\n\nfunction warnStoreInitFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastStoreInitWarnAtMs < STORE_INIT_WARN_THROTTLE_MS) {\n suppressedStoreInitWarnCount++\n return\n }\n\n const suppressed = suppressedStoreInitWarnCount\n suppressedStoreInitWarnCount = 0\n lastStoreInitWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Request outbound store is disabled${suffix}`, error)\n}\n\ntype HeaderMap = Record<string, string>\n\nfunction shouldRedactHeader(key: string): boolean {\n return SENSITIVE_HEADER_PATTERNS.some((pattern) => pattern.test(key))\n}\n\nexport function getRedactedHeaderKeys(headers: HeaderMap): Array<string> {\n return Object.keys(headers).filter((key) => shouldRedactHeader(key))\n}\n\nexport function redactHeaders(headers: HeaderMap): HeaderMap {\n const redacted: HeaderMap = {}\n\n for (const [key, value] of Object.entries(headers)) {\n redacted[key] = shouldRedactHeader(key) ? \"***\" : value\n }\n\n return redacted\n}\n\nexport type OutboundCaptureInput = {\n requestId: string\n httpStatus: number\n upstreamUrl: string\n upstreamMethod: string\n requestHeaders: HeaderMap\n requestBody: string | null\n requestBodyKind: string\n responseStatus: number\n responseHeaders: HeaderMap\n responseBody: string | null\n responseBodyKind: string\n}\n\nexport type OutboundCaptureRow = OutboundCaptureInput & {\n capturedAtMs: number\n}\n\nexport type RequestOutboundStoreApi = {\n insert(input: OutboundCaptureInput): void\n getByRequestId(requestId: string): OutboundCaptureRow | null\n hasOutboundForIds(requestIds: Array<string>): Set<string>\n cleanupOrphans(): void\n meta(): {\n dbPath: string\n userVersion: number\n }\n}\n\nclass RequestOutboundStore implements RequestOutboundStoreApi {\n private readonly db: Database\n private readonly insertStmt: ReturnType<Database[\"query\"]>\n private readonly getByRequestIdStmt: ReturnType<Database[\"query\"]>\n private readonly cleanupOrphansStmt: ReturnType<Database[\"query\"]>\n\n constructor(db: Database) {\n this.db = db\n this.insertStmt = db.query(`\n INSERT OR REPLACE INTO request_outbound (\n request_id,\n captured_at_ms,\n http_status,\n upstream_url,\n upstream_method,\n request_headers,\n request_body,\n request_body_kind,\n response_status,\n response_headers,\n response_body,\n response_body_kind\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n `)\n this.getByRequestIdStmt = db.query(`\n SELECT\n request_id,\n captured_at_ms,\n http_status,\n upstream_url,\n upstream_method,\n request_headers,\n request_body,\n request_body_kind,\n response_status,\n response_headers,\n response_body,\n response_body_kind\n FROM request_outbound\n WHERE request_id = ?\n LIMIT 1;\n `)\n this.cleanupOrphansStmt = db.query(`\n DELETE FROM request_outbound\n WHERE NOT EXISTS (\n SELECT 1\n FROM request_log\n WHERE request_log.request_id = request_outbound.request_id\n );\n `)\n }\n\n insert(input: OutboundCaptureInput): void {\n try {\n this.insertStmt.run(\n input.requestId,\n Date.now(),\n input.httpStatus,\n input.upstreamUrl,\n input.upstreamMethod,\n JSON.stringify(redactHeaders(input.requestHeaders)),\n input.requestBody,\n input.requestBodyKind,\n input.responseStatus,\n JSON.stringify(input.responseHeaders),\n input.responseBody,\n input.responseBodyKind,\n )\n } catch (error) {\n warnInsertFailure(error)\n }\n }\n\n getByRequestId(requestId: string): OutboundCaptureRow | null {\n try {\n const row = this.getByRequestIdStmt.get(requestId) as\n | {\n request_id: string\n captured_at_ms: number\n http_status: number\n upstream_url: string\n upstream_method: string\n request_headers: string\n request_body: string | null\n request_body_kind: string\n response_status: number\n response_headers: string\n response_body: string | null\n response_body_kind: string\n }\n | null\n | undefined\n\n if (!row) {\n return null\n }\n\n return {\n requestId: row.request_id,\n capturedAtMs: row.captured_at_ms,\n httpStatus: row.http_status,\n upstreamUrl: row.upstream_url,\n upstreamMethod: row.upstream_method,\n requestHeaders: JSON.parse(row.request_headers) as HeaderMap,\n requestBody: row.request_body,\n requestBodyKind: row.request_body_kind,\n responseStatus: row.response_status,\n responseHeaders: JSON.parse(row.response_headers) as HeaderMap,\n responseBody: row.response_body,\n responseBodyKind: row.response_body_kind,\n }\n } catch (error) {\n consola.debug(\"Failed to fetch request outbound by request_id\", error)\n return null\n }\n }\n\n hasOutboundForIds(requestIds: Array<string>): Set<string> {\n if (requestIds.length === 0) return new Set()\n try {\n const placeholders = requestIds.map(() => \"?\").join(\", \")\n const stmt = this.db.query(\n `SELECT request_id FROM request_outbound WHERE request_id IN (${placeholders})`,\n )\n const rows = stmt.all(...requestIds) as Array<{ request_id: string }>\n return new Set(rows.map((r) => r.request_id))\n } catch (error) {\n consola.debug(\"Failed to batch-check request outbound ids\", error)\n return new Set()\n }\n }\n\n cleanupOrphans(): void {\n try {\n this.cleanupOrphansStmt.run()\n } catch (error) {\n consola.debug(\"Failed to cleanup request_outbound orphans\", error)\n }\n }\n\n meta(): { dbPath: string; userVersion: number } {\n return {\n dbPath: getAdminDbPath(),\n userVersion: getAdminDbUserVersion(this.db),\n }\n }\n}\n\nexport function createRequestOutboundStore(\n db: Database,\n): RequestOutboundStoreApi {\n return new RequestOutboundStore(db)\n}\n\nconst disabledStore: RequestOutboundStoreApi = {\n insert: () => {},\n getByRequestId: () => null,\n hasOutboundForIds: () => new Set(),\n cleanupOrphans: () => {},\n meta: () => ({\n dbPath: getAdminDbPath(),\n userVersion: 0,\n }),\n}\n\nlet sharedStore: RequestOutboundStoreApi | null = null\n\nexport function getRequestOutboundStore(): RequestOutboundStoreApi {\n if (sharedStore) {\n return sharedStore\n }\n\n const now = Date.now()\n if (now < nextStoreRetryAtMs) {\n return disabledStore\n }\n\n try {\n sharedStore = createRequestOutboundStore(getAdminDb())\n return sharedStore\n } catch (error) {\n nextStoreRetryAtMs = now + STORE_INIT_RETRY_DELAY_MS\n warnStoreInitFailure(error)\n return disabledStore\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"request-outbound-DZTxxtcx.js","names":[],"sources":["../src/lib/admin-db.ts","../src/lib/request-outbound.ts"],"sourcesContent":["import { Database } from \"bun:sqlite\"\nimport consola from \"consola\"\nimport fs from \"node:fs\"\nimport path from \"node:path\"\n\nimport { PATHS } from \"./paths\"\n\nconst ADMIN_DB_FILENAME = \"admin.sqlite\"\nconst DEFAULT_DB_PATH = path.join(PATHS.APP_DIR, ADMIN_DB_FILENAME)\n\nlet sharedDb: Database | null = null\nlet initialized = false\n\nconst INIT_WARN_THROTTLE_MS = 30_000\n\nlet lastInitWarnAtMs = 0\nlet suppressedInitWarnCount = 0\n\nfunction warnAdminDbInitFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastInitWarnAtMs < INIT_WARN_THROTTLE_MS) {\n suppressedInitWarnCount++\n return\n }\n\n const suppressed = suppressedInitWarnCount\n suppressedInitWarnCount = 0\n lastInitWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(\n `Failed to initialize admin DB; admin features disabled${suffix}`,\n error,\n )\n}\n\nexport function getAdminDbPath(): string {\n return DEFAULT_DB_PATH\n}\n\nexport function openAdminDb(filePath: string = DEFAULT_DB_PATH): Database {\n if (filePath !== \":memory:\") {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n }\n\n return new Database(filePath)\n}\n\nexport function initAdminDb(db: Database): void {\n // Pragmas: prefer WAL for concurrent reads, keep writes fast.\n // Note: journal_mode=WAL is per-database and persists in the DB file.\n db.run(\"PRAGMA journal_mode = WAL;\")\n db.run(\"PRAGMA synchronous = NORMAL;\")\n db.run(\"PRAGMA busy_timeout = 3000;\")\n db.run(\"PRAGMA foreign_keys = ON;\")\n\n migrateAdminDb(db)\n}\n\nexport function getAdminDb(): Database {\n if (!sharedDb) {\n sharedDb = openAdminDb()\n }\n if (!initialized) {\n try {\n initAdminDb(sharedDb)\n initialized = true\n } catch (error) {\n // Admin DB is a best-effort feature; server should continue to run.\n warnAdminDbInitFailure(error)\n }\n }\n return sharedDb\n}\n\nexport function getAdminDbUserVersion(db: Database = getAdminDb()): number {\n try {\n const row = db.query(\"PRAGMA user_version;\").get() as {\n user_version?: number\n } | null\n return row?.user_version ?? 0\n } catch {\n return 0\n }\n}\n\nfunction hasRequestLogColumn(db: Database, columnName: string): boolean {\n return db\n .query(\"PRAGMA table_info(request_log);\")\n .all()\n .some((row) => (row as { name?: string }).name === columnName)\n}\n\nfunction migrateV1(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS request_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n request_id TEXT NOT NULL UNIQUE,\n\n started_at_ms INTEGER NOT NULL,\n finished_at_ms INTEGER,\n duration_ms INTEGER,\n ttfb_ms INTEGER,\n\n method TEXT NOT NULL,\n path TEXT NOT NULL,\n upstream_endpoint TEXT,\n stream INTEGER NOT NULL DEFAULT 0,\n\n account_id TEXT,\n account_type TEXT,\n cost_units REAL,\n client_model TEXT,\n upstream_model TEXT,\n\n client_ip TEXT,\n client_ip_source TEXT,\n user_agent TEXT,\n\n tokens_input INTEGER,\n tokens_output INTEGER,\n tokens_total INTEGER,\n tokens_cached_input INTEGER,\n usage_json TEXT,\n\n premium_remaining_before REAL,\n premium_remaining_after REAL,\n premium_remaining_diff REAL,\n premium_unlimited_before INTEGER,\n premium_unlimited_after INTEGER,\n\n http_status INTEGER,\n error_name TEXT,\n error_status INTEGER,\n error_message TEXT,\n selection_failure_reason TEXT\n );\n\n CREATE INDEX IF NOT EXISTS idx_request_log_started_at\n ON request_log(started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_account_started_at\n ON request_log(account_id, started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_model_started_at\n ON request_log(upstream_model, started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_endpoint_started_at\n ON request_log(upstream_endpoint, started_at_ms DESC);\n CREATE INDEX IF NOT EXISTS idx_request_log_status_started_at\n ON request_log(http_status, started_at_ms DESC);\n\n PRAGMA user_version = 1;\n `)\n}\n\nfunction migrateV9(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS daily_premium_stats (\n date TEXT NOT NULL,\n account_id TEXT NOT NULL,\n request_count INTEGER NOT NULL DEFAULT 0,\n cost_units_sum REAL NOT NULL DEFAULT 0,\n tokens_total INTEGER NOT NULL DEFAULT 0,\n error_count INTEGER NOT NULL DEFAULT 0,\n updated_at_ms INTEGER NOT NULL,\n PRIMARY KEY (date, account_id)\n );\n\n CREATE INDEX IF NOT EXISTS idx_daily_premium_stats_date\n ON daily_premium_stats(date);\n `)\n\n // Backfill from existing request_log (guard: table may not exist in edge cases)\n const hasRequestLog = db\n .query(\n \"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'request_log' LIMIT 1;\",\n )\n .get()\n\n if (hasRequestLog) {\n const nowMs = Date.now()\n db.run(\n `INSERT INTO daily_premium_stats\n (date, account_id, request_count, cost_units_sum, tokens_total, error_count, updated_at_ms)\n SELECT\n date(started_at_ms / 1000, 'unixepoch', 'localtime') AS date,\n account_id,\n COUNT(*) AS request_count,\n SUM(cost_units) AS cost_units_sum,\n COALESCE(SUM(tokens_total), 0) AS tokens_total,\n SUM(CASE WHEN error_name IS NOT NULL THEN 1 ELSE 0 END) AS error_count,\n ? AS updated_at_ms\n FROM request_log\n WHERE cost_units > 0\n AND account_id IS NOT NULL\n GROUP BY 1, 2\n ON CONFLICT(date, account_id) DO UPDATE SET\n request_count = excluded.request_count,\n cost_units_sum = excluded.cost_units_sum,\n tokens_total = excluded.tokens_total,\n error_count = excluded.error_count,\n updated_at_ms = excluded.updated_at_ms;`,\n [nowMs],\n )\n }\n\n db.run(\"PRAGMA user_version = 9;\")\n}\n\nfunction migrateV8(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS session_affinity (\n cache_key TEXT PRIMARY KEY,\n account_id TEXT NOT NULL,\n created_at_ms INTEGER NOT NULL,\n last_confirmed_at_ms INTEGER NOT NULL,\n last_used_at_ms INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_session_affinity_last_used\n ON session_affinity(last_used_at_ms);\n\n CREATE INDEX IF NOT EXISTS idx_session_affinity_account\n ON session_affinity(account_id);\n\n PRAGMA user_version = 8;\n `)\n}\n\nfunction migrateV10(db: Database): void {\n db.run(`\n CREATE TABLE IF NOT EXISTS quota_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n account_id TEXT NOT NULL,\n snapshot_at_ms INTEGER NOT NULL,\n remaining INTEGER NOT NULL,\n entitlement INTEGER NOT NULL,\n unlimited INTEGER NOT NULL DEFAULT 0,\n source TEXT NOT NULL DEFAULT 'refresh'\n );\n\n CREATE INDEX IF NOT EXISTS idx_quota_snapshots_account_time\n ON quota_snapshots(account_id, snapshot_at_ms);\n\n CREATE INDEX IF NOT EXISTS idx_quota_snapshots_time\n ON quota_snapshots(snapshot_at_ms);\n `)\n\n const hasRequestLog = db\n .query(\n \"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'request_log' LIMIT 1;\",\n )\n .get()\n\n if (hasRequestLog) {\n db.run(`\n INSERT INTO quota_snapshots\n (account_id, snapshot_at_ms, remaining, entitlement, unlimited, source)\n SELECT\n account_id,\n finished_at_ms,\n CAST(premium_remaining_after AS INTEGER),\n 0,\n COALESCE(premium_unlimited_after, 0),\n 'backfill'\n FROM request_log\n WHERE premium_remaining_after IS NOT NULL\n AND account_id IS NOT NULL\n AND finished_at_ms IS NOT NULL\n ORDER BY finished_at_ms;\n `)\n }\n\n db.run(\"PRAGMA user_version = 10;\")\n}\n\nfunction migrateV11(db: Database): void {\n const outboundHeaderColumns = [\n \"outbound_x_request_id\",\n \"outbound_x_agent_task_id\",\n \"outbound_x_interaction_type\",\n \"outbound_openai_intent\",\n \"outbound_user_agent\",\n ] as const\n\n for (const columnName of outboundHeaderColumns) {\n if (!hasRequestLogColumn(db, columnName)) {\n db.run(`ALTER TABLE request_log ADD COLUMN ${columnName} TEXT;`)\n }\n }\n\n db.run(`\n CREATE TABLE IF NOT EXISTS request_outbound (\n request_id TEXT PRIMARY KEY,\n captured_at_ms INTEGER NOT NULL,\n http_status INTEGER NOT NULL,\n\n upstream_url TEXT NOT NULL,\n upstream_method TEXT NOT NULL,\n\n request_headers TEXT NOT NULL,\n request_body TEXT,\n request_body_kind TEXT NOT NULL,\n\n response_status INTEGER NOT NULL,\n response_headers TEXT NOT NULL,\n response_body TEXT,\n response_body_kind TEXT NOT NULL,\n\n FOREIGN KEY (request_id) REFERENCES request_log(request_id) ON DELETE CASCADE\n );\n\n CREATE INDEX IF NOT EXISTS idx_request_outbound_captured_at\n ON request_outbound(captured_at_ms DESC);\n\n PRAGMA user_version = 11;\n `)\n}\n\nfunction migrateV12(db: Database): void {\n if (!hasRequestLogColumn(db, \"outbound_x_interaction_id\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN outbound_x_interaction_id TEXT;\")\n }\n\n db.run(\"PRAGMA user_version = 12;\")\n}\n\nfunction migrateV13(db: Database): void {\n if (!hasRequestLogColumn(db, \"responses_item_owner_lookup_keys_json\")) {\n db.run(\n \"ALTER TABLE request_log ADD COLUMN responses_item_owner_lookup_keys_json TEXT;\",\n )\n }\n\n if (!hasRequestLogColumn(db, \"responses_item_owner_recorded_keys_json\")) {\n db.run(\n \"ALTER TABLE request_log ADD COLUMN responses_item_owner_recorded_keys_json TEXT;\",\n )\n }\n\n db.run(\"PRAGMA user_version = 13;\")\n}\n\nfunction migrateV8ToV13(db: Database, current: number): void {\n if (current < 8) {\n migrateV8(db)\n }\n\n if (current < 9) {\n migrateV9(db)\n }\n\n if (current < 10) {\n migrateV10(db)\n }\n\n if (current < 11) {\n migrateV11(db)\n }\n\n if (current < 12) {\n migrateV12(db)\n }\n\n if (current < 13) {\n migrateV13(db)\n }\n}\n\n// eslint-disable-next-line complexity -- migration chain grows with each version\nfunction migrateAdminDb(db: Database): void {\n const row = db.query(\"PRAGMA user_version;\").get() as {\n user_version?: number\n } | null\n const current = row?.user_version ?? 0\n\n if (current >= 13) {\n if (current === 13) migrateV13(db)\n return\n }\n\n if (current === 12) {\n migrateV12(db)\n }\n\n if (current === 11) {\n migrateV11(db)\n }\n\n if (current < 1) {\n migrateV1(db)\n }\n\n if (current < 2) {\n // v2: request_log session correlation fields\n db.run(`\n ALTER TABLE request_log ADD COLUMN user_id TEXT;\n ALTER TABLE request_log ADD COLUMN safety_identifier TEXT;\n ALTER TABLE request_log ADD COLUMN prompt_cache_key TEXT;\n ALTER TABLE request_log ADD COLUMN initiator TEXT;\n ALTER TABLE request_log ADD COLUMN upstream_request_id TEXT;\n\n PRAGMA user_version = 2;\n `)\n }\n\n if (current < 3) {\n // v3: index for session lookup\n db.run(`\n CREATE INDEX IF NOT EXISTS idx_request_log_session_finished\n ON request_log(\n prompt_cache_key,\n safety_identifier,\n finished_at_ms DESC\n )\n WHERE finished_at_ms IS NOT NULL\n AND tokens_input IS NOT NULL;\n\n PRAGMA user_version = 3;\n `)\n }\n\n if (current < 4) {\n // v4: index for session lookup by client model\n db.run(`\n CREATE INDEX IF NOT EXISTS idx_request_log_session_finished_by_client_model\n ON request_log(\n prompt_cache_key,\n safety_identifier,\n client_model,\n finished_at_ms DESC\n )\n WHERE finished_at_ms IS NOT NULL\n AND tokens_input IS NOT NULL;\n\n PRAGMA user_version = 4;\n `)\n }\n\n if (current < 5) {\n // v5: account affinity tracking columns\n db.run(`\n ALTER TABLE request_log ADD COLUMN affinity_hit INTEGER;\n ALTER TABLE request_log ADD COLUMN affinity_cache_key TEXT;\n\n PRAGMA user_version = 5;\n `)\n }\n\n if (current < 6) {\n // v6: explicit subagent request tracking column\n if (!hasRequestLogColumn(db, \"is_subagent\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN is_subagent INTEGER;\")\n }\n\n db.run(\"PRAGMA user_version = 6;\")\n }\n\n if (current < 7) {\n // v7: request-level affinity and upstream error observability columns\n if (!hasRequestLogColumn(db, \"affinity_key_used\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN affinity_key_used TEXT;\")\n }\n\n if (!hasRequestLogColumn(db, \"affinity_key_source\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN affinity_key_source TEXT;\")\n }\n\n if (!hasRequestLogColumn(db, \"selection_reason\")) {\n db.run(\"ALTER TABLE request_log ADD COLUMN selection_reason TEXT;\")\n }\n\n if (!hasRequestLogColumn(db, \"upstream_error_message_raw\")) {\n db.run(\n \"ALTER TABLE request_log ADD COLUMN upstream_error_message_raw TEXT;\",\n )\n }\n\n db.run(\"PRAGMA user_version = 7;\")\n }\n\n migrateV8ToV13(db, current)\n}\n","import type { Database } from \"bun:sqlite\"\n\nimport consola from \"consola\"\n\nimport { getAdminDb, getAdminDbPath, getAdminDbUserVersion } from \"./admin-db\"\n\nconst INSERT_WARN_THROTTLE_MS = 30_000\nconst STORE_INIT_WARN_THROTTLE_MS = 30_000\nconst STORE_INIT_RETRY_DELAY_MS = 30_000\n\nlet lastInsertWarnAtMs = 0\nlet suppressedInsertWarnCount = 0\nlet lastStoreInitWarnAtMs = 0\nlet suppressedStoreInitWarnCount = 0\nlet nextStoreRetryAtMs = 0\n\nexport const SENSITIVE_HEADER_PATTERNS = [\n /^authorization$/i,\n /^x-github-token$/i,\n /^cookie$/i,\n /^set-cookie$/i,\n /^proxy-authorization$/i,\n /^x-api-key$/i,\n /-token$/i,\n /-secret$/i,\n] as const\n\nfunction warnInsertFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastInsertWarnAtMs < INSERT_WARN_THROTTLE_MS) {\n suppressedInsertWarnCount++\n return\n }\n\n const suppressed = suppressedInsertWarnCount\n suppressedInsertWarnCount = 0\n lastInsertWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Failed to insert request outbound${suffix}`, error)\n}\n\nfunction warnStoreInitFailure(error: unknown): void {\n const now = Date.now()\n\n if (now - lastStoreInitWarnAtMs < STORE_INIT_WARN_THROTTLE_MS) {\n suppressedStoreInitWarnCount++\n return\n }\n\n const suppressed = suppressedStoreInitWarnCount\n suppressedStoreInitWarnCount = 0\n lastStoreInitWarnAtMs = now\n\n const suffix =\n suppressed > 0 ? ` (suppressed ${suppressed} similar errors)` : \"\"\n consola.warn(`Request outbound store is disabled${suffix}`, error)\n}\n\ntype HeaderMap = Record<string, string>\n\nfunction shouldRedactHeader(key: string): boolean {\n return SENSITIVE_HEADER_PATTERNS.some((pattern) => pattern.test(key))\n}\n\nexport function getRedactedHeaderKeys(headers: HeaderMap): Array<string> {\n return Object.keys(headers).filter((key) => shouldRedactHeader(key))\n}\n\nexport function redactHeaders(headers: HeaderMap): HeaderMap {\n const redacted: HeaderMap = {}\n\n for (const [key, value] of Object.entries(headers)) {\n redacted[key] = shouldRedactHeader(key) ? \"***\" : value\n }\n\n return redacted\n}\n\nexport type OutboundCaptureInput = {\n requestId: string\n httpStatus: number\n upstreamUrl: string\n upstreamMethod: string\n requestHeaders: HeaderMap\n requestBody: string | null\n requestBodyKind: string\n responseStatus: number\n responseHeaders: HeaderMap\n responseBody: string | null\n responseBodyKind: string\n}\n\nexport type OutboundCaptureRow = OutboundCaptureInput & {\n capturedAtMs: number\n}\n\nexport type RequestOutboundStoreApi = {\n insert(input: OutboundCaptureInput): void\n getByRequestId(requestId: string): OutboundCaptureRow | null\n hasOutboundForIds(requestIds: Array<string>): Set<string>\n cleanupOrphans(): void\n meta(): {\n dbPath: string\n userVersion: number\n }\n}\n\nclass RequestOutboundStore implements RequestOutboundStoreApi {\n private readonly db: Database\n private readonly insertStmt: ReturnType<Database[\"query\"]>\n private readonly getByRequestIdStmt: ReturnType<Database[\"query\"]>\n private readonly cleanupOrphansStmt: ReturnType<Database[\"query\"]>\n\n constructor(db: Database) {\n this.db = db\n this.insertStmt = db.query(`\n INSERT OR REPLACE INTO request_outbound (\n request_id,\n captured_at_ms,\n http_status,\n upstream_url,\n upstream_method,\n request_headers,\n request_body,\n request_body_kind,\n response_status,\n response_headers,\n response_body,\n response_body_kind\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\n `)\n this.getByRequestIdStmt = db.query(`\n SELECT\n request_id,\n captured_at_ms,\n http_status,\n upstream_url,\n upstream_method,\n request_headers,\n request_body,\n request_body_kind,\n response_status,\n response_headers,\n response_body,\n response_body_kind\n FROM request_outbound\n WHERE request_id = ?\n LIMIT 1;\n `)\n this.cleanupOrphansStmt = db.query(`\n DELETE FROM request_outbound\n WHERE NOT EXISTS (\n SELECT 1\n FROM request_log\n WHERE request_log.request_id = request_outbound.request_id\n );\n `)\n }\n\n insert(input: OutboundCaptureInput): void {\n try {\n this.insertStmt.run(\n input.requestId,\n Date.now(),\n input.httpStatus,\n input.upstreamUrl,\n input.upstreamMethod,\n JSON.stringify(redactHeaders(input.requestHeaders)),\n input.requestBody,\n input.requestBodyKind,\n input.responseStatus,\n JSON.stringify(input.responseHeaders),\n input.responseBody,\n input.responseBodyKind,\n )\n } catch (error) {\n warnInsertFailure(error)\n }\n }\n\n getByRequestId(requestId: string): OutboundCaptureRow | null {\n try {\n const row = this.getByRequestIdStmt.get(requestId) as\n | {\n request_id: string\n captured_at_ms: number\n http_status: number\n upstream_url: string\n upstream_method: string\n request_headers: string\n request_body: string | null\n request_body_kind: string\n response_status: number\n response_headers: string\n response_body: string | null\n response_body_kind: string\n }\n | null\n | undefined\n\n if (!row) {\n return null\n }\n\n return {\n requestId: row.request_id,\n capturedAtMs: row.captured_at_ms,\n httpStatus: row.http_status,\n upstreamUrl: row.upstream_url,\n upstreamMethod: row.upstream_method,\n requestHeaders: JSON.parse(row.request_headers) as HeaderMap,\n requestBody: row.request_body,\n requestBodyKind: row.request_body_kind,\n responseStatus: row.response_status,\n responseHeaders: JSON.parse(row.response_headers) as HeaderMap,\n responseBody: row.response_body,\n responseBodyKind: row.response_body_kind,\n }\n } catch (error) {\n consola.debug(\"Failed to fetch request outbound by request_id\", error)\n return null\n }\n }\n\n hasOutboundForIds(requestIds: Array<string>): Set<string> {\n if (requestIds.length === 0) return new Set()\n try {\n const placeholders = requestIds.map(() => \"?\").join(\", \")\n const stmt = this.db.query(\n `SELECT request_id FROM request_outbound WHERE request_id IN (${placeholders})`,\n )\n const rows = stmt.all(...requestIds) as Array<{ request_id: string }>\n return new Set(rows.map((r) => r.request_id))\n } catch (error) {\n consola.debug(\"Failed to batch-check request outbound ids\", error)\n return new Set()\n }\n }\n\n cleanupOrphans(): void {\n try {\n this.cleanupOrphansStmt.run()\n } catch (error) {\n consola.debug(\"Failed to cleanup request_outbound orphans\", error)\n }\n }\n\n meta(): { dbPath: string; userVersion: number } {\n return {\n dbPath: getAdminDbPath(),\n userVersion: getAdminDbUserVersion(this.db),\n }\n }\n}\n\nexport function createRequestOutboundStore(\n db: Database,\n): RequestOutboundStoreApi {\n return new RequestOutboundStore(db)\n}\n\nconst disabledStore: RequestOutboundStoreApi = {\n insert: () => {},\n getByRequestId: () => null,\n hasOutboundForIds: () => new Set(),\n cleanupOrphans: () => {},\n meta: () => ({\n dbPath: getAdminDbPath(),\n userVersion: 0,\n }),\n}\n\nlet sharedStore: RequestOutboundStoreApi | null = null\n\nexport function getRequestOutboundStore(): RequestOutboundStoreApi {\n if (sharedStore) {\n return sharedStore\n }\n\n const now = Date.now()\n if (now < nextStoreRetryAtMs) {\n return disabledStore\n }\n\n try {\n sharedStore = createRequestOutboundStore(getAdminDb())\n return sharedStore\n } catch (error) {\n nextStoreRetryAtMs = now + STORE_INIT_RETRY_DELAY_MS\n warnStoreInitFailure(error)\n return disabledStore\n }\n}\n"],"mappings":"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"}