248 lines
7.6 KiB
Markdown
248 lines
7.6 KiB
Markdown
# 多注册流程来源与驱动注册设计
|
||
|
||
本文解决的是另一个会在第二个 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()`
|
||
- `core/flow-kernel/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',
|
||
'flows/openai/content/auth-page-recovery.js',
|
||
'flows/openai/content/phone-country-utils.js',
|
||
'flows/openai/content/phone-auth.js',
|
||
'flows/openai/content/openai-auth.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', 'flows/openai/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: 'flows/openai/content/openai-auth',
|
||
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
|
||
|
||
|