docs: .env.example 未记录 Watcha 登录所需的全部变量(线上已启用)

Author: dajiaohuangCreated Sep 10, 2026Updated Sep 10, 2026

问题 / The problem

.env.example 里没有任何 Watcha(观猹)相关的变量,而 Watcha 是仓库里已经完整实现、线上也已启用的第二种登录方式。

在提交 073d105d4dbb3f3afcd2e7cd194cee3a557b0999main)上核对:

$ grep -c WATCHA .env.example
0
$ grep -rn -i "watcha|观猹" README.md README.zh-CN.md README.ja.md docs/ .env.example
(无输出)

但它并不是占位功能:

  1. 服务端流程是完整的 —— api/auth/watcha/start.jsapi/auth/watcha/callback.js 实现了带 PKCE 的授权码流程,api/_lib/watcha.js 负责配置、cookie 和 token 交换。
  2. 界面入口是完整的 —— src/main.jsx 里有 watchaLogoUrl、"Continue with Watcha / 使用观猹登录" 按钮,以及 watchaNotConfiguredwatchaSessionExpiredwatchaDeniedwatchaLoginFailed 四类错误文案。
  3. 线上确实开着 —— 对生产站点请求登录入口会拿到真实的跳转,说明这些变量在部署环境里已经配置好了:
$ curl -s -o /dev/null -D - https://gpt-image2.canghe.ai/api/auth/watcha/start
HTTP/1.1 302 Found
Location: https://watcha.cn/oauth/authorize?response_type=code&client_id=...&
          redirect_uri=https%3A%2F%2Fgpt-image2.canghe.ai%2Fapi%2Fauth%2Fwatcha%2Fcallback&
          scope=read&state=...&code_challenge=...&code_challenge_method=S256
Set-Cookie: watcha_oauth_state=...; watcha_oauth_verifier=...; watcha_oauth_return_to=...

缺的只是配置说明。变量本身在 api/_lib/watcha.jsgetWatchaConfig() 里读得很明确:

javascript
clientId:     process.env.WATCHA_CLIENT_ID || '',
clientSecret: process.env.WATCHA_CLIENT_SECRET || '',
isPublicClient: process.env.WATCHA_PUBLIC_CLIENT === 'true',
redirectUri:  process.env.WATCHA_REDIRECT_URI || `${appUrl}/api/auth/watcha/callback`,
scope:        process.env.WATCHA_SCOPE || 'read email',
authorizeUrl: process.env.WATCHA_AUTHORIZE_URL || 'https://watcha.cn/oauth/authorize',
tokenUrl:     process.env.WATCHA_TOKEN_URL     || 'https://watcha.cn/oauth/api/token',
userinfoUrl:  process.env.WATCHA_USERINFO_URL  || 'https://watcha.cn/oauth/api/userinfo'

其中 WATCHA_CLIENT_ID 加上 WATCHA_CLIENT_SECRET(或 WATCHA_PUBLIC_CLIENT=true)决定 isWatchaConfigured() 是否成立,也就决定登录按钮能不能用。

影响.env.example 是这个项目唯一的自部署配置清单,APIMart、Supabase、Stripe、支付宝、GA4 都逐项列了。唯独 Watcha 一项没有。照着它部署的人既不知道需要这些变量,也无从得知变量名,点登录只能看到"观猹登录还没有完成配置",而且这个失败没有任何线索指向缺失的配置。

同一类遗漏还有一处:api/_lib/supabase.js:6 的服务端回退 process.env.VITE_SUPABASE_URL || process.env.SUPABASE_URL,其中 SUPABASE_URL 也没有被记录。

建议的修复 / Suggested fix

.env.example 补一段 Watcha 配置,并补上 SUPABASE_URL;再加一个守卫,断言 api/ 下读取的每个 process.env.* 都能在 .env.example 里找到,避免以后再漂移。

我已经按这个思路提了 PR #43:https://github.com/freestylefly/awesome-gpt-image-2/pull/43。守卫已验证过 —— 对着改动前的 .env.example 会列出全部 9 个缺失变量,改动后 npm test 41/41、npm run test:apimart 24/24、npm run build 均通过。

范围说明 / Scope notes

  • 只涉及文档和测试,不改运行时代码、依赖、CI 或权限。
  • 没有在本 issue 里写出任何密钥类信息:上面输出中的 client_id 属于公开的 OAuth 客户端标识(它本身就会出现在跳转 URL 里),我也只截取了片段。
  • 两个安装脚本里的 CLAUDE_HOME(#30)和 docs/gallery.md 索引缺案例(#29)是另外两个已有人处理的已知问题,不在本 issue 范围内。
  • scripts/alipay-webpay-sandbox-server.mjsALIPAY_SANDBOX_PORT 同样未被记录,但只在本地沙箱脚本里使用且有默认值 4174,优先级更低;我在 PR 的守卫里只扫描 api/,所以没有一并处理,留给你决定。

English summary: .env.example documents every provider (APIMart, Supabase, Stripe, Alipay, GA4) except Watcha, which is a fully implemented and production-enabled second sign-in option — a PKCE authorization-code flow in api/auth/watcha/, a "Continue with Watcha" button in the UI, and a live 302 to watcha.cn/oauth/authorize from the deployed site. None of its eight environment variables (WATCHA_CLIENT_ID, WATCHA_CLIENT_SECRET, WATCHA_PUBLIC_CLIENT, WATCHA_REDIRECT_URI, WATCHA_SCOPE, and the three endpoint overrides) appear in the file, nor anywhere in the READMEs or docs/, so a self-hosted deployment following the documented contract has no way to discover or enable the feature and the UI can only report that Watcha is not configured. The undocumented server-side fallback SUPABASE_URL in api/_lib/supabase.js is the same class of gap. PR #43 fixes both and adds a guard asserting that every process.env name read under api/ is documented; the guard is verified to fail on the previous file listing all nine missing names. Documentation and tests only.

Source: freestylefly/awesome-gpt-image-2