@jeffreycao/copilot-api 2.7.39 → 2.7.41

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.
@@ -1,14 +1,15 @@
1
1
  import { D as state, E as isGitHubCopilotEnabled, O as HTTPError, S as PATHS, a as getAnthropicApiKey, c as getConfig, d as getUpstreamTransportConfig, g as isResponsesApiWebSocketEnabled, h as isResponsesApiWebSearchEnabled, i as getAlphaSearchModel, j as forwardError, l as getMessageApiWebSearchModel, m as isMessagesApiEnabled, o as getClaudeAutoModel, p as isAlphaSearchCodexPriorityEnabled, s as getClaudeTokenMultiplier, u as getOpencodeModelContextWindow, w as GITHUB_COPILOT_PROVIDER, y as reloadConfig } from "./config-store-BsluQttR.js";
2
2
  import { A as resolveMappedModel, C as getModelResponsesApiCompactThreshold$1, D as isContextManagementEnabledForMessages, E as getSmallModelForProvider, O as isContextManagementEnabledForResponses, S as getModelMappings, T as getSmallModel, _ as getModelsDevModelMaxOutputTokens, a as normalizeProviderBaseUrl, d as isProviderModelVisible, f as resolveProviderModelsDevId, g as getModelsDevModel, h as getBuiltinProviderModelRecords, i as listEnabledProviders, j as setModelMappings, k as isGpt56OrAbove, l as getLocalProviderModelRecords, m as builtinProviderModelRegistry, n as getRawProviderConfig, o as resolveEffectiveProviderType, p as usesModelsDevModelCatalog, s as resolveProviderConfigForModel, t as getProviderConfig, u as getProviderModelConfig, v as getModelsDevModelPricing, w as getReasoningEffortForModel, x as getExtraPromptForModel } from "./config-BqSuE5h5.js";
3
- import { $ as forwardCodexResponses, B as getXaiAccessToken, C as copilotHeaders, D as prepareForCompact, E as isOpencodeOauthApp, F as compactTextOnlyGuard, I as createAuthMiddleware, J as XAI_API_BASE_URL, K as readGitHubToken, L as getConfiguredAdminApiKeys, M as compactMessageSections, O as prepareInteractionHeaders, P as compactSystemPromptStarts, Q as buildCodexRequestHeaders, S as copilotBaseUrl, T as copilotWebSocketHeaders, Z as CODEX_API_BASE_URL, _ as isAsyncIterable, at as createResponsesHttpEventStream, b as parseUserIdMetadata, ct as getResponsesStreamTerminalDisposition, d as generateRequestIdFromPayload, et as generateTraceId, f as getPromptCacheKey, ft as stripInternalRequestHeaders, g as getUUID, h as getSessionAffinityFromHeaders, it as fetchUpstreamWithLifecycle, j as compactAutoContinuePromptStarts, k as prepareMessageProxyHeaders, lt as createPooledWebSocketStream, m as getRootSessionIdFromHeaders, n as invalidateCodexRuntime, nt as resolveTraceId$1, ot as createResponsesSafeStream, p as getRootSessionId, q as readGitHubTokenFromEnv, rt as setPluginRequestActualModel, s as setupCodexToken, st as encodePoolKeyPart, tt as requestContext, u as stopCopilotRefreshLoop, ut as createWebSocketUrl, v as isNullish, x as getCopilotUsage, y as isResponsesStream } from "./token-_1CBLbqH.js";
3
+ import { $ as buildCodexRequestHeaders, B as getXaiAccessToken, C as copilotHeaders, D as prepareForCompact, E as isOpencodeOauthApp, F as compactTextOnlyGuard, I as createAuthMiddleware, J as readGitHubTokenFromEnv, L as getConfiguredAdminApiKeys, M as compactMessageSections, O as prepareInteractionHeaders, P as compactSystemPromptStarts, Q as CODEX_API_BASE_URL, S as copilotBaseUrl, T as copilotWebSocketHeaders, U as readXaiCredentials, Y as XAI_API_BASE_URL, _ as isAsyncIterable, at as fetchUpstreamWithLifecycle, b as parseUserIdMetadata, ct as encodePoolKeyPart, d as generateRequestIdFromPayload, dt as createWebSocketUrl, et as forwardCodexResponses, f as getPromptCacheKey, g as getUUID, h as getSessionAffinityFromHeaders, it as setPluginRequestActualModel, j as compactAutoContinuePromptStarts, k as prepareMessageProxyHeaders, lt as getResponsesStreamTerminalDisposition, m as getRootSessionIdFromHeaders, n as invalidateCodexRuntime, nt as requestContext, ot as createResponsesHttpEventStream, p as getRootSessionId, pt as stripInternalRequestHeaders, q as readGitHubToken, rt as resolveTraceId$1, s as setupCodexToken, st as createResponsesSafeStream, tt as generateTraceId, u as stopCopilotRefreshLoop, ut as createPooledWebSocketStream, v as isNullish, x as getCopilotUsage, y as isResponsesStream } from "./token-CZmr-geT.js";
4
4
  import { a as isDeferredToolName, c as parseMcpToolSearchSentinel, d as shouldEnableResponsesToolSearch, i as isBridgeToolSearchName, l as resolveBridgeToolSearchName, o as listDeferredToolNames, r as formatToolSearchBridgeArguments, s as normalizeToolSearchBridgeArguments, t as BRIDGE_TOOL_SEARCH_NAME, u as selectDeferredToolsByNames } from "./tool-search-DzipwtCX.js";
