Files
GuJumpgate/docs/多注册流程来源与驱动注册设计.md
T

7.5 KiB
Raw Blame History

多注册流程来源与驱动注册设计

本文解决的是另一个会在第二个 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.jsdetectScriptSource()
  • background/navigation-utils.jsmatchesSourceUrlFamily()
  • 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,而不是模糊业务词。

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 解决的是“页面上能做什么”,不是“标签页如何复用”。

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. 新增正式 sourceopenai-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”。

建议改成:

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 明确自己的 hostPatternsinjectFiles
  • 新增 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