Claude Counter 架构拆解:Manifest V3 下 Content Script 与 MAIN World 的 postMessage 桥接通信设计
Claude Counter 架构拆解Manifest V3 下 Content Script 与 MAIN World 的 postMessage 桥接通信设计【免费下载链接】claude-counterA minimal browser extension that shows token count, cache timer, and usage bars on claude.ai.项目地址: https://gitcode.com/gh_mirrors/cl/claude-counterClaude Counter是一款轻量级 Chrome 浏览器扩展能在 claude.ai 页面顶部实时显示当前对话的 Token 计数、5 分钟缓存倒计时以及 5 小时/每周的使用量进度条。它的核心架构难题在于Manifest V3 扩展的 Content Script 运行在**隔离世界isolated world**中无法直接读取页面 JS 发出的 fetch 请求也无法拿到会话 Cookie。本文拆解 Claude Counter 如何用postMessage在 Content Script 与MAIN World之间搭建一座通信桥让扩展偷听到 API 响应并精准注入 UI——这是所有想拦截页面网络数据的 MV3 扩展都会遇到的经典问题。 先看懂问题MV3 扩展的双世界隔离在 Manifest V3 中浏览器把每个页面分成了两个互不相通的 JS 世界世界能做什么不能做什么isolated worldContent Script 默认所在安全访问 DOM、调用chrome.runtimeAPI看不到页面 JS 对象无法拦截window.fetch读不到会话 CookieMAIN world页面本身拥有完整页面权限fetch、Cookie、SSE 流不能直接调用扩展 APIClaude Counter 需要三样东西全在 MAIN world 里拦截window.fetch—— 捕获 Claude 前端的 completion 请求、对话树请求和 SSE 流带 Cookie 的请求—— 以用户身份调用/api/organizations/{orgId}/usagecrypto.subtle哈希—— 隔离世界里的 Content Script 没有 SubtleCrypto没法对消息做 SHA-256 指纹。解决方案就是本文的主角桥接bridge模式—— 向 MAIN world 注入一个脚本当内应两边用window.postMessage对话。️ 架构总览一份 manifest 两个角色打开 manifest.json整个通信骨架就藏在两段配置里content_scripts: [ { matches: [https://claude.ai/*], js: [src/content/constants.js, src/content/bridge-client.js, src/vendor/o200k_base.js, src/content/tokens.js, src/content/ui.js, src/content/main.js] } ], web_accessible_resources: [ { resources: [src/injected/bridge.js], matches: [https://claude.ai/*] } ]content_scriptsmanifest.json#L31-L44按依赖顺序加载 6 个脚本到隔离世界它们共享一个全局命名空间globalThis.ClaudeCounter下称CCweb_accessible_resourcesmanifest.json#L45-L50把 src/injected/bridge.js 声明为可被页面访问的资源——这是 MAIN world 侧内应的门票没有它页面无法加载该脚本。┌─────────────────── claude.ai 页面 ───────────────────┐ │ │ │ MAIN world postMessage(窗口级广播) │ │ ┌─────────────┐ ◄────────────────────────────────► │ │ │ bridge.js │ { cc:ClaudeCounter, type, … } │ │ │ 包装 fetch/ │ │ │ │ history/SSE │ isolated world │ │ └──────▲──────┘ ┌──────────────────────────────┐ │ │ │script │ bridge-client.js (桥客户端) │ │ │ 注入 script │ main.js / tokens.js / ui.js │ │ └─────────┴─────────┴──────────────────────────────┘ │ 第一步Content Script 把内应注入页面注入动作由 src/content/bridge-client.js 中的injectBridgeOnce()完成核心逻辑在 bridge-client.js#L91-L111const script document.createElement(script); script.src runtime.getURL(src/injected/bridge.js); (document.head || document.documentElement).appendChild(script);三个值得注意的工程细节runtime.getURL()把扩展内部路径解析成chrome-extension://绝对地址配合web_accessible_resources才能被页面加载单例保证bridgeReadyPromise缓存 Promise重复调用不会二次注入就绪门控src/content/main.js#L139 中所有依赖桥的请求都会先await bridgeReady确保内应上线后才发令。 postMessage 协议设计请求-响应 事件两种模式这是整个架构的灵魂。bridge.js 和 bridge-client.js 之间约定了一个极简协议所有消息都带cc: ClaudeCounter标记做身份过滤① 事件推送MAIN → Content单向// bridge.js 中只有两行bridge.js#L52-L54 window.postMessage({ cc: ClaudeCounter, type, payload }, *);事件名都以cc:前缀命名避免和页面自身消息混淆事件触发时机用途cc:generation_start拦截到/completionPOST 请求UI 立刻把缓存条置为等待中cc:conversation抓到对话树响应重新计算 Token 数cc:message_limit从 SSE 流里解析出用量数据更新 5h/7d 进度条cc:urlchangehistory.pushState被调用感知 SPA 路由切换② 请求-响应Content → MAIN → Content客户端发起请求时生成requestId把 Promise 存进_pendingMap超时默认 10 秒bridge-client.js#L54-L74服务端完成后用同一requestId回cc:response客户端据此 resolve/reject。目前支持三种kindhash借用 MAIN world 的crypto.subtle.digest(SHA-256)计算消息指纹供 src/content/tokens.js 做 Token 缓存见后文usage以用户身份credentials: include请求/api/organizations/{orgId}/usageconversation主动拉取对话树作为被动拦截之外的兜底。安全细节值得抄作业两侧监听器都先校验event.source ! window直接丢弃再检查data.cc ! ClaudeCounter防止页面里其他脚本伪造消息、或跨 iframe 消息误伤bridge.js#L130-L133、bridge-client.js#L19-L22。 MAIN World 侧的内应都在拦什么bridge.js 全文只有 183 行但每处都卡得极准抢在框架前包装window.fetchbridge.js#L7。注释写得很直白——Capture original fetch before anyone else can wrap it。React 等框架可能在之后缓存 fetch 的引用包装太晚就漏单了同样抢先包装history.pushState / replaceStatebridge.js#L10-L23每次调用后广播cc:urlchange自定义事件。Content Script 侧再叠加popstate监听前后覆盖 SPA 前进/后退/编程式跳转三种导航路径main.js#L61-L81SSE 流式解析对content-type: text/event-stream的响应执行response.clone()用getReader()逐行读data:事件只挑出message_limit转发bridge.js#L96-L128。注意它克隆的是 Response 本体、原样返回给页面且整体包在 try/catch 里——注释写着 best-effort; dont break claude.ai桥挂了也不能影响用户正常聊天对话树嗅探匹配/chat_conversations/…?tree的 URL解析出orgId和conversationId后把 JSON 转发出去bridge.js#L86-L94。 Content Script 侧事件驱动的 UI 更新main.js 把桥事件接成三条业务线main.js#L217-L219cc:generation_start→ UI 缓存条进入pending态提示新一轮生成中cc:conversation→ 调用CC.tokens.computeConversationMetrics()重算 Tokencc:message_limit→ SSE 带来的是精确未取整的用量小数比 Claude 原生/usage页更准直接刷新进度条。DOM 注入则靠MutationObserver轮询代替定时轮询waitForElement()main.js#L30-L57会在锚点元素出现的第一帧把 UI 挂上去。此外还有一个秒级tick()main.js#L291-L316负责倒计时走表并在 5h/7d 窗口到期时主动刷新——因为 SSE 只在用户发消息时才推数据窗口翻转那一刻必须自己伸手去拉。⚡ 一个隐藏亮点把 SHA-256 指纹也走桥Token 计算是最贵的操作tokens.js 的TokenCache用消息 ID 内容指纹避免重复计数。但隔离世界没有crypto.subtle于是它把待哈希文本通过桥发给 MAIN world 算完再拿回 8 字节前缀tokens.js#L135-L151——又一次印证桥的价值它不只是数据通道还是能力代理。 文件地图与阅读路线想亲手验证上述设计按这个顺序读代码效率最高文件角色manifest.json注入配置总入口先看两个 script 列表src/content/bridge-client.js桥客户端注入 请求-响应 事件订阅src/injected/bridge.jsMAIN world 内应fetch/SSE/history 拦截src/content/main.js业务编排导航感知、用量刷新、秒级 ticksrc/content/tokens.js对话树解析 缓存 Token 计数src/content/ui.js进度条、倒计时、长按提示等纯 UIsrc/content/constants.jsDOM 选择器、5 分钟缓存窗口、200k 上限不想装扩展的用户也可以看 userscript/claude-counter.user.js它是同一套逻辑的用户脚本版本。✅ 总结三条可复用的 MV3 桥接经验能看不到页面 JS就用web_accessible_resources 动态script把逻辑送进 MAIN world隔离世界只留指挥官协议要双向完备用requestId把 Promise 和消息对上请求-响应同时保留单向事件通道推送再给每个request配超时桥死了也不会卡死页面逻辑防御式拦截克隆 Response、全程 try/catch、优先缓存原始 fetch——扩展是寄生者永远不能影响宿主页面的正常行为。看懂了 Claude Counter 这座 183 行的桥你也就掌握了 Manifest V3 下Content Script ↔ MAIN World 通信的标准答案。【免费下载链接】claude-counterA minimal browser extension that shows token count, cache timer, and usage bars on claude.ai.项目地址: https://gitcode.com/gh_mirrors/cl/claude-counter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