5
5
  import { n as isProviderAgentModelVisible, t as getProviderAgentModels } from "./provider-management-vyEQj9RR.js";
6
- import { i as registerProcessCleanup, n as stopModelsRefreshLoop, r as EventBus, t as setupCopilotRuntime } from "./copilot-runtime-0CujVONa.js";
6
+ import { i as registerProcessCleanup, n as stopModelsRefreshLoop, r as EventBus, t as setupCopilotRuntime } from "./copilot-runtime-CjQPxPeV.js";
7
7
  import consola from "consola";
8
8
  import { createHash, randomUUID } from "node:crypto";
9
9
  import fs, { readFileSync } from "node:fs";
10
10
  import path from "node:path";
11
11
  import fs$1 from "node:fs/promises";
12
+ import os from "node:os";
12
13
  import { fetch as fetch$1, getGlobalDispatcher } from "undici";
13
14
  import { events } from "fetch-event-stream";
14
15
  import { z } from "zod";
@@ -2063,14 +2064,16 @@ const createResponsesWebSocketStreamChunk = (data) => {
2063
2064
  try {
2064
2065
  const parsed = JSON.parse(data);
2065
2066
  if (parsed.type === "response.completed") logCopilotQuotaSnapshots(parsed.copilot_quota_snapshots);
2067
+ let forwardedData = data;
2066
2068
  if (parsed.type === "error" && parsed.error) {
2067
2069
  consola.warn("Copilot responses websocket stream error:", parsed.error);
2068
2070
  parsed.code = parsed.error.code;
2069
2071
  parsed.message = parsed.error.message;
2072
+ forwardedData = JSON.stringify(parsed);
2070
2073
  }
2071
2074
  return {
2072
2075
  event: typeof parsed.type === "string" ? parsed.type : void 0,
2073
- data: JSON.stringify(parsed),
2076
+ data: forwardedData,
2074
2077
  id: typeof parsed.id === "string" ? parsed.id : void 0
2075
2078
  };
2076
2079
  } catch {
@@ -9828,11 +9831,11 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
9828
9831
  recordAnthropicFirstToken(parsedEvent);
9829
9832
  if (parsedEvent?.type === "message_start") usage = mergeAnthropicUsage(usage, {
9830
9833
  ...normalizeAnthropicUsage(parsedEvent.message.usage),
9831
- ...normalizeCopilotUsage(parsedEvent.message.copilot_usage)
9834
+ ...normalizeCopilotUsage$1(parsedEvent.message.copilot_usage)
9832
9835
  });
9833
9836
  else if (parsedEvent?.type === "message_delta") usage = mergeAnthropicUsage(usage, {
9834
9837
  ...normalizeAnthropicUsage(parsedEvent.usage),
9835
- ...normalizeCopilotUsage(parsedEvent.copilot_usage)
9838
+ ...normalizeCopilotUsage$1(parsedEvent.copilot_usage)
9836
9839
  });
9837
9840
  if (parsedEvent?.type === "message_stop" || eventName === "message_stop") messageStopSeen = true;
9838
9841
  else if (parsedEvent?.type === "error" || eventName === "error") errorSeen = true;
@@ -9861,7 +9864,7 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
9861
9864
  });
