添加设计方案

This commit is contained in:
QLHazyCoder
2026-05-13 00:52:10 +08:00
parent ff38933ce4
commit 04f89620be
8 changed files with 1116 additions and 10 deletions
@@ -0,0 +1,246 @@
# 多注册流程来源与驱动注册设计
本文解决的是另一个会在第二个 flow 接入时立刻爆炸的问题:当前项目虽然有 `tab-runtime`,但“来源 source 是谁、该注入什么脚本、URL family 怎么判定、localhost callback 应该清谁”仍然带着明显的 OpenAI 单流程假设。
## 1. 当前源码里的真实耦合
### 1.1 `signup-page` 其实不是抽象 source,而是 OpenAI Auth 标签页别名
目前这些地方都把 OpenAI Auth / Consent / Add-phone 页面统称为 `signup-page`
- `content/utils.js``detectScriptSource()`
- `background/navigation-utils.js``matchesSourceUrlFamily()`
- `background/tab-runtime.js` 的注册表、冲突清理、callback 清理
这说明当前的 source 体系不是“可扩展的来源注册表”,而是“OpenAI 时代遗留的 source 命名”。
### 1.2 `content/utils.js` 的默认回退不安全
当前 `detectScriptSource()` 在无法识别页面时会回退成 `vps-panel`。这对单流程时期问题不大,但多 flow 下会出现两个风险:
1. 新 flow 页面被误识别成 `vps-panel`
2. `PING / READY / COMPLETE` 日志和标签注册打到错误 source
### 1.3 `tab-runtime` 的 localhost cleanup 直接写死 `registry['signup-page']`
`closeLocalhostCallbackTabs()` 现在默认把匹配 callback 的残留 tab 从 `signup-page` 名下清掉。将来只要第二个 flow 也有 callback,或者 callback 不是来自 OpenAI Auth 页,这里就会清错或漏清。
### 1.4 manifest 的静态注入列表目前基本围绕 OpenAI
`manifest.json` 里的静态内容脚本匹配域名,目前只有 OpenAI Auth 页是明确的 flow 页面入口。第二个 flow 如果沿用这套做法,后续只会不断在 manifest 里继续加分散规则,缺少统一 source 定义中心。
## 2. 设计目标
后续必须拆成两层注册表:
1. `sourceRegistry`:管理“页面来源与标签页生命周期”
2. `driverRegistry`:管理“这个来源页面由哪个 content driver 负责,支持哪些命令”
这两层不要再混成一个 `signup-page` 字符串。
## 3. `sourceRegistry` 设计
建议 source 用稳定 ID,而不是模糊业务词。
```js
sourceRegistry = {
'openai-auth': {
flowId: 'openai',
kind: 'flow-page',
label: 'OpenAI 认证页',
hostPatterns: [
'https://auth.openai.com/*',
'https://auth0.openai.com/*',
'https://accounts.openai.com/*',
],
familyMatcher: 'openai-auth-family',
injectFiles: [
'content/activation-utils.js',
'content/utils.js',
'content/operation-delay.js',
'content/auth-page-recovery.js',
'content/phone-country-utils.js',
'content/phone-auth.js',
'content/signup-page.js',
],
cleanupScopes: ['oauth-localhost-callback'],
},
'mail-gmail': {
flowId: null,
kind: 'mail-provider',
label: 'Gmail',
hostPatterns: ['https://mail.google.com/*'],
familyMatcher: 'gmail-family',
injectFiles: ['content/activation-utils.js', 'content/utils.js', 'content/gmail-mail.js'],
},
'panel-sub2api': {
flowId: 'openai',
kind: 'panel-page',
label: 'SUB2API 后台',
dynamicOnly: true,
familyMatcher: 'sub2api-panel-family',
injectFiles: ['content/utils.js', 'content/sub2api-panel.js'],
},
};
```
### 3.1 source 里至少要有这些字段
- `id`
- `flowId`
- `kind`
- `label`
- `hostPatterns`
- `familyMatcher`
- `injectFiles`
- `readyPolicy`
- `cleanupScopes`
- `tabReusePolicy`
### 3.2 source 不等于 flow
一个 flow 会有多个 source
- `openai-entry`
- `openai-auth`
- `openai-plus-checkout`
- `openai-paypal`
- `openai-gopay`
- `panel-sub2api`
同样,一个 source 也可能不属于具体 flow,例如:
- `mail-gmail`
- `mail-163`
- `mail-2925`
- `mail-inbucket`
## 4. `driverRegistry` 设计
`driverRegistry` 解决的是“页面上能做什么”,不是“标签页如何复用”。
```js
driverRegistry = {
'openai-auth': {
sourceId: 'openai-auth',
driverId: 'content/signup-page',
commands: [
'OPEN_SIGNUP',
'SUBMIT_SIGNUP_IDENTIFIER',
'SUBMIT_PASSWORD',
'SUBMIT_PROFILE',
'SUBMIT_LOGIN_CODE',
'SUBMIT_PHONE_CODE',
'DETECT_AUTH_STATE',
],
},
'mail-gmail': {
sourceId: 'mail-gmail',
driverId: 'content/gmail-mail',
commands: ['POLL_MAILBOX', 'OPEN_MESSAGE', 'DELETE_MESSAGE'],
},
};
```
这样做的好处是:
- `tab-runtime` 只关心 source
- workflow / mail service 只关心 driver capability
- 后续换内容脚本实现时,不需要改 tab 生命周期代码
## 5. `signup-page` 的迁移策略
`signup-page` 不能直接继续作为未来通用 source 名字。
建议迁移方式:
1. 新增正式 source`openai-auth`
2.`sourceRegistry.aliases` 里临时保留:
- `signup-page -> openai-auth`
3. `getSourceLabel()``matchesSourceUrlFamily()``ensureContentScriptReadyOnTab()` 全部优先读注册表
4. 等 OpenAI 全链路迁完后,再删除 `signup-page` 别名
## 6. localhost callback cleanup 怎么改
当前 callback 清理逻辑最大的问题是“只知道 callback URL,不知道 callback 属于哪个 flow source”。
建议改成:
```js
callbackRegistry = {
'oauth-localhost-callback': {
ownerSourceId: 'openai-auth',
matcher: isLocalhostOAuthCallbackUrl,
clearOwnerTabOnClose: true,
},
};
```
`closeLocalhostCallbackTabs()` 的输入要升级为:
- `cleanupScope`
- `callbackUrl`
- `ownerSourceId`
而不是默认拿 `signup-page`
## 7. `content/utils.js` 的改法
### 7.1 禁止默认回退成 `vps-panel`
新的规则应该是:
-`window.__MULTIPAGE_SOURCE` 时,以注入 source 为准
- 没有显式 source 时,只在静态 host map 里做白名单匹配
- 仍无法识别时返回 `unknown-source`
`unknown-source` 不参与 tab 注册,不自动 `reportReady()`,只记录诊断日志。
### 7.2 child frame ready 规则也要转到注册表
当前 `shouldReportReadyForFrame()` 里写死了多个 source 名称。后续应改成 source metadata
- `readyPolicy: 'top-frame-only'`
- `readyPolicy: 'allow-child-frame'`
## 8. manifest / 动态注入策略
原则上以后由 `sourceRegistry` 作为单一事实来源,manifest 只是实现载体。
建议约定:
- 稳定公共页面可继续走静态 `content_scripts`
- 变动大、域名多、只在运行期打开的页面改走 `chrome.scripting.executeScript`
- 每个 source 明确自己的 `hostPatterns``injectFiles`
- 新增 flow 时,不允许直接在业务代码里散写 `injectFiles = [...]`
## 9. 与网络策略的关系
`sourceRegistry` 只负责页面来源,不负责代理策略;但每个 flow 应同时提供自己的 `networkProfile`,至少包含:
- `guardDomains`
- `probeEndpoints`
- `failCloseDomains`
否则 `ip-proxy-core` 仍会继续写死 `chatgpt.com / openai.com`
## 10. 第一阶段迁移顺序
1. 引入 `sourceRegistry / driverRegistry` 与旧 source alias。
2.`getSourceLabel()``matchesSourceUrlFamily()``ensureContentScriptReadyOnTab()` 改成读注册表。
3. 去掉 `detectScriptSource()``vps-panel` 默认回退。
4.`closeLocalhostCallbackTabs()`,不再写死 `signup-page`
5. 第二个 flow 接入时,严格要求先注册 source 和 driver,再写步骤逻辑。
## 11. 本文对应解决的缺口
本文主要补齐以下缺口:
- `signup-page` 实际是 OpenAI source,不是通用注册页
- source URL family / content ready / localhost callback cleanup 没有统一注册表
- manifest 与动态注入没有统一入口
- `content/utils.js` 的默认 source 回退会污染未来 flow