news 2026/9/13 12:43:24

CodexBar ZoomMate 提供方深度解析:Cookie 换 Token、Credits 用量窗口、30 天历史与 Statuspage 组件白名单

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CodexBar ZoomMate 提供方深度解析:Cookie 换 Token、Credits 用量窗口、30 天历史与 Statuspage 组件白名单

CodexBar ZoomMate 提供方深度解析:Cookie 换 Token、Credits 用量窗口、30 天历史与 Statuspage 组件白名单

【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBar

CodexBar 的 ZoomMate 提供方以「凭预算上限(budget cap)计费的 Credits 配额」为核心模型,通过 Zoom 官方 Web 客户端的 cookie-to-token 引导端点自动换取短时效 bearer JWT,再调用credits/statuscredits/history两个第一方 API,把今日/30 天用量、预算节奏判定(Pace)内联渲染到菜单栏卡片中。读完本篇,你将掌握 ZoomMate 在 CodexBar 中的完整接入流程(Chrome 自动导入与手动 cURL 捕获两种 Cookie 来源)、bearer 令牌缓存与失效策略、数据字段到 Credits 窗口的映射逻辑、30 天历史分页抓取与日粒度聚合算法,以及 Statuspage.io 状态页组件白名单过滤的实现细节,并能在出问题时依据错误分类表快速定位原因。

提供方模型:单一 Credits 窗口与 Zoom 品牌色

ZoomMate 不是按会话/周窗口限流的提供商,而是一个凭预算上限的 Credits 配额:没有会话窗口、没有周窗口,只有一个主 "Credits" 窗口。这一点直接体现在提供方描述符 ZoomMateProviderDescriptor.swift 的元数据中:

