7.6 KiB
多注册流程来源与驱动注册设计
本文解决的是另一个会在第二个 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 下会出现两个风险:
- 新 flow 页面被误识别成
vps-panel 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. 设计目标
后续必须拆成两层注册表:
sourceRegistry:管理“页面来源与标签页生命周期”driverRegistry:管理“这个来源页面由哪个 content driver 负责,支持哪些命令”
这两层不要再混成一个 signup-page 字符串。
3. sourceRegistry 设计
建议 source 用稳定 ID,而不是模糊业务词。
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 里至少要有这些字段
idflowIdkindlabelhostPatternsfamilyMatcherinjectFilesreadyPolicycleanupScopestabReusePolicy
3.2 source 不等于 flow
一个 flow 会有多个 source:
openai-entryopenai-authopenai-plus-checkoutopenai-paypalopenai-gopaypanel-sub2api
同样,一个 source 也可能不属于具体 flow,例如:
mail-gmailmail-163mail-2925mail-inbucket
4. driverRegistry 设计
driverRegistry 解决的是“页面上能做什么”,不是“标签页如何复用”。
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 名字。
建议迁移方式:
- 新增正式 source:
openai-auth - 在
sourceRegistry.aliases里临时保留:signup-page -> openai-auth
getSourceLabel()、matchesSourceUrlFamily()、ensureContentScriptReadyOnTab()全部优先读注册表- 等 OpenAI 全链路迁完后,再删除
signup-page别名
6. localhost callback cleanup 怎么改
当前 callback 清理逻辑最大的问题是“只知道 callback URL,不知道 callback 属于哪个 flow source”。
建议改成:
callbackRegistry = {
'oauth-localhost-callback': {
ownerSourceId: 'openai-auth',
matcher: isLocalhostOAuthCallbackUrl,
clearOwnerTabOnClose: true,
},
};
closeLocalhostCallbackTabs() 的输入要升级为:
cleanupScopecallbackUrlownerSourceId
而不是默认拿 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,至少包含:
guardDomainsprobeEndpointsfailCloseDomains
否则 ip-proxy-core 仍会继续写死 chatgpt.com / openai.com。
10. 第一阶段迁移顺序
- 引入
sourceRegistry / driverRegistry与旧 source alias。 - 把
getSourceLabel()、matchesSourceUrlFamily()、ensureContentScriptReadyOnTab()改成读注册表。 - 去掉
detectScriptSource()的vps-panel默认回退。 - 改
closeLocalhostCallbackTabs(),不再写死signup-page。 - 第二个 flow 接入时,严格要求先注册 source 和 driver,再写步骤逻辑。
11. 本文对应解决的缺口
本文主要补齐以下缺口:
signup-page实际是 OpenAI source,不是通用注册页- source URL family / content ready / localhost callback cleanup 没有统一注册表
- manifest 与动态注入没有统一入口
content/utils.js的默认 source 回退会污染未来 flow