SIMPACK轨道谱.tre文件生成与调试全指南

SIMPACK轨道谱.tre文件生成与调试全指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 2:00:41 阅读更多 →
Nav2 系统级集成测试实战指南:从 Gazebo 仿真到导航栈验收(nav2_system_tests 全解析)

Nav2 系统级集成测试实战指南:从 Gazebo 仿真到导航栈验收(nav2_system_tests 全解析)

机器人ROS自动驾驶 【免费下载链接】navigation2 ROS 2 Navigation Framework and System 项目地址: https://gitcode.com/gh_mirrors/na/navigation2 点击查看 免费下载 Nav2(ROS 2 Navigation Framework)的 nav2_system_tests 包承载着整套…

2026/10/4 1:59:40 阅读更多 →
中职对口升学计算机网络基础考点总结与高效复习方法

中职对口升学计算机网络基础考点总结与高效复习方法

简介:计算机网络基础是网络技术学习的核心入门内容,也是中职对口升学计算机类专业的高频必考科目。掌握OSI七层模型与TCP/IP协议栈的分层原理,是理解数据通信与网络架构的关键;而IP地址规划、子网掩码计算、传输层协议对比等知识点…

2026/10/4 1:59:40 阅读更多 →

最新新闻

用MRAM替代Flash:工业控制器防掉电丢数据的完整存储方案