metadata: ProviderMetadata( id: .zoommate, displayName: "ZoomMate", sessionLabel: "Credits", weeklyLabel: "Credits", opusLabel: nil, supportsOpus: false, supportsCredits: true, creditsHint: "Shows used/remaining credits against your ZoomMate budget cap.", ... dashboardURL: "https://zoommate.zoom.us/#/?settings=credit-usage", statusPageURL: "https://www.zoomstatus.com/", statusComponentAllowlist: [ /* 见后文 "Status 页" 一节 */ ]), branding: ProviderBranding( iconStyle: .init(provider: .zoommate), iconResourceName: "ProviderIcon-zoommate", // Zoom Brand Center "Visual identity > Color": // Bloom 为主色,Dawn 与 Midnight 为辅助色 color: ProviderColor(red: 11 / 255, green: 92 / 255, blue: 255 / 255), confettiPalette: [ ProviderColor(hex: 0x0B5CFF), // Bloom(主色) ProviderColor(hex: 0xB4D0F8), // Dawn ProviderColor(hex: 0x00053D), // Midnight ]),

品牌色采用 Zoom 官方核心色板:Bloom(#0B5CFF)作为主色,Dawn(#B4D0F8)与 Midnight(#00053D)为辅助色,出处为 Zoom Brand Center 的 "Visual identity — Color" 页面(源码注释中标注了检索日期 2026-07-18,页面最后修改于 2025-08-28)。同一份描述符还声明了 CLI 名称(cliName: "zoommate"/ProviderCLIConfig(name: "zoommate"))、默认关闭(defaultEnabled: false)、不进入桌面小组件(widgetSelectable: false)等关键属性。

配置方式一:Chrome 自动导入(推荐)

自动模式面向仅 Chrome的 macOS 用户,步骤只有两步:

  1. 在 Chrome 中登录 ZoomMate;
  2. Settings → Providers中启用ZoomMateCookie source保持默认的Auto

从 Cookie 到 Bearer 的完整链路

自动路径的核心思想是「用长寿命的会话 Cookie 换取短寿命的 bearer token」。CodexBar 从 Chrome 的 Cookie 罐导入 ZoomMate/Zoom 会话 Cookie(覆盖zoommate.zoom.usai.zoom.us以及父域zoom.us—— Zoom 的 SSO 会话 Cookie 实际作用在父域上),然后调用 ZoomMate Web 前端自己内部使用的同一个 cookie-to-token 引导端点换取短期 bearer token,全程无需手动粘贴:

GET https://ai.zoom.us/ai-computer/api/v1/login/?continue=https://zoommate.zoom.us/

这一调用在 ZoomMateUsageFetcher.swift 中实现为mintBearerToken:请求携带指定主机的 Cookie 头,固定Origin/Refererhttps://zoommate.zoom.us,响应体中的data.nak就是新铸造的 bearer JWT;data.user_profile.email(可选)顺带提供账号身份。由于 bearer token 由(寿命长得多)的会话 Cookie 铸造而来,只要 Chrome 中保持登录状态就能持续工作:铸造出的 token 存放在进程生命周期的内存缓存中,跨刷新复用直到接近过期,然后从同一批 Cookie 重新铸造,不需要重新粘贴。若 Chrome 中没有会话 Cookie,CodexBar 报告noSession;若 Zoom 拒绝已有会话,则报告invalidCredentials

自动路径刻意只尝试 ChromebrowserCookieOrder在 macOS 下为[.chrome]),以避免其他浏览器存储库带来意外的 Keychain 授权弹窗;其他浏览器只能走手动捕获。

Keychain 边界与共享 Cookie 缓存

Chrome 的 Cookie 解密密钥存放在 macOS Keychain 中,因此 CodexBar只在用户主动发起的刷新时(菜单/设置刷新,或codexbar cookie命令)读取 Chrome 的 Cookie 存储。这一约束在源码中体现为resolveRequestContext的注释:Chrome 的 Cookie 解密被BrowserCookieAccessGate限制在用户发起的上下文中。

一旦某次新鲜导入验证成功(cookie-to-token 铸造成功),验证过的按主机划分的 Cookie 头会被保存到 CodexBar 的共享 Keychain Cookie 缓存(com.steipete.codexbar.cache,account 为cookie.zoommate,与其他 Cookie 类提供商相同),并在下次重新导入 Chrome 之前优先复用:

if allowCachedCookieHeader, let cached = CookieHeaderCache.load(provider: .zoommate), let cookieHeaders = ZoomMateCookieHeaders.decodeFromStorage(cached.cookieHeader), !cookieHeaders.isEmpty { logger?("[zoommate] Using cached cookie headers from \(cached.sourceLabel)") return try await Self.requestContext( forCookieHeaders: cookieHeaders, persistingValidatedHeaderAs: nil, ...) }

背景刷新与随附的codexbarCLI完全基于这些缓存头运行,从不触碰 Chrome 存储、不触发 Keychain 提示。若 Zoom 拒绝缓存的会话,CodexBar 会丢弃缓存并重试一次新鲜的 Chrome 导入——但仅在用户发起的上下文中;背景刷新则报告noSession,直到下一次用户刷新。这一「重试一次」逻辑位于统一抓取策略ZoomMateWebFetchStrategy.fetch中:

do { return try await self.fetchOnce(context, allowCachedCookieHeader: true) } catch ZoomMateUsageError.invalidCredentials where cookieSource == .auto { // 持久化的 Cookie 会话(或从它铸造的 bearer)被拒绝。 // 丢弃缓存头,针对全新浏览器导入重试一次; // 用户发起之外的上下文中导入被门控拦截,重试将直接暴露 noSession。 CookieHeaderCache.clear(provider: .zoommate) return try await self.fetchOnce(context, allowCachedCookieHeader: false) }

Cookie 导入的作用域收窄

ZoomMateCookieImporter.swift 从 Chrome 读取三个域的 Cookie(cookieDomains = ["zoommate.zoom.us", "ai.zoom.us", "zoom.us"],父域用于发现父作用域的 SSO Cookie,如_zm_*cf_clearance等),随后按 RFC 6265 域匹配规则把导入集合收窄到浏览器实际会附加给ai.zoom.us/zoommate.zoom.us的 Cookie,丢弃作用域在其他无关*.zoom.us兄弟子域上的记录:

public struct ZoomMateCookieHeaders: Codable, Equatable, Sendable { static let allowedHosts = ["ai.zoom.us", "zoommate.zoom.us"] ... }

把「目的地主机」内嵌在凭据值中(按主机的头字典headersByHost),从结构上保证了主机故障切换(failover)不可能把叶子主机的 Cookie 复用到其兄弟主机上。

配置方式二:手动粘贴 cURL 捕获

将 ZoomMate 提供方设置中的Cookie source改为Manual,然后粘贴从 DevTools 捕获的完整curl命令。捕获步骤:

  1. 打开 ZoomMate 并登录;
  2. 进入 AI 积分用量页面(Settings → AI credit usage 或等效入口);
  3. 打开开发者工具 → Network 标签页;
  4. 重新加载页面,找到credits/status请求(GET https://ai.zoom.us/ai-computer/api/v1/credits/status);
  5. 右键 → Copy →Copy as cURL
  6. 把完整curl命令粘贴到 CodexBar 设置中的ZoomMate capture字段。

手动模式与某些其他「粘贴型」提供方的一个关键差异:ZoomMate 的转发头白名单包含Authorization—— 这正是必需的凭据(见下文 "常见错误")。ZoomMateUsageFetcher.swift 中的白名单定义:

/// 手动 `.web` cURL 捕获的转发头白名单。与 T3 Chat 不同,这里 /// 必须包含 `authorization`,因为 ZoomMate 的凭据是 bearer token 而非 cookie。 private static let forwardedManualHeaders = [ "authorization": "Authorization", "cookie": "Cookie", "user-agent": "User-Agent", "accept": "Accept", "accept-language": "Accept-Language", "sec-fetch-dest": "Sec-Fetch-Dest", "sec-fetch-mode": "Sec-Fetch-Mode", "sec-fetch-site": "Sec-Fetch-Site", ]

捕获的合法性由isAllowedCaptureURL严格校验,可概括为四条规则:

  • Cookie与选定的浏览器头可能被转发,但OriginReferer始终被替换为固定值https://zoommate.zoom.us(防止捕获值扩大第一方请求边界);
  • 仅接受ai.zoom.uszoommate.zoom.us上、HTTPS 的/ai-computer/api/v1/credits/status端点 —— DevTools 中请求可能显示在任一口主机上(两者当前提供同一套第一方 API);源码层面还要求 URL 无端口、无 userinfo、无 query、无 fragment;
  • 捕获的Cookie绑定到该请求所在的主机:CodexBar 先尝试捕获主机,若因非鉴权类失败回退到兄弟主机,则绝不转发原主机的 Cookie;
  • 解析不出非空的Authorization头时返回noCapture

Bearer Token 生命周期(约一小时)与内存缓存策略

ZoomMate 的 bearer token 寿命很短(通常约一小时),而会话 Cookie 的寿命长得多。因此两种模式下的行为分别是:

  • 自动模式:只要保持 Chrome 登录就无需任何操作;CodexBar 从会话 Cookie 铸造 bearer token 并在内存中复用,接近过期时自动重新铸造;
  • 手动模式:粘贴的 token 过期(约每小时)后需要重新捕获并粘贴新的curl命令,表现为invalidCredentials。这是预期行为而非 Bug —— 切换到自动模式即可完全规避。

令牌缓存的安全属性由 ZoomMateBearerTokenCache.swift 实现,值得逐条理解:

actor ZoomMateBearerTokenCache { static let shared = ZoomMateBearerTokenCache() /// 在 JWT 自身 exp 之前这么多秒就刷新, /// 避免在途请求骑着一个中途过期的 token。 static let refreshSkew: TimeInterval = 60 ... }
  • 进程生命周期、纯内存:每次启动缓存为空,铸造出的 bearer 绝不持久化;
  • 不可逆键:缓存键是源主机作用域 Cookie 头的 SHA-256 十六进制摘要(ZoomMateBearerTokenCache.key(forCookieHeaders:)),不同浏览器会话/账号不会碰撞,且原始 Cookie 不作为键存储;
  • 可判定过期才缓存:仅当 JWT 能解析出exp声明时才入缓存,且只在now < exp - 60s时发放(validEntry(forKey:now:));读不到过期时间的 token 永远不入缓存,调用方退化为「每次刷新都重新铸造」,缓存因此不可能发出一个已过期的 token;
  • 401/403 驱逐:下游请求被拒绝(会话在自身过期前被吊销)时,策略层调用invalidateCachedBearerToken驱逐缓存条目,下一次刷新立即重新铸造(见ZoomMateWebFetchStrategyfetchCreditsStatus抛出invalidCredentials时的处理)。

exp的解析在expiry(fromJWT:)中完成:对 JWT 第二段做 base64url 解码后读取 JSON 中的数值exp声明(不做签名验证——token 是自己铸造的)。

数据源:Credits Status 与 Credits History

每次刷新 CodexBar 会发出至多几个 GET 请求:

GET https://ai.zoom.us/ai-computer/api/v1/credits/status GET https://ai.zoom.us/ai-computer/api/v1/credits/history?app_id=demo_app&limit=50&page=<n>&sort_by=time&sort_order=desc&start_time=<ISO8601>&end_time=<ISO8601>

主机容错规则:自动模式请求先尝试ai.zoom.us,若以非鉴权错误失败则在zoommate.zoom.us上以相同路径重试一次;手动模式从捕获命令中的主机开始,非鉴权失败时切换到另一主机(不带捕获主机的 Cookie)。源码中这一机制是withAPIHostFailover,其语义在注释中写得很明确:

apiHosts顺序中的每个主机执行一次 API 请求,返回首个成功结果。鉴权拒绝和解析失败立即传播——主机已经应答,换到可互换的备用主机无济于事;其他任何情况(主机不可达、非鉴权 HTTP 错误)则落到下一个主机,这样任一主机退役时提供方仍可用。

状态快照与字段映射

credits/status响应的data.credit_status对象被解码为 ZoomMateModels.swift 中的ZoomMateCreditStatus结构体(budget_capused_creditremaining_creditoverage_creditallow_overagecycle_start_datecycle_end_dateis_quota_availableis_unlimited,日期均为 epoch 毫秒)。映射到 CodexBar 的 Credits 窗口:

源字段CodexBar 映射
used_credit/budget_cap主窗口usedPercent(钳制到 0–100)
cycle_end_date主窗口重置时间(epoch 毫秒)
is_unlimited/budget_cap <= 0usedPercent强制为 0,重置倒计时省略

没有次窗口;resetDescription恒为"Credits"。映射实现位于ZoomMateUsageSnapshot.toUsageSnapshot

let usedPercent: Double = if isUnlimited || budgetCap <= 0 { 0 } else { min(100, max(0, usedCredit / budgetCap * 100)) } let resetsAt: Date? = (isUnlimited || budgetCap <= 0) ? nil : zoomMateDate(fromMilliseconds: self.creditStatus.cycleEndDate) let primary = RateWindow( usedPercent: usedPercent, windowMinutes: nil, resetsAt: resetsAt, resetDescription: "Credits")

历史分页:双重终止条件与失败降级

credits/history请求是分页的(循环page直到page * limit + records.length达到响应中扁平的data.total,或某页记录全部早于请求的start_time),覆盖最近 30 天;真实账号的历史量级不大(总共几十条记录),因此通常只需 1–2 个请求。ZoomMateCreditsHistoryFetcher.swift 中还有两个工程性护栏:

/// 确认对真实账号足够便宜:30 天历史在此尺寸下最多两页, /// 远低于任何实际限流担忧。比 Web UI 的 10 更大的 limit 减少了往返次数。 public static let defaultPageLimit = 50 /// 每次抓取的分页请求硬上限,独立于账号实际历史大小—— /// 防止意外的大(或行为异常的)账号/响应(如永远满足不了的 total) /// 变成无界抓取循环。 public static let maxPages = 20

分页循环的第二个终止条件值得单独说明:total反映的是账号整个历史而非请求窗口,若存在服务端过滤怪癖,仅靠total可能导致越过窗口实际需要范围的额外分页。因此当某页记录(按time降序)全部早于startTime时直接停止。整个分页循环以「单位」参与主机故障切换,保证一个快照的所有页来自同一主机。

app_id以固定占位符demo_app发送,与 ZoomMate 自家 Web UI 一致——它不对结果集做按集成方过滤。历史抓取失败不致命:它从不阻塞主credits/status快照,只意味着本次刷新省略历史仪表盘(策略层fetchOncehistory捕获invalidCredentials与其他错误均置为nil,且前者的同时会驱逐缓存的 bearer)。

账号身份(仅自动模式)

用于铸造 bearer token 的同一登录引导响应(GET .../login/?continue=...)还携带data.user_profile对象。CodexBar 从中读取user_profile.email作为提供方的accountEmail—— 与 Codex/Claude 填充的同一身份字段 —— 使菜单卡片账号行显示当前登录者,呈现方式与这些提供方一致;解析到邮箱时loginMethod设为"Cookie"。这是纯粹附加性的富集:user_profileemail缺失/不存在永远不会使 token 铸造失败,只是身份保持未设置。手动(cURL 捕获)模式没有等效的引导调用,accountEmail在该模式下保持nil。这一行为在快照映射中直接可见:

let identity = ProviderIdentitySnapshot( providerID: .zoommate, accountEmail: accountEmail, accountOrganization: nil, loginMethod: accountEmail != nil ? "Cookie" : nil)

Credits 历史与节奏(Pace):内联仪表盘

启用 ZoomMate 且历史数据可用时,菜单 Credits 卡片会在积分进度条正下方内联显示 Today/30d 仪表盘与节奏判定 —— 同时出现在 ZoomMate 自有标签页和 Overview 聚合视图中,与 Claude/Codex 的内联仪表盘一致。它包含三部分:

  • 两个 KPI 磁贴,复用 Claude/Codex 渲染内联仪表盘所用的同一个InlineUsageDashboardContent组件(InlineUsageDashboardContent.swift):Today(强调显示 —— 当前日历日在credits/history中累加的cost,今天尚无记录则为 0)与30d credits(整个 30 天窗口的合计)。这对应 Codex 的 "Today" / "30d cost" 磁贴对和 Claude 的 "Today" / "30d spend" 磁贴,只是把 "$"/成本单位换成了 "credits"(ZoomMate 没有美元成本概念);
  • 磁贴下方的一排迷你用量条,每个有 ZoomMate 用量的日历日一根(credits/history的按事件台账按日汇总),上限为最近 30 天,渲染为 ZoomMate 品牌色#0B5CFF—— 与 Codex/Claude 自身的条密度及按提供方着色完全一致;
  • 节奏行("Pace: on track" / "Pace: N% ahead of budget" / "Pace: N% behind budget"),渲染为迷你条下方的普通内联仪表盘详情行。它由credits/statusbudget_cap、累计used_credit以及当前计费周期的cycle_start_date/cycle_end_date计算 —— 把实际用量与周期线性已过时间占比对比。它复用UsagePace既有的阶段阈值(on track / slightly ahead / ahead / far ahead / slightly behind / behind / far behind),而非 ZoomMate 专属刻度,措辞因此与其他 CodexBar 节奏指示器一致。

源码中的节奏计算值得注意一个细节:ZoomMate 计费周期长度任意(不是固定周节律),所以把windowMinutes设为实际周期分钟数,workDays: nil使UsagePace.weekly()的工作日感知分支永不触发,退化为纯粹的线性周期占比对比:

public func pacingVerdict(now: Date = Date()) -> UsagePace? { guard let budgetCap, budgetCap > 0, self.isUnlimited != true, let cycleStartMillis = self.cycleStartDate, let cycleEndMillis = self.cycleEndDate else { return nil } ... let window = RateWindow( usedPercent: usedPercent, windowMinutes: cycleMinutes, resetsAt: cycleEnd, resetDescription: "Credits") return UsagePace.weekly(window: window, now: now, workDays: nil) }

聚合规则(dailyBreakdown(),见 ZoomMateModels.swift):

  • is_deleted历史记录从 KPI 磁贴和迷你条中都排除;仍在运行的会话(is_running: true计入,因为其cost反映迄今消耗;
  • 30 天窗口在抓取时(请求的start_time)和展示时dailyBreakdown()无论如何都过滤到最近 30 个日历日)双重强制执行,图表的日历跨度因此有保证;
  • 无法解析timecost为负的记录被防御性跳过;
  • 节奏行只需要每次必抓的credits/status快照,因此即使某次刷新credits/history失败或无数据也能出现;
  • 内联区块以「有非空日粒度分解可计算的节奏判定」为门控 —— 空/失败的历史抓取会静默省略整个区块,而不是显示一个空仪表盘。

Status 页:Statuspage.io 共享通道 + 组件白名单

ZoomMate 的描述符指向 Zoom 的公开状态页(zoomstatus.com),这是一个 Atlassian Statuspage.io 站点 —— 与 Claude 状态页所用平台相同。这意味着整体状态行及其 "Updated …" 副标题通过 CodexBar 既有的共享 Statuspage.io 抓取/解析通道工作,没有ZoomMate 专属的抓取代码。

Zoom 的状态页列出 300+ 组件,被大量与 ZoomMate 无关的服务(Zoom Phone、Contact Center、CX 各自按区域重复)所主导。全部展示在 ZoomMate 的状态下钻中会是噪音,因此组件子菜单被过滤到一个命名白名单:

  • Zoom Meetings
  • ZoomMate
  • My Notes
  • Zoom Workflows
  • Zoom Developer Platform
  • Zoom Support
  • Zoom Website

白名单在描述符元数据statusComponentAllowlist中声明(见上文描述符代码),过滤发生在 StatusItemController+Menu.swift 的statusComponentsSubmenuProviders与描述符驱动的filterStatusComponents。其容错语义:

  • 对实时 API 返回的内容做大小写敏感的组件/分组名精确匹配,容忍 Zoom 侧重命名或移除任意子集:缺失的名字被静默省略,绝非错误;
  • 若白名单名字一个都不在场,子菜单回退到其他提供方已有的 "components not loaded" 空状态(没有 ZoomMate 专属空状态 UI);
  • "Zoom Meetings" 和 "Zoom Workflows" 在 Zoom 的数据中本身就是分组(各有子组件);白名单中的分组展开时显示其完整既有子列表,与其他提供方一致;
  • 其余所有提供方都没有描述符白名单,保持展示其数据源返回的全部组件,不受影响。

CLI 使用

codexbar usage --provider zoommate

CLI 复用先前一次验证成功刷新所缓存的主机作用域 Cookie 头;它自身不读取 Chrome 的 Cookie 存储。若尚不存在缓存会话(noSession),从应用刷新一次,或在终端播种缓存:

codexbar cookie --provider zoommate

(可加--allow-keychain-prompt确认 Chrome Cookie 解密可能触发提示。)

注意能力边界:ZoomMate 不提供 token 成本数据(描述符中supportsTokenCost: false),且暂不支持 CodexBar 桌面小组件 —— 这包括上文提到的 credits 历史仪表盘与状态页,二者目前均为应用菜单专属

常见错误速查

错误原因修复
noCapture选择了手动模式但捕获为空、域名不符、或缺少可解析的Authorizationai.zoom.uszoommate.zoom.us重新粘贴 HTTPScredits/status请求的 cURL 捕获
noSession自动模式下既无缓存会话,也没有可读取的 ZoomMate/Zoom 会话 Cookie(背景刷新与 CLI 从不直接读 Chrome)在 Chrome 登录 ZoomMate 并从应用刷新一次(或codexbar cookie --provider zoommate),或切换到手动粘贴捕获
invalidCredentialsHTTP 401/403 —— token 过期(约一小时)或被吊销重新登录(自动)或重新粘贴新捕获(手动)
apiError其他任何非 200 HTTP 状态检查 ZoomMate 状态页;稍后重试
parseFailedHTTP 200 响应体不含预期的credit_status形状附带脱敏响应样本提交 CodexBar issue

五种错误在 ZoomMateModels.swift 中统一建模为ZoomMateUsageError枚举,每个 case 都携带用户可读的errorDescription

隐私与请求边界小结

  • 铸造出的 bearer token 只存在于进程生命周期的内存缓存中,绝不持久化;持久化到共享 Keychain Cookie 缓存的是验证过的主机作用域 Cookie 头(仅这些头,绝不含 bearer),生命周期与其他 Cookie 类提供方(Claude Web、Perplexity、OpenCode 等)一致;
  • ZoomMate 日志刻意省略 Cookie、bearer token、nak值与原始响应体;
  • 所有鉴权与积分请求都使用两个第一方 API 主机上的固定 HTTPS URL,每个请求只携带作用域到其目标主机的 Cookie;Origin/Referer/continue固定为 ZoomMate Web 客户端值;父域zoom.us的作用域仅用于发现父作用域 SSO Cookie,不授权对任意 Zoom 子域的请求;
  • ZoomMate 目前没有公开文档的公共 API,因此该提供方依赖产品自身的第一方 Web 客户端端点;这种「cookie 换 bearer」形状沿用了 CodexBar 在 Factory 提供方 WorkOS Cookie 交换中的既有先例。

关键文件索引

  • ZoomMateProviderDescriptor.swift — 提供方元数据(含statusPageURL与状态组件白名单)、品牌色,以及统一抓取策略ZoomMateWebFetchStrategy(同时调用credits/statuscredits/history,处理缓存失效与一次重试)
  • ZoomMateUsageFetcher.swift — credits/status 请求、cURL 捕获解析、cookie-to-token 铸造、主机故障切换、JWTexp解析
  • ZoomMateCreditsHistoryFetcher.swift — credits/history 请求(limit=50maxPages=20、日期边界停止分页)与ZoomMateCreditsHistorySnapshot模型
  • ZoomMateModels.swift — 响应解码、错误分类(ZoomMateUsageError)、窗口映射(toUsageSnapshot)、日粒度聚合(dailyBreakdown())、今日合计(todayCreditsUsed(now:calendar:))、节奏判定(pacingVerdict
  • ZoomMateCookieImporter.swift — Chrome Cookie 罐导入(仅 macOS)与 RFC 6265 域匹配收窄
  • ZoomMateBearerTokenCache.swift — 进程生命周期内存 bearer 缓存(SHA-256 键、60s 刷新偏斜、401/403 驱逐)
  • ZoomMateProviderSettings.swift — Cookie 来源与手动捕获的持久化模型
  • InlineUsageDashboardContent.swift — 与 Claude/Codex/OpenRouter 等共享的 Today/30d KPI 磁贴 + 迷你条视图;ZoomMate 经由同一组件渲染
  • StatusItemController+Menu.swift —statusComponentsSubmenuProviders与描述符驱动的filterStatusComponents
  • 测试:ZoomMateUsageFetcherTests.swift、ZoomMateCreditsHistoryFetcherTests.swift、ZoomMateCookieCacheTests.swift

最后说明适用前提:自动导入路径仅支持 macOS + Chrome(其他平台下resolveRequestContext直接抛noSessionisAvailable在非 macOS 下返回 false),且依赖 ZoomMate 第一方 Web 端点的行为保持稳定;任一 API 主机未来退役时,withAPIHostFailover的双主机回退是当前设计给出的缓冲。

【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBar

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 12:42:15

智能小区电动汽车充电博弈定价策略与MATLAB实现

1. 项目背景与核心挑战智能小区中的电动汽车充电管理正面临着一个典型的两难困境&#xff1a;电力代理商希望最大化售电收益&#xff0c;而车主则追求充电成本最小化。这种利益冲突在传统定价模式下往往导致供需失衡——要么电价过高抑制需求&#xff0c;要么低价策略让代理商无…

作者头像 李华
网站建设 2026/9/13 12:42:11

grbl v1.1运动控制内核全解析:从G代码到步进脉冲

简介&#xff1a;这是一份基于grbl v1.1的完整开源源码包&#xff0c;面向桌面级CNC雕刻机与3D打印机的嵌入式开发者、硬件爱好者和二次开发人员&#xff0c;用于在Arduino平台上实现高效率、低成本的G代码解释与运动控制。压缩包共69个文件&#xff0c;以C语言源码&#xff08…

作者头像 李华
网站建设 2026/9/13 12:40:46

全球股市估值数据分析与应用实战指南

1. 全球股市估值数据的核心价值与应用场景全球股市估值数据是投资者进行跨国资产配置的基石工具。不同于单一市场分析&#xff0c;这类数据通过横向比较不同国家、地区股票市场的估值水平&#xff0c;帮助投资者识别被低估或高估的市场机会。以2023年第三季度数据为例&#xff…

作者头像 李华
网站建设 2026/9/13 12:39:13

全排列算法:递归与迭代实现及应用解析

1. 全排列问题概述全排列问题是计算机科学和数学中一个经典的基础问题。简单来说&#xff0c;给定一组不同的元素&#xff0c;我们需要找出所有可能的排列方式。比如对于数字[1,2,3]&#xff0c;它的全排列包括[1,2,3]、[1,3,2]、[2,1,3]、[2,3,1]、[3,1,2]、[3,2,1]这6种不同的…

作者头像 李华
网站建设 2026/9/13 12:38:05

非线性DSGE求解:Promes工具箱中的投影方法解析

简介&#xff1a;一套基于投影方法求解DSGE模型的Matlab实现方案&#xff0c;面向经济学、金融学及数学方向的研究生、科研人员&#xff0c;以及需要完成相关课程设计或毕业设计的本硕学生&#xff0c;适合具备一定宏观经济学与Matlab基础的读者。方案内含完整的参数化编程框架…

作者头像 李华