9862
9865
  recordUsage({
9863
9866
  ...normalizeAnthropicUsage(response.usage),
9864
- ...normalizeCopilotUsage(response.copilot_usage)
9867
+ ...normalizeCopilotUsage$1(response.copilot_usage)
9865
9868
  });
9866
9869
  return c.json(response);
9867
9870
  };
@@ -9893,7 +9896,7 @@ const createCopilotUsageRecorder = (options) => createCopilotTokenUsageRecorder(
9893
9896
  sessionId: getMetadataSessionId(options.payload)
9894
9897
  });
9895
9898
  const getMetadataSessionId = (payload) => parseUserIdMetadata(payload.metadata?.user_id).sessionId;
9896
- const normalizeCopilotUsage = (copilotUsage) => ({ total_nano_aiu: normalizeOptionalToken(copilotUsage?.total_nano_aiu) });
9899
+ const normalizeCopilotUsage$1 = (copilotUsage) => ({ total_nano_aiu: normalizeOptionalToken(copilotUsage?.total_nano_aiu) });
9897
9900
  const parseAnthropicStreamEvent = (data) => {
9898
9901
  try {
9899
9902
  return JSON.parse(data);
@@ -13593,9 +13596,8 @@ const streamProviderResponses = async (c, upstreamResponse, options) => {
13593
13596
  normalizeCodex: options.normalizeCodex,
13594
13597
  provider: options.provider
13595
13598
  });
13596
- if (event && options.normalizeCodex) responseChunk = {
13599
+ if (event && options.normalizeCodex && chunk.event !== event.type) responseChunk = {
13597
13600
  ...chunk,
13598
- data: JSON.stringify(event),
13599
13601
  event: event.type
13600
13602
  };
13601
13603
  }
@@ -13947,8 +13949,329 @@ function parsePageQuery(c) {
13947
13949
  }
13948
13950
  tokenUsageRoute.get("/events", async (c) => c.json(await getTokenUsageEventsPage(parsePageQuery(c))));
13949
13951
  tokenUsageRoute.get("/sessions", async (c) => c.json(await getTokenUsageSessionsPage(parsePageQuery(c))));
13952
+ // src/services/subscription-usage.ts
13953
+ const CODEX_CLI_VERSION = "0.164.0";
13954
+ const amount = z.union([z.number().finite(), z.string().trim().min(1).refine((value) => Number.isFinite(Number(value)))]).transform(Number);
13955
+ const number = z.number().finite();
13956
+ const codexWindow = z.object({
13957
+ used_percent: number,
13958
+ limit_window_seconds: number.nullish(),
13959
+ reset_at: number.nullish(),
13960
+ reset_after_seconds: number.nullish()
13961
+ });
13962
+ const codexRateLimit = z.object({
13963
+ allowed: z.boolean().nullish(),
13964
+ limit_reached: z.boolean().nullish(),
13965
+ primary_window: codexWindow.nullish(),
13966
+ secondary_window: codexWindow.nullish()
13967
+ });
13968
+ const codexUsage = z.object({
13969
+ plan_type: z.string(),
13970
+ rate_limit: codexRateLimit.nullish(),
13971
+ additional_rate_limits: z.array(z.object({
13972
+ limit_name: z.string(),
13973
+ metered_feature: z.string(),
13974
+ rate_limit: codexRateLimit.nullish()
13975
+ })).nullish(),
13976
+ credits: z.object({
13977
+ has_credits: z.boolean(),
13978
+ unlimited: z.boolean(),
13979
+ balance: amount.nullish()
13980
+ }).nullish(),
13981
+ spend_control: z.object({
13982
+ reached: z.boolean(),
13983
+ individual_limit: z.object({
13984
+ limit: amount,
13985
+ used: amount,
13986
+ used_percent: number,
13987
+ reset_at: number.nullish(),
13988
+ reset_after_seconds: number.nullish()
13989
+ }).nullish()
13990
+ }).nullish(),
13991
+ rate_limit_reached_type: z.object({ type: z.string() }).nullish()
13992
+ });
13993
+ const cents = z.object({ val: amount.default(0) }).nullish();
13994
+ const xaiUsage = z.object({
13995
+ config: z.object({
13996
+ creditUsagePercent: number.nullish(),
13997
+ currentPeriod: z.object({
13998
+ type: z.string().nullish(),
13999
+ end: z.string().nullish()
14000
+ }).nullish(),
14001
+ monthlyLimit: cents,
14002
+ used: cents,
14003
+ onDemandCap: cents,
14004
+ onDemandUsed: cents,
14005
+ prepaidBalance: cents,
14006
+ billingPeriodEnd: z.string().nullish()
14007
+ }).nullish(),
14008
+ subscription_tier: z.string().nullish()
14009
+ });
14010
+ const copilotQuota = z.object({
14011
+ entitlement: number.nullish(),
14012
+ remaining: number.nullish(),
14013
+ quota_remaining: number.nullish(),
14014
+ percent_remaining: number.nullish(),
14015
+ unlimited: z.boolean().nullish()
14016
+ });
14017
+ const copilotUsage = z.object({
14018
+ copilot_plan: z.string().nullish(),
14019
+ quota_reset_date: z.string().nullish(),
14020
+ quota_snapshots: z.object({
14021
+ premium_interactions: copilotQuota.nullish(),
14022
+ chat: copilotQuota.nullish(),
14023
+ completions: copilotQuota.nullish()
14024
+ }).nullish()
14025
+ });
14026
+ const opencodeGoWindow = z.object({
14027
+ status: z.enum(["ok", "rate-limited"]),
14028
+ percent: number,
14029
+ resetsAt: z.string().nullish()
14030
+ });
14031
+ const opencodeGoUsage = z.object({ usage: z.object({
14032
+ rolling: opencodeGoWindow.nullish(),
14033
+ weekly: opencodeGoWindow.nullish(),
14034
+ monthly: opencodeGoWindow.nullish()
14035
+ }) });
14036
+ function normalizeOpencodeGoUsage(value) {
14037
+ const { usage } = opencodeGoUsage.parse(value);
14038
+ const windows = [];
14039
+ for (const scope of [
14040
+ "rolling",
14041
+ "weekly",
14042
+ "monthly"
14043
+ ]) {
14044
+ const window = usage[scope];
14045
+ if (!window) continue;
14046
+ windows.push({
14047
+ id: `opencode-go:${scope}`,
14048
+ kind: "usage",
14049
+ windowSeconds: scope === "rolling" ? 18e3 : void 0,
14050
+ period: scope === "rolling" ? void 0 : scope,
14051
+ usedPercent: window.percent,
14052
+ resetAt: parseResetDate(window.resetsAt),
14053
+ limitReached: window.status === "rate-limited" || window.percent >= 100
14054
+ });
14055
+ }
14056
+ return {
14057
+ provider: "opencode-go",
14058
+ windows,
14059
+ limitReached: windows.some((window) => window.limitReached)
14060
+ };
14061
+ }
14062
+ function normalizeCopilotUsage(value) {
14063
+ const usage = copilotUsage.parse(value);
14064
+ const windows = [];
14065
+ const labels = {
14066
+ premium_interactions: "Premium",
14067
+ chat: "Chat",
14068
+ completions: "Completions"
14069
+ };
14070
+ for (const id of [
14071
+ "premium_interactions",
14072
+ "chat",
14073
+ "completions"
14074
+ ]) {
14075
+ const quota = usage.quota_snapshots?.[id];
14076
+ if (!quota) continue;
14077
+ const remaining = quota.remaining ?? quota.quota_remaining;
14078
+ const limit = quota.entitlement ?? void 0;
14079
+ const remainingPercent = quota.percent_remaining ?? (limit !== void 0 && limit > 0 && remaining != null ? remaining / limit * 100 : void 0);
14080
+ if (!quota.unlimited && remainingPercent == null && remaining == null && limit === void 0) continue;
14081
+ windows.push({
14082
+ id: `copilot:${id}`,
14083
+ kind: "usage",
14084
+ name: labels[id],
14085
+ unlimited: quota.unlimited ?? false,
14086
+ usedPercent: quota.unlimited || remainingPercent == null ? void 0 : 100 - remainingPercent,
14087
+ used: limit !== void 0 && remaining != null ? Math.max(0, limit - remaining) : void 0,
14088
+ limit,
14089
+ unit: "requests",
14090
+ resetDate: usage.quota_reset_date ?? void 0,
14091
+ limitReached: !quota.unlimited && remainingPercent != null && remainingPercent <= 0
14092
+ });
14093
+ }
14094
+ return {
14095
+ provider: "github-copilot",
14096
+ planType: usage.copilot_plan ?? void 0,
14097
+ windows,
14098
+ limitReached: windows.some((window) => window.limitReached)
14099
+ };
14100
+ }
14101
+ function resetAt(window, now) {
14102
+ return window.reset_at ?? (window.reset_after_seconds == null ? void 0 : Math.floor(now / 1e3) + window.reset_after_seconds);
14103
+ }
14104
+ function normalizeCodexUsage(value, now = Date.now()) {
14105
+ const usage = codexUsage.parse(value);
14106
+ const windows = [];
14107
+ const addWindows = (id, limits, name) => {
14108
+ for (const scope of ["primary_window", "secondary_window"]) {
14109
+ const window = limits?.[scope];
14110
+ if (!window) continue;
14111
+ windows.push({
14112
+ id: `${id}:${scope}`,
14113
+ kind: "usage",
14114
+ name,
14115
+ usedPercent: window.used_percent,
14116
+ windowSeconds: window.limit_window_seconds ?? void 0,
14117
+ resetAt: resetAt(window, now),
14118
+ limitReached: limits?.limit_reached === true || limits?.allowed === false
14119
+ });
14120
+ }
14121
+ };
14122
+ addWindows("codex", usage.rate_limit);
14123
+ for (const [index, limit] of (usage.additional_rate_limits ?? []).entries()) addWindows(`${limit.metered_feature}:${index}`, limit.rate_limit, limit.limit_name);
14124
+ const spend = usage.spend_control?.individual_limit;
14125
+ if (spend) windows.push({
14126
+ id: "individual-limit",
14127
+ kind: "spend",
14128
+ period: "monthly",
14129
+ usedPercent: spend.used_percent,
14130
+ used: spend.used,
14131
+ limit: spend.limit,
14132
+ unit: "credits",
14133
+ resetAt: resetAt(spend, now),
14134
+ limitReached: usage.spend_control?.reached
14135
+ });
14136
+ return {
14137
+ provider: "codex",
14138
+ planType: usage.plan_type,
14139
+ windows,
14140
+ credits: usage.credits ? {
14141
+ balance: usage.credits.balance ?? void 0,
14142
+ unlimited: usage.credits.unlimited,
14143
+ hasCredits: usage.credits.has_credits,
14144
+ unit: "credits"
14145
+ } : void 0,
14146
+ limitReached: usage.rate_limit?.limit_reached === true || usage.rate_limit?.allowed === false || usage.spend_control?.reached === true || usage.rate_limit_reached_type != null && usage.rate_limit_reached_type.type !== "unknown",
14147
+ limitReason: usage.rate_limit_reached_type?.type
14148
+ };
14149
+ }
14150
+ function parseResetDate(value) {
14151
+ const milliseconds = value ? Date.parse(value) : NaN;
14152
+ return Number.isFinite(milliseconds) ? milliseconds / 1e3 : void 0;
14153
+ }
14154
+ function normalizeXaiUsage(value) {
14155
+ const usage = xaiUsage.parse(value);
14156
+ const config = usage.config;
14157
+ const windows = [];
14158
+ if (config) {
14159
+ const limit = config.monthlyLimit?.val;
14160
+ const used = config.used?.val;
14161
+ const usedPercent = config.creditUsagePercent ?? (limit !== void 0 && limit > 0 && used !== void 0 ? used / limit * 100 : void 0);
14162
+ if (usedPercent != null || limit !== void 0 || used !== void 0) windows.push({
14163
+ id: "included",
14164
+ kind: "usage",
14165
+ period: config.currentPeriod?.type === "USAGE_PERIOD_TYPE_WEEKLY" ? "weekly" : config.currentPeriod?.type === "USAGE_PERIOD_TYPE_MONTHLY" || config.monthlyLimit ? "monthly" : void 0,
14166
+ usedPercent,
14167
+ used: config.creditUsagePercent == null && used !== void 0 ? used / 100 : void 0,
14168
+ limit: config.creditUsagePercent == null && limit !== void 0 ? limit / 100 : void 0,
14169
+ unit: "USD",
14170
+ resetAt: parseResetDate(config.currentPeriod?.end ?? config.billingPeriodEnd)
14171
+ });
14172
+ if (config.onDemandCap || config.onDemandUsed) {
14173
+ const cap = Math.abs(config.onDemandCap?.val ?? 0);
14174
+ const spent = Math.abs(config.onDemandUsed?.val ?? 0);
14175
+ windows.push({
14176
+ id: "on-demand",
14177
+ kind: "on-demand",
14178
+ period: "monthly",
14179
+ unit: "USD",
14180
+ used: spent / 100,
14181
+ limit: cap / 100,
14182
+ usedPercent: cap > 0 ? spent / cap * 100 : void 0
14183
+ });
14184
+ }
14185
+ }
14186
+ return {
14187
+ provider: "xai",
14188
+ planType: usage.subscription_tier ?? void 0,
14189
+ windows,
14190
+ credits: config?.prepaidBalance ? {
14191
+ balance: Math.abs(config.prepaidBalance.val) / 100,
14192
+ unlimited: false,
14193
+ hasCredits: config.prepaidBalance.val !== 0,
14194
+ unit: "USD"
14195
+ } : void 0,
14196
+ limitReached: (windows.find((window) => window.id === "included")?.usedPercent ?? 0) >= 100
14197
+ };
14198
+ }
14199
+ async function getSubscriptionUsage(provider, signal) {
14200
+ if (provider === "github-copilot") {
14201
+ if (!isGitHubCopilotEnabled()) return null;
14202
+ const timeout = AbortSignal.timeout(15e3);
14203
+ const usage = await getCopilotUsage(void 0, signal ? AbortSignal.any([signal, timeout]) : timeout);
14204
+ return usage ? normalizeCopilotUsage(usage) : null;
14205
+ }
14206
+ const config = await resolveProviderConfig(provider);
14207
+ if (!config) return null;
14208
+ if (provider !== "opencode-go" && config.authType !== "oauth2") return null;
14209
+ let headers;
14210
+ let url;
14211
+ if (provider === "opencode-go") {
14212
+ url = resolveProviderEndpointUrl(config, "usage");
14213
+ headers = new Headers({
14214
+ Authorization: `Bearer ${config.apiKey}`,
14215
+ Accept: "application/json"
14216
+ });
14217
+ } else if (provider === "codex") {
14218
+ const platform = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "Mac OS" : os.type();
14219
+ const arch = process.arch === "x64" ? "x86_64" : process.arch === "arm64" ? "aarch64" : process.arch;
14220
+ headers = buildCodexRequestHeaders(new Headers({
14221
+ "user-agent": `codex_cli_rs/${CODEX_CLI_VERSION} (${platform} ${os.release()}; ${arch}) unknown`,
14222
+ originator: "codex_cli_rs",
14223
+ accept: "application/json"
14224
+ }));
14225
+ url = `${CODEX_API_BASE_URL}/wham/usage`;
14226
+ } else {
14227
+ const credentials = await readXaiCredentials();
14228
+ if (!credentials) return null;
14229
+ if (credentials.accessToken !== config.apiKey) throw new Error("Subscription account changed during the usage query");
14230
+ const version = await getGrokBuildVersion();
14231
+ const platform = process.platform === "win32" ? "windows" : process.platform === "darwin" ? "macos" : process.platform;
14232
+ const arch = process.arch === "x64" ? "x86_64" : process.arch === "arm64" ? "aarch64" : process.arch;
14233
+ headers = new Headers({
14234
+ Authorization: `Bearer ${config.apiKey}`,
14235
+ "X-XAI-Token-Auth": "xai-grok-cli",
14236
+ "x-userid": credentials.accountId,
14237
+ "x-grok-client-version": version,
14238
+ "x-grok-client-mode": "headless",
14239
+ "User-Agent": `grok-shell/${version} (${platform}; ${arch})`,
14240
+ Accept: "application/json"
14241
+ });
14242
+ url = `${XAI_API_BASE_URL}/v1/billing?format=credits`;
14243
+ }
14244
+ const timeout = AbortSignal.timeout(15e3);
14245
+ const response = await fetch(url, {
14246
+ headers,
14247
+ signal: signal ? AbortSignal.any([signal, timeout]) : timeout,
14248
+ redirect: "error"
14249
+ });
14250
+ if (provider === "opencode-go" && response.status === 403) {
14251
+ await response.body?.cancel();
14252
+ return null;
14253
+ }
14254
+ if (!response.ok) {
14255
+ await response.body?.cancel();
14256
+ throw new Error(`Subscription usage request failed (HTTP ${response.status})`);
14257
+ }
14258
+ const value = await response.json();
14259
+ if (provider === "opencode-go") return normalizeOpencodeGoUsage(value);
14260
+ return provider === "codex" ? normalizeCodexUsage(value) : normalizeXaiUsage(value);
14261
+ }
13950
14262
  // src/routes/usage/route.ts
13951
14263
  const usageRoute = new Hono();
14264
+ usageRoute.get("/:provider", async (c) => {
14265
+ const provider = c.req.param("provider");
14266
+ c.header("Cache-Control", "no-store");
14267
+ if (provider !== "codex" && provider !== "xai" && provider !== "github-copilot" && provider !== "opencode-go") return c.json({ error: "Unsupported subscription provider" }, 404);
14268
+ try {
14269
+ const usage = await getSubscriptionUsage(provider, c.req.raw.signal);
14270
+ return usage ? c.json(usage) : c.json({ error: "Subscription account is not available" }, 404);
14271
+ } catch {
14272
+ return c.json({ error: "Failed to fetch subscription usage" }, 502);
14273
+ }
14274
+ });
13952
14275
  usageRoute.get("/", async (c) => {
13953
14276
  try {
13954
14277
  const usage = await getCopilotUsage();
@@ -14109,4 +14432,4 @@ function createServer(options = {}) {
14109
14432
  createServer();
14110
14433
  export { createServer };
14111
14434
 
14112
- //# sourceMappingURL=server-Jvc5DYJV.js.map
14435
+ //# sourceMappingURL=server-h60svXN0.js.map