用MRAM替代Flash:工业控制器防掉电丢数据的完整存储方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 3:02:21 阅读更多 →
单表查询SQL:从执行顺序到去重与慢SQL优化全解析

单表查询SQL:从执行顺序到去重与慢SQL优化全解析

单表查询SQL,是数据库开发里出现频率最高、也最容易翻车的基础操作。很多人写了两三年SQL,对付复杂JOIN头头是道,回头写一条SELECT * FROM table WHERE ...却依然踩空值、去重、分组这些坑。这篇文章不聊多表,只把单表查询从执行顺…

2026/10/4 3:02:21 阅读更多 →
Silvaco光电仿真实战:响应度与暗电流的物理建模与校准

Silvaco光电仿真实战:响应度与暗电流的物理建模与校准

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 3:02:21 阅读更多 →
MATLAB频谱分析避坑指南:采样率、FFT点数与PSD校准

MATLAB频谱分析避坑指南:采样率、FFT点数与PSD校准

1. 为什么“一行代码”频谱图反而最容易出错——从MATLAB新手的三个典型崩溃现场说起你刚在知乎看到标题:“一行代码实现MATLAB频谱、功率谱图”,心里一热,复制粘贴进命令行,回车——结果弹出红色报错:Undefined funct…

2026/10/4 3:02:21 阅读更多 →
OpenCV+MediaPipe实现石头剪刀布手势识别:关键点检测与几何规则

OpenCV+MediaPipe实现石头剪刀布手势识别:关键点检测与几何规则

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 3:02:21 阅读更多 →
MT4指标MT5指标

MT4指标MT5指标

HH:HHV(HIGH,13); LL:LLV(LOW,13); HH1:BARSLAST((HH>REF(HH,1))); LL1:BARSLAST((LL<REF(LL,1))); DRAWTEXT(CROSS(HH1,LL1),90,众),COLORWHITE; DRAWTEXT(CROSS(LL1,HH1),90,4),COLORYELLOW; DRAWTEXT(CROSS(HH1,LL1),60,龙),COLORWHITE; DRAWTEXT(CROSS(LL1,HH1),60,8…

2026/10/4 3:01:20 阅读更多 →

日新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 1:00:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/2 10:36:31 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:35 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/3 9:42:36 阅读更多 →