npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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.

Readme

webext-publish

通过各商店官方 API,把 WXT 构建的浏览器扩展上传并发布到 Chrome Web Store 和 Microsoft Edge Add-ons——一个工具、一份提交到仓库的配置、一套跨所有扩展共用的凭据。

pnpm build && pnpm zip && pnpm publish:all

webext-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)

  1. 生成共享凭据文件(每个开发者账号一次性):

    pnpm exec webext-publish init        # 创建 ~/.config/webext-publish/.env(chmod 600)

    编辑它,填入六个凭据——见下文第 4 节「凭据」。

  2. 添加每扩展配置——把 publish.config.json 提交到 package.json 旁边:

    {
      "chrome": { "extensionId": "glmidaajlaanaccljcpgdgjacbcnighb" },
      "edge": { "productId": "278a715c-cdb9-4a3d-8477-1c02c3f16291" }
    }
  3. 构建并发布:

    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.env

4.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)

凭据按从高到低解析:

  1. 真实环境变量(如 CI 密钥)——始终胜出。
  2. 当前目录的本地 .env——单扩展覆盖。
  3. 共享文件(~/.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 重启保留当前标签页数据;浏览器关闭时清空;不向外部传输。
  • 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