webext-publish
v0.1.1
Published
Upload and publish a WXT-built browser extension to the Chrome Web Store and Microsoft Edge Add-ons via their APIs.
Maintainers
Readme
webext-publish
通过各商店官方 API,把 WXT 构建的浏览器扩展上传并发布到 Chrome Web Store 和 Microsoft Edge Add-ons——一个工具、一份提交到仓库的配置、一套跨所有扩展共用的凭据。
pnpm build && pnpm zip && pnpm publish:allwebext-publish 会上传 zip、等待 Edge 包处理完成,然后向每个商店提交一个新版本进入审核。它不负责构建——先跑你正常的 wxt build && wxt zip。
- Chrome —— 使用
chrome-webstore-upload(OAuth refresh token 流程)。 - Edge —— 使用 Edge Add-ons Update REST API v1.1(API key 鉴权;v1 已于 2024-12-31 停用)。
1. 安装(Install)
pnpm add -D webext-publish在 package.json 中加入脚本:
{
"scripts": {
"publish:chrome": "webext-publish chrome",
"publish:edge": "webext-publish edge",
"publish:all": "webext-publish all"
}
}需要 Node >= 18(用到全局
fetch)。
2. 快速开始(Quick start)
生成共享凭据文件(每个开发者账号一次性):
pnpm exec webext-publish init # 创建 ~/.config/webext-publish/.env(chmod 600)编辑它,填入六个凭据——见下文第 4 节「凭据」。
添加每扩展配置——把
publish.config.json提交到package.json旁边:{ "chrome": { "extensionId": "glmidaajlaanaccljcpgdgjacbcnighb" }, "edge": { "productId": "278a715c-cdb9-4a3d-8477-1c02c3f16291" } }构建并发布:
pnpm build && pnpm zip && pnpm publish:all
全新扩展的第一个版本必须先在各商店后台手动上传一次,之后 API 才能更新它。
3. 每扩展配置(公开,提交到仓库)
webext-publish 从当前目录向上查找 publish.config.json。它装的是两个公开商店 ID——它们在商店页面上可见,离开你的凭据毫无用处,所以应当进仓库,而不是放在 .env 里。
{
"chrome": { "extensionId": "glmidaajlaanaccljcpgdgjacbcnighb" },
"edge": { "productId": "278a715c-cdb9-4a3d-8477-1c02c3f16291" },
"zip": ".output/*-chrome.zip"
}| 字段 | 是什么 | 在哪找 |
|---|---|---|
| chrome.extensionId | 32 位 item ID | Chrome Web Store 详情页 URL(.../detail/<这一段>) |
| edge.productId | Product ID GUID | Edge Partner Center → 扩展概览页,或商店页面的 "Product ID"。不是 Store ID,也不是 CRX ID。 |
| zip | 可选的 zip 路径/glob | 默认:.output/*-chrome.zip 中最新的一个(WXT 命名 <name>-<version>-chrome.zip) |
环境变量覆盖(优先级高于文件):CHROME_EXTENSION_ID、EDGE_PRODUCT_ID、WEBEXT_ZIP。
4. 凭据(secret,共享)
六个账户级密钥,只在仓库外存一份,所有扩展共用:
~/.config/webext-publish/.env # 默认路径;chmod 600
# 用环境变量覆盖路径:
WEBXT_PUBLISH_SHARED_ENV=/path/to/creds.env4.1 示例 .env
webext-publish init 写出的空模板:
# webext-publish shared credentials — account-level, reused across ALL your extensions.
# Keep this file private (chmod 600). Do NOT commit it to any repo.
# ===== Chrome Web Store =====
CHROME_PUBLISHER_ID=
CHROME_CLIENT_ID=
CHROME_CLIENT_SECRET=
CHROME_REFRESH_TOKEN=
# ===== Microsoft Edge Add-ons (API v1.1) =====
EDGE_CLIENT_ID=
EDGE_API_KEY=填好的示例(占位值——请替换成你自己的):
# ===== Chrome Web Store =====
CHROME_PUBLISHER_ID=00000000-0000-0000-0000-000000000000
CHROME_CLIENT_ID=000000000000-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.apps.googleusercontent.com
CHROME_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
CHROME_REFRESH_TOKEN=1//0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# ===== Microsoft Edge Add-ons (API v1.1) =====
EDGE_CLIENT_ID=11111111-1111-1111-1111-111111111111
EDGE_API_KEY="XXXXXXXXXX$YYYYY$ZZZZZZZZZZZZZZZZZZ"含
$的值要加引号。webext-publish用的是dotenv的parse,不会展开$VAR引用,所以原值会被保留。仍建议加引号,避免别的工具(或未来的加载器)把含$的 key 弄坏。
4.2 优先级(Precedence)
凭据按从高到低解析:
- 真实环境变量(如 CI 密钥)——始终胜出。
- 当前目录的本地
.env——单扩展覆盖。 - 共享文件(
~/.config/webext-publish/.env或$WEBEXT_PUBLISH_SHARED_ENV)——最常见的情形。
文件不存在会被静默跳过——全用真实环境变量、不写任何文件也能跑。
4.3 怎么拿到这些凭据
需要 6 个值:Chrome 4 个(CHROME_CLIENT_ID / CHROME_CLIENT_SECRET / CHROME_REFRESH_TOKEN / CHROME_PUBLISHER_ID),Edge 2 个(EDGE_CLIENT_ID / EDGE_API_KEY)。下面分别给出地址、步骤和官方文档。
4.3.1 Chrome Web Store
官方文档
- Chrome Web Store API 总览:https://developer.chrome.com/docs/webstore/api/index
- 凭据获取指南(fregante 维护,图文):https://github.com/fregante/chrome-webstore-upload-keys
步骤 1 — 建 GCP 项目并启用 Chrome Web Store API
- 打开 Google Cloud Console:https://console.cloud.google.com/ ,新建或选一个项目(后续 OAuth client 必须建在同一个项目里,否则 API 返回
403: API has not been used…)。 - 进入「APIs & Services → Library」:https://console.cloud.google.com/apis/library ,搜索 Chrome Web Store API,进入后点 ENABLE。
步骤 2 — 配置 OAuth consent screen
- 打开 OAuth 同意屏幕:https://console.cloud.google.com/apis/credentials/consent 。
- 选 External(工作区账号也可选 Internal),填写应用名、支持邮箱等。
- 在 Test users 里加上你自己的 Google 账号(即 Chrome Web Store 开发者账号那个)。不加会导致第 4 步拿 token 时返回
access_denied。
步骤 3 — 创建 OAuth 2.0 客户端(Desktop app 类型)
- 打开「Credentials」:https://console.cloud.google.com/apis/credentials 。
- Create Credentials → OAuth client ID → Application type 选
Desktop app→ 命名 → 创建。 - 复制 Client ID 和 Client secret → 填入
.env的CHROME_CLIENT_ID/CHROME_CLIENT_SECRET。
步骤 4 — 拿 refresh token(一次性,长期有效)
- 打开 Google OAuth Playground:https://developers.google.com/oauthplayground/ 。
- 右上角齿轮 ⚙ → 勾选 Use your own OAuth credentials → 填入上一步的 Client ID / Client secret。
- 左侧 Step 1 输入 scope(按 chrome-webstore-upload-keys 指南,目前为
https://www.googleapis.com/auth/chromewebstore)→ Authorize APIs。 - 用你的 Web Store 开发者 Google 账号登录并授权。
- Step 2 → Exchange authorization code for tokens → 复制返回的
refresh_token→ 填入CHROME_REFRESH_TOKEN。 - ⚠️ refresh token 只在首次完整显示,复制后妥善保存;丢了就得重跑此步重新生成。
之后 refresh token 过期或被撤销,不用重走整套 Playground 流程——直接跑
webext-publish chrome-refresh-token,会自动复用已有的CHROME_CLIENT_ID/CHROME_CLIENT_SECRET打开浏览器走一遍授权,然后把新 token 写回共享凭据文件。
步骤 5 — 拿 publisherId
- 打开 Chrome Web Store Developer Dashboard:https://chrome.google.com/webstore/devconsole 。
- 进入 Account → Publisher(或 Publisher → Settings),复制 Publisher ID(一个 UUID)→ 填入
CHROME_PUBLISHER_ID。 - 这是账户级 UUID,不是扩展 ID,也不在商店 URL 里。
一套 OAuth client + refresh token 可以发布该账户下所有 Chrome 扩展,无需为每个扩展重复。
4.3.2 Microsoft Edge Add-ons
官方文档
- Edge Add-ons Update REST API 使用指南(v1.1):https://learn.microsoft.com/en-us/microsoft-edge/extensions/update/api/using-addons-api?tabs=v1-1
- REST API 参考:https://learn.microsoft.com/en-us/microsoft-edge/extensions/update/api/addons-api-reference
v1.1 用 API key 鉴权——不需要 tenant、client secret,也不需要换 OAuth token。
步骤 1 — 进入 Partner Center 的 Publish API 页
- 打开 Edge Partner Center:https://partner.microsoft.com/dashboard/microsoftedge 。
- 左侧 Microsoft Edge 程序 → Publish API。
步骤 2 — 启用 v1.1 体验并创建凭据
- 在 "enable the new experience" 旁点 Enable(切到 v1.1 界面;v1 已于 2024-12-31 停用,不要用 v1)。
- 点 Create API credentials(可能要等几分钟)。
- 页面会显示 Client ID 和 API key(含过期时间)。
步骤 3 — 填入 .env
- 复制 Client ID →
EDGE_CLIENT_ID - 复制 API key →
EDGE_API_KEY(值里含$等字符的话加引号,见 4.1 的提示)。 - ⚠️ API key 只在创建/续期时完整显示,复制后妥善保存;过期后回到此页重新生成即可。
一个 API key 可以发布该 Partner Center 账户下所有 Edge 扩展。
5. 用法(Usage)
webext-publish chrome # 上传并发布到 Chrome
webext-publish edge # 上传并发布到 Edge
webext-publish all # 先 chrome 后 edge;任一失败即中止
webext-publish chrome --zip p.zip # 覆盖 zip 路径
webext-publish init # 生成 ~/.config/webext-publish/.env
webext-publish init --force # 覆盖已存在的凭据文件
webext-publish chrome-refresh-token # 重新生成 CHROME_REFRESH_TOKEN(OAuth 授权流程)
webext-publish --help通过 npm scripts(pnpm publish:all)或直接(pnpm exec webext-publish ...)调用。
5.1 工作原理(How it works)
- Chrome —— 用 refresh token 换 access token,上传 zip(
uploadExisting,对IN_PROGRESS最多轮询 120 秒),再用同一个 token 调publish('DEFAULT_PUBLISH')。 - Edge ——
POST .../submissions/draft/package(API key 鉴权)→ 202 +Location里的 operation id → 轮询.../draft/package/operations/{id}直到Succeeded→POST .../submissions→ 202 + operation id → 轮询.../submissions/operations/{id}直到Succeeded。完成后打印后台 URL。
任一步失败,CLI 以 exit code 1 退出并给出清晰信息;all 在第一家失败时不会再去碰第二家。
6. 环境变量参考(Environment reference)
| 变量 | 层 | 用途 |
|---|---|---|
| CHROME_EXTENSION_ID | 身份(覆盖) | 覆盖 publish.config.json 的 chrome.extensionId |
| EDGE_PRODUCT_ID | 身份(覆盖) | 覆盖 edge.productId |
| WEBEXT_ZIP | 身份(覆盖) | 覆盖 zip 路径/glob |
| CHROME_PUBLISHER_ID | 凭据 | Chrome publisher UUID |
| CHROME_CLIENT_ID | 凭据 | Google OAuth client ID |
| CHROME_CLIENT_SECRET | 凭据 | Google OAuth client secret |
| CHROME_REFRESH_TOKEN | 凭据 | 长期 OAuth refresh token |
| EDGE_CLIENT_ID | 凭据 | Edge Partner Center client ID |
| EDGE_API_KEY | 凭据 | Edge Partner Center API key(v1.1) |
| WEBXT_PUBLISH_SHARED_ENV | 路径 | 共享凭据文件的位置 |
7. CI
把凭据放进 CI 提供方的 secret(真实环境变量,优先级最高),不需要任何文件。示例(GitHub Actions):
- run: pnpm build && pnpm zip && pnpm publish:all
env:
CHROME_PUBLISHER_ID: ${{ secrets.CHROME_PUBLISHER_ID }}
CHROME_CLIENT_ID: ${{ secrets.CHROME_CLIENT_ID }}
CHROME_CLIENT_SECRET: ${{ secrets.CHROME_CLIENT_SECRET }}
CHROME_REFRESH_TOKEN: ${{ secrets.CHROME_REFRESH_TOKEN }}
EDGE_CLIENT_ID: ${{ secrets.EDGE_CLIENT_ID }}
EDGE_API_KEY: ${{ secrets.EDGE_API_KEY }}publish.config.json(公开 ID)已提交, checkout 里就有。
8. 商店侧一次性注意事项(Store-side gotchas)
Chrome Web Store API 必须与 OAuth client 在同一个 GCP 项目里启用,否则 API 返回
403: API has not been used…。权限说明(Permissions justification):首次 API 发布会被以
does not meet requirements拒绝,直到你在后台 Permissions 标签里为每个权限填一次说明。常见权限的参考文案:- tabs — 读取活动标签页的 URL/title(
tabs.query、tabs.onActivated、tabs.onUpdated),把 HTTP 采集限定在活动标签页。只读;不修改标签页、导航或内容。 - webRequest — 观察活动标签页的 HTTP 请求(
onBeforeRequest、onBeforeSendHeaders、onCompleted、onErrorOccurred),展示 method、URL、headers、status、timing。只读;仅在面板打开时生效;不修改、阻断、重定向或回放任何请求。 - sidePanel — 以 Chrome 侧边栏形式打开 UI(
sidePanel.open、setPanelBehavior)。 - permissions — 用
chrome.permissions.request/contains仅在用户主动开启时请求 host 权限;安装时不请求任何 host 权限。 - storage — 用
chrome.storage.session在一次会话内跨 service-worker 重启保留当前标签页数据;浏览器关闭时清空;不向外部传输。
- tabs — 读取活动标签页的 URL/title(
Edge 的 Product ID 是 GUID,不是 Store ID 或 CRX ID。
全新扩展必须先在各商店后台手动上传一次,之后 API 才能更新它。
9. 排错(Troubleshooting)
| 现象 | 处理 |
|---|---|
| Chrome 403: API has not been used… | 在与 OAuth client 同一个 GCP 项目里启用 Chrome Web Store API。 |
| 一次性 OAuth 步骤出现 access_denied | 在 OAuth consent screen 把自己加为 Test user。 |
| Chrome 发布 does not meet requirements | 在后台 Permissions 标签里为每个权限填一次说明(见 8)。 |
| Edge 401 Unauthorized | 在 Partner Center → Publish API 重新生成 API key;确认 Client ID 正确。 |
| No zip matched ".output/*-chrome.zip" | 先跑 wxt build && wxt zip,或传 --zip,或在 publish.config.json 设 zip。 |
| 上传被拒为重复版本 | 在 package.json/manifest 里 bump version——商店会拒绝重复上传已发布的同版本。 |
| Missing chrome credentials / Missing edge credentials | 跑 webext-publish init 填共享文件,或导出环境变量。 |
| Chrome refresh_token 过期/被撤销(invalid_grant 等) | 跑 webext-publish chrome-refresh-token 重新走一遍 OAuth 授权,自动写回共享凭据文件。 |
10. 作为 AI skill 使用
本仓库在 ./skills/webext-publish/ 自带一个通用 AI skill,把上面的发布流程(探测现状 → 补齐配置/凭据 → 构建并发布)交给 AI agent 一步步完成,避免漏掉两层配置的分工和商店侧的一次性坑。
它诊断驱动:先看清当前工程缺哪一层、缺哪个商店,再只补缺失项,不推倒已正确的部分。用户没指定目标时,默认发两家(webext-publish all);只有明确说只发某一家、或某一家身份/凭据暂不就位时,才退化为单店。
skill 目录是平台中立的:
SKILL.md—— skill 定义(frontmatter 的name/description+ 工作流正文),任何支持 skill 加载的 AI agent 都可消费。agents/openai.yaml—— 给非 Claude 系平台(如 OpenAI agents)的接口元数据(display name / short description / default prompt)。references/—— 凭据获取和发布清单的补充材料,skill 正文按需引用。
在你的 AI agent 工具里加载这个 skill 后,直接发起发布即可(例如 Claude Code 里输入 /webext-publish,或其它平台用 agents/openai.yaml 里的 default_prompt)。也可以把 ./skills/webext-publish/ 复制到任意一个 WXT 扩展工程的 skills 目录复用。细节见 skills/webext-publish/SKILL.md,凭据获取见 skills/webext-publish/references/credential-setup.md。
skill 只是封装本 CLI 的使用流程,最终仍然调用
webext-publish——凭据层(6 个 key)依然只在仓库外,不进任何会进仓库的文件。
11. License
MIT
