添加设计方案
This commit is contained in:
@@ -338,6 +338,8 @@ OAuth 登录流程打开新标签页,避免复用旧页面导致状态污染
|
||||
|
||||
## 8. 接码平台多平台适配:HeroSMS + 5sim
|
||||
|
||||
边界说明:接码平台多平台适配当前只属于 OpenAI 注册 / OAuth 链路,不作为多注册 flow 架构的 core 通用服务。后续新增的注册项目默认不接入接码;只有出现第二个真实项目也需要短信生命周期时,再按实际复用点抽象 provider 层。
|
||||
|
||||
### 目标
|
||||
|
||||
手机号验证 Step 9 支持按平台切换接码能力:
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
# 多注册流程侧边栏能力矩阵
|
||||
|
||||
本文解决的是一个很容易被低估的问题:sidepanel 现在不只是“渲染 UI”,它还承担了大量业务约束。如果未来要支持多个 flow,不能只做动态渲染,还必须把“哪些能力允许显示、允许切换、允许启动”做成统一能力矩阵。
|
||||
|
||||
## 1. 当前源码里的真实问题
|
||||
|
||||
当前手机号注册能力至少同时受这几组条件约束:
|
||||
|
||||
- `phoneVerificationEnabled`
|
||||
- `plusModeEnabled`
|
||||
- `contributionMode`
|
||||
- `panelMode === 'cpa'` 时还会触发额外提醒
|
||||
|
||||
而这些约束现在分散在多个地方:
|
||||
|
||||
- `background.js`:`canUsePhoneSignup`
|
||||
- `background/message-router.js`:同类判断
|
||||
- `sidepanel/sidepanel.js`:`canSelectPhoneSignupMethod`
|
||||
- `sidepanel/sidepanel.js`:`shouldWarnCpaPhoneSignup`
|
||||
|
||||
这说明 sidepanel 当前既在做展示,也在做策略判定,而且判定逻辑有重复。
|
||||
|
||||
## 2. 设计目标
|
||||
|
||||
后续 sidepanel 至少要拆成三层能力判断:
|
||||
|
||||
1. `flowCapabilities`
|
||||
2. `panelCapabilities`
|
||||
3. `runtimeLocks`
|
||||
|
||||
最终所有显示 / 禁用 / 启动校验都只读这三层组合结果。
|
||||
|
||||
## 3. 三层能力定义
|
||||
|
||||
### 3.1 `flowCapabilities`
|
||||
|
||||
表示“当前 flow 业务上支持什么”。
|
||||
|
||||
示例:
|
||||
|
||||
```js
|
||||
flowCapabilities.openai = {
|
||||
supportsEmailSignup: true,
|
||||
supportsPhoneSignup: true,
|
||||
supportsPhoneVerificationSettings: true,
|
||||
supportsPlusMode: true,
|
||||
supportsContributionMode: true,
|
||||
supportsPlatformBinding: ['cpa', 'sub2api', 'codex2api'],
|
||||
supportsLuckmail: true,
|
||||
supportsOauthTimeoutBudget: true,
|
||||
stepDefinitionMode: 'openai-dynamic',
|
||||
};
|
||||
|
||||
flowCapabilities.siteA = {
|
||||
supportsEmailSignup: true,
|
||||
supportsPhoneSignup: false,
|
||||
supportsPhoneVerificationSettings: false,
|
||||
supportsPlusMode: false,
|
||||
supportsContributionMode: false,
|
||||
supportsPlatformBinding: ['siteA-panel'],
|
||||
supportsLuckmail: false,
|
||||
supportsOauthTimeoutBudget: false,
|
||||
stepDefinitionMode: 'siteA',
|
||||
};
|
||||
```
|
||||
|
||||
原则:
|
||||
|
||||
- 没有真实需求,不要默认给新 flow 打开手机号、Plus、LuckMail
|
||||
- 新 flow 默认从最小能力集合开始
|
||||
|
||||
### 3.2 `panelCapabilities`
|
||||
|
||||
表示“当前面板来源允许什么交互”。
|
||||
|
||||
示例:
|
||||
|
||||
```js
|
||||
panelCapabilities = {
|
||||
cpa: {
|
||||
supportsPhoneSignup: true,
|
||||
requiresPhoneSignupWarning: true,
|
||||
},
|
||||
sub2api: {
|
||||
supportsPhoneSignup: true,
|
||||
requiresPhoneSignupWarning: false,
|
||||
},
|
||||
codex2api: {
|
||||
supportsPhoneSignup: true,
|
||||
requiresPhoneSignupWarning: false,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
注意:`contributionMode` 不是新的 `panelMode`,它是独立运行态锁。
|
||||
|
||||
### 3.3 `runtimeLocks`
|
||||
|
||||
表示“当前这一次运行或当前 UI 状态是否允许操作”。
|
||||
|
||||
示例:
|
||||
|
||||
```js
|
||||
runtimeLocks = {
|
||||
autoRunLocked: false,
|
||||
contributionMode: false,
|
||||
plusModeEnabled: false,
|
||||
phoneVerificationEnabled: true,
|
||||
settingsMenuLocked: false,
|
||||
};
|
||||
```
|
||||
|
||||
它决定的是:
|
||||
|
||||
- 现在能不能切换注册方式
|
||||
- 能不能改 flow
|
||||
- 能不能导入导出配置
|
||||
- 能不能打开某些配置区
|
||||
|
||||
## 4. 统一选择器
|
||||
|
||||
建议提供一个中心 selector:
|
||||
|
||||
```js
|
||||
resolveSidepanelCapabilities({
|
||||
activeFlowId,
|
||||
panelMode,
|
||||
state,
|
||||
});
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```js
|
||||
{
|
||||
effectiveSignupMethods: ['email', 'phone'],
|
||||
canShowPhoneSettings: true,
|
||||
canSelectPhoneSignup: true,
|
||||
shouldWarnCpaPhoneSignup: true,
|
||||
canShowPlusSettings: true,
|
||||
canShowLuckmail: true,
|
||||
canExportSettings: true,
|
||||
canSwitchFlow: false,
|
||||
stepDefinitionOptions: {},
|
||||
}
|
||||
```
|
||||
|
||||
以后 sidepanel 与 background 都只消费这份结果,不再各写一套判断。
|
||||
|
||||
## 5. OpenAI 当前矩阵
|
||||
|
||||
### 5.1 仅看 flow 能力
|
||||
|
||||
OpenAI 当前业务上支持:
|
||||
|
||||
- 邮箱注册
|
||||
- 手机号注册
|
||||
- OAuth 登录
|
||||
- 平台回调绑定
|
||||
- Plus
|
||||
- LuckMail
|
||||
- 接码配置
|
||||
|
||||
### 5.2 加上 runtime lock 后的真实结果
|
||||
|
||||
OpenAI 的手机号注册只有在以下条件同时成立时才可选:
|
||||
|
||||
- `flowCapabilities.openai.supportsPhoneSignup === true`
|
||||
- `phoneVerificationEnabled === true`
|
||||
- `plusModeEnabled === false`
|
||||
- `contributionMode === false`
|
||||
|
||||
也就是说,手机号注册不是一个“单纯 UI 开关”,而是能力矩阵结果。
|
||||
|
||||
### 5.3 加上 panel 约束后的额外行为
|
||||
|
||||
当满足手机号注册可用,且当前 `panelMode === 'cpa'` 时:
|
||||
|
||||
- 不阻止
|
||||
- 但要提示风险
|
||||
|
||||
这类“允许但要提醒”的逻辑也必须归到能力矩阵里,而不是散落在点击事件中。
|
||||
|
||||
## 6. 步骤列表也属于能力矩阵的一部分
|
||||
|
||||
当前步骤定义主要受:
|
||||
|
||||
- `plusModeEnabled`
|
||||
- `signupMethod`
|
||||
|
||||
影响,并通过 `data/step-definitions.js` 动态切换。
|
||||
|
||||
多 flow 后必须升级成:
|
||||
|
||||
```js
|
||||
getStepDefinitions({
|
||||
activeFlowId,
|
||||
signupVariant,
|
||||
panelMode,
|
||||
plusModeEnabled,
|
||||
contributionMode,
|
||||
});
|
||||
```
|
||||
|
||||
也就是说,步骤列表不再是全局 `10 步 / 13 步` 二选一,而是 flow-aware 的定义。
|
||||
|
||||
## 7. Sidepanel 分层职责
|
||||
|
||||
### 7.1 展示层
|
||||
|
||||
只负责:
|
||||
|
||||
- show / hide
|
||||
- enabled / disabled
|
||||
- 文案与提示
|
||||
|
||||
### 7.2 能力判定层
|
||||
|
||||
只负责:
|
||||
|
||||
- `resolveSidepanelCapabilities()`
|
||||
- `validateAutoRunStart()`
|
||||
- `validateModeSwitch()`
|
||||
|
||||
### 7.3 后台复核层
|
||||
|
||||
后台在收到启动、切换注册方式、切换 flow 等消息时,仍要复核一遍同一套能力判断,避免 sidepanel 以外的入口绕过约束。
|
||||
|
||||
## 8. 新 flow 的默认能力策略
|
||||
|
||||
后续新增 flow 时,默认按以下最小集合开始:
|
||||
|
||||
- 仅邮箱注册
|
||||
- 无手机号注册
|
||||
- 无 Plus
|
||||
- 无 LuckMail
|
||||
- 无贡献模式
|
||||
- 无 OpenAI 平台回调面板
|
||||
|
||||
只有真实需求出现时,再逐项打开 capability。
|
||||
|
||||
## 9. 迁移顺序
|
||||
|
||||
1. 提炼 `flowCapabilitiesRegistry`
|
||||
2. 提炼 `panelCapabilitiesRegistry`
|
||||
3. 新增 `resolveSidepanelCapabilities()` 与 `validateAutoRunStart()`
|
||||
4. 让 `sidepanel.js`、`background.js`、`message-router.js` 共用同一套 selector
|
||||
5. 再把步骤定义切换也改成 flow-aware
|
||||
|
||||
## 10. 本文对应解决的缺口
|
||||
|
||||
本文主要补齐以下缺口:
|
||||
|
||||
- sidepanel 不只是渲染层,还承接业务约束
|
||||
- 手机号注册能力由多个开关共同决定,当前逻辑分散且重复
|
||||
- `contributionMode` 与 `panelMode` 容易混淆
|
||||
- 多 flow 之后,步骤列表也必须纳入能力矩阵,而不是继续全局写死
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
# 多注册流程架构边界
|
||||
|
||||
本文记录后续从“OpenAI 注册扩展”升级到“多注册流程扩展”时的模块边界。当前结论是:需要引入多 flow 架构,但不要把所有能力都提前抽成通用服务。
|
||||
|
||||
## 1. 总体判断
|
||||
|
||||
后续新增注册项目时,不应继续在现有 OpenAI 步骤里堆 `if site === ...`。不同网站的注册入口、验证码、资料页、风控页、回调页和成功判定都可能完全不同,应按独立 flow 处理。
|
||||
|
||||
目标形态:
|
||||
|
||||
```txt
|
||||
core/
|
||||
flow-registry
|
||||
workflow-engine
|
||||
runtime-state
|
||||
tab-runtime
|
||||
logging
|
||||
account-artifacts
|
||||
email
|
||||
mail-code-polling
|
||||
network-proxy
|
||||
|
||||
flows/
|
||||
openai/
|
||||
workflow.js
|
||||
content-driver.js
|
||||
mail-rules.js
|
||||
network-profile.js
|
||||
phone-verification-flow.js
|
||||
phone-sms-providers/
|
||||
|
||||
site-a/
|
||||
workflow.js
|
||||
content-driver.js
|
||||
mail-rules.js
|
||||
network-profile.js
|
||||
```
|
||||
|
||||
第一阶段不需要立刻调整成上述目录,只需要按这个边界重构,避免新增项目继续污染 OpenAI 专用逻辑。
|
||||
|
||||
## 2. 必须通用化的部分
|
||||
|
||||
- `activeFlowId / runId / nodeId` 状态模型:替代只适合单流程的 `currentStep / stepStatuses`,同时避免与现有外部接口里的远端 `flow_id` 语义冲突。
|
||||
- Workflow engine:负责节点执行、跳转、停止、恢复、重试和超时,不理解具体网站页面。
|
||||
- Flow registry:负责注册 OpenAI、后续网站 A、网站 B 等独立流程。
|
||||
- Tab runtime:标签页注册、自动化窗口锁定、脚本注入、消息超时、页面 ready 检查。
|
||||
- Logging / status:结构化日志、节点状态、运行进度、停止和失败展示。
|
||||
- Account artifact store:记录账号产物、身份、凭据、回调结果和失败信息。
|
||||
- Email identity:邮箱生成、邮箱池、别名、转发收件目标等身份能力。
|
||||
- Mail polling:邮件验证码、magic link、激活链接的轮询框架;具体过滤和提取规则由 flow 提供。
|
||||
- IP proxy / network policy:代理应用、切换、出口检测、防泄漏;目标域名和探测 URL 由 flow 提供。
|
||||
- Sidepanel dynamic renderer:按 flow capability 显示配置区、步骤列表和运行状态。
|
||||
- Settings schema:通用配置与 flow 私有配置分层导入导出。
|
||||
- Error taxonomy / recovery policy:通用层只处理执行框架错误,业务错误由 flow 自己分类。
|
||||
|
||||
## 3. 暂不通用化的部分
|
||||
|
||||
以下能力当前只属于 OpenAI flow,不进入 core:
|
||||
|
||||
- 手机接码:HeroSMS / 5sim / NexSMS、取号、复用、轮询、换号、释放、手机号注册和后置 add-phone。
|
||||
- LuckMail:当前 `project_code = openai` 的购邮、复用、已用/保留/禁用管理。
|
||||
- OpenAI / ChatGPT 页面 DOM 操作。
|
||||
- OpenAI OAuth 授权、localhost callback、CPA / SUB2API / Codex2API 绑定。
|
||||
- ChatGPT Plus、PayPal、GoPay、GPC 相关支付流程。
|
||||
- OpenAI 的验证码邮件过滤规则、登录状态判断、add-phone fatal 判断。
|
||||
- OpenAI 专属账号产物字段,如 Plus checkout、OAuth state、平台验证字段。
|
||||
|
||||
原因:当前除了 OpenAI,新项目暂不需要手机接码。过早把接码抽成通用服务会让新 flow 被迫理解手机号订单、短信平台、号码复用和页面 resend 细节,增加维护成本。
|
||||
|
||||
## 4. 手机接码边界
|
||||
|
||||
手机接码先保持为 OpenAI 专属能力。
|
||||
|
||||
当前这些模块在逻辑上归属 `flows/openai`,即使物理路径暂时还在旧目录:
|
||||
|
||||
- `background/phone-verification-flow.js`
|
||||
- `phone-sms/providers/hero-sms.js`
|
||||
- `phone-sms/providers/five-sim.js`
|
||||
- `phone-sms/providers/registry.js`
|
||||
- `content/phone-auth.js`
|
||||
- `content/phone-country-utils.js`
|
||||
- sidepanel 中的接码配置区
|
||||
- 相关测试:`tests/phone-verification-flow.test.js`、`tests/five-sim-provider.test.js`、`tests/sidepanel-phone-verification-settings.test.js`
|
||||
|
||||
后续新增 flow 默认 `sms: false`,不显示接码配置,不加载接码步骤,也不要求 workflow engine 理解短信订单。
|
||||
|
||||
如果未来第二个真实 flow 也需要接码,再按事实抽象,优先抽 provider API,而不是直接抽完整手机号验证编排:
|
||||
|
||||
```js
|
||||
flow.phoneVerification = {
|
||||
acquirePolicy,
|
||||
submitPhoneNumber,
|
||||
submitCode,
|
||||
classifyPhoneError,
|
||||
recoverAfterTimeout,
|
||||
}
|
||||
```
|
||||
|
||||
只有两个以上 flow 共享相同短信供应商生命周期时,才考虑把 `phone-sms/providers/*` 下沉到 `core/services/sms`。
|
||||
|
||||
## 5. 迁移顺序
|
||||
|
||||
1. 引入 `activeFlowId / runId / currentNodeId / nodeStatuses / flowContext`,先兼容 OpenAI 旧步骤。
|
||||
2. 把邮箱、邮件轮询、代理、tab runtime、日志和账号记录逐步参数化,去掉 OpenAI 常量。
|
||||
3. 建立 `flows/openai` 边界,把 OpenAI 步骤、content driver、OAuth、Plus 和接码逻辑收拢进去。
|
||||
4. 用第二个真实注册项目验证 flow registry 和 workflow engine,而不是靠假想接口设计过度抽象。
|
||||
5. 稳定后清理旧 `step` 数字兼容层。
|
||||
|
||||
## 6. 新 flow 接入原则
|
||||
|
||||
新增注册项目时,只允许新增该 flow 的 workflow、content driver、mail rules、network profile 和必要的私有配置。不要直接修改 OpenAI 步骤,也不要把 OpenAI 的手机号验证、OAuth、Plus 支付逻辑提升为通用能力。
|
||||
|
||||
通用层只负责“怎么运行一个 flow”,具体 flow 负责“这个网站怎么注册”。
|
||||
|
||||
## 7. 配套设计文档
|
||||
|
||||
本边界文档只回答“什么该进 core、什么暂时不要抽”。要真正开工,还需要同时遵守下面四份配套设计:
|
||||
|
||||
- `docs/多注册流程状态迁移设计.md`:解决 `DEFAULT_STATE` 扁平模型、旧 step 兼容、自动运行/日志/账号记录如何迁移。
|
||||
- `docs/多注册流程来源与驱动注册设计.md`:解决 `signup-page`、source family、内容脚本注入和 localhost callback cleanup 的注册表设计。
|
||||
- `docs/多注册流程邮件分层设计.md`:解决 provider driver 与 flow mail rules 的边界,以及 LuckMail 暂不通用化的问题。
|
||||
- `docs/多注册流程侧边栏能力矩阵.md`:解决 sidepanel 展示层与业务约束层混在一起的问题。
|
||||
|
||||
后续新 flow 设计如果与这四份文档冲突,以“先修正文档边界,再动代码”为准,不允许直接在现有 OpenAI 逻辑上叠条件分支。
|
||||
@@ -0,0 +1,248 @@
|
||||
# 多注册流程状态迁移设计
|
||||
|
||||
本文是 `docs/多注册流程架构边界.md` 的落地补充,专门解决“现有扁平状态怎么迁到多 flow 架构”这个最容易把旧逻辑拖垮的问题。
|
||||
|
||||
## 1. 先说结论
|
||||
|
||||
当前项目不能直接在 `DEFAULT_STATE` 上继续堆字段。要支持多个完全不同的注册流程,必须先把“运行态”“持久配置”“共享服务状态”“flow 私有状态”分层,再保留一层 OpenAI 旧步骤兼容视图。
|
||||
|
||||
这次迁移的目标不是一步把全部字段搬完,而是先建立新的状态主模型,让旧代码通过 adapter 继续运行。
|
||||
|
||||
## 2. 当前源码里的真实问题
|
||||
|
||||
### 2.1 `DEFAULT_STATE` 仍然是单流程扁平模型
|
||||
|
||||
`background.js` 里的 `DEFAULT_STATE` 目前把这些不同层次的状态混在一起:
|
||||
|
||||
- 流程进度:`currentStep`、`stepStatuses`
|
||||
- 通用运行态:`automationWindowId`、`tabRegistry`、`logs`
|
||||
- OpenAI OAuth / 平台回调:`oauthUrl`、`localhostUrl`、`sub2apiSessionId`、`codex2apiSessionId`
|
||||
- OpenAI Plus:`plusCheckoutTabId`、`plusCheckoutUrl`、`plusBillingAddress`
|
||||
- OpenAI 接码:`currentPhoneActivation`、`signupPhoneActivation`、`reusablePhoneActivation`
|
||||
- OpenAI LuckMail:`currentLuckmailPurchase`
|
||||
- 共享邮箱运行态:`registrationEmailState`
|
||||
|
||||
这会带来两个直接后果:
|
||||
|
||||
1. 新 flow 一接进来,就只能继续往全局 state 加字段。
|
||||
2. 任何 reset / retry / stop 都容易误清理别的业务域状态。
|
||||
|
||||
### 2.2 旧步骤数字模型已经渗透到多个模块
|
||||
|
||||
当前不只是 `background.js` 依赖 `currentStep / stepStatuses`,下列模块也在按“Step 1~13”理解流程:
|
||||
|
||||
- `background/auto-run-controller.js`
|
||||
- `background/logging-status.js`
|
||||
- `background/account-run-history.js`
|
||||
|
||||
所以新状态模型不能只改 `background.js`,必须给自动运行、日志、账号记录保留兼容出口。
|
||||
|
||||
### 2.3 `registrationEmailState` 名字看起来通用,内部却仍带 OpenAI 身份假设
|
||||
|
||||
`background/registration-email-state.js` 已经把邮箱运行态单独抽出来了,这是好事;但它的 `preserveAccountIdentity` 现在默认保留的是“手机号身份”,也就是:
|
||||
|
||||
- `accountIdentifierType = phone`
|
||||
- `signupPhoneNumber`
|
||||
- `signupPhoneActivation`
|
||||
- `signupPhoneCompletedActivation`
|
||||
|
||||
这对 OpenAI 的 `add-email` 分支是对的,但对未来可能出现的“用户名主身份”“邀请码主身份”“钱包地址主身份”并不通用。
|
||||
|
||||
## 3. 目标状态分层
|
||||
|
||||
建议先建立“概念上的标准状态模型”,物理存储可以分阶段迁移。
|
||||
|
||||
```js
|
||||
chrome.storage.session.runtimeState = {
|
||||
activeFlowId: 'openai',
|
||||
activeRunId: 'run_20260512_xxx',
|
||||
currentNodeId: 'submit-signup-email',
|
||||
nodeStatuses: {
|
||||
'open-chatgpt': 'completed',
|
||||
'submit-signup-email': 'running',
|
||||
},
|
||||
|
||||
shared: {
|
||||
automationWindowId: 123,
|
||||
tabRegistry: {},
|
||||
sourceLastUrls: {},
|
||||
logs: [],
|
||||
autoRun: {},
|
||||
accountArtifacts: {},
|
||||
},
|
||||
|
||||
services: {
|
||||
mail: {},
|
||||
proxy: {},
|
||||
accountPools: {},
|
||||
},
|
||||
|
||||
flows: {
|
||||
openai: {
|
||||
auth: {},
|
||||
platformBinding: {},
|
||||
plus: {},
|
||||
phoneVerification: {},
|
||||
luckmail: {},
|
||||
identity: {},
|
||||
},
|
||||
},
|
||||
|
||||
legacyStepCompat: {
|
||||
currentStep: 2,
|
||||
stepStatuses: { 1: 'completed', 2: 'running' },
|
||||
},
|
||||
};
|
||||
|
||||
chrome.storage.local.settings = {
|
||||
schemaVersion: 2,
|
||||
|
||||
shared: {
|
||||
autoRunDefaults: {},
|
||||
logging: {},
|
||||
},
|
||||
|
||||
services: {
|
||||
mailProviders: {},
|
||||
ipProxy: {},
|
||||
hotmailPool: {},
|
||||
mail2925Pool: {},
|
||||
icloud: {},
|
||||
customEmailPool: {},
|
||||
},
|
||||
|
||||
flows: {
|
||||
openai: {
|
||||
signupMethod: 'email',
|
||||
phoneVerificationEnabled: false,
|
||||
plusModeEnabled: false,
|
||||
plusPaymentMethod: 'paypal',
|
||||
sub2api: {},
|
||||
codex2api: {},
|
||||
luckmail: {},
|
||||
smsProviders: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## 4. 四层状态边界
|
||||
|
||||
### 4.1 共享运行态 `runtimeState.shared`
|
||||
|
||||
只放“运行任何 flow 都需要”的内容:
|
||||
|
||||
- `activeFlowId / activeRunId / currentNodeId / nodeStatuses`
|
||||
- `automationWindowId`
|
||||
- `tabRegistry`
|
||||
- `sourceLastUrls`
|
||||
- `logs`
|
||||
- 自动运行轮次、暂停、计时器计划
|
||||
- 账号产物总览,如最终身份、最终邮箱、最终手机号、完成时间
|
||||
|
||||
这里不要再放 OpenAI 特有概念,例如 `plusCheckoutTabId`、`currentPhoneActivation`。
|
||||
|
||||
### 4.2 共享服务状态 `runtimeState.services`
|
||||
|
||||
放“可被多个 flow 复用的服务运行态”,而不是具体网站流程状态:
|
||||
|
||||
- 邮箱 provider 当前会话
|
||||
- 2925 / Hotmail / iCloud / Cloud Mail 等共享邮箱服务上下文
|
||||
- IP 代理当前应用结果、探测结果、池游标
|
||||
- 可复用的共享账号池游标
|
||||
|
||||
注意:`LuckMail` 目前不进这一层,它仍属于 OpenAI flow 私有能力。
|
||||
|
||||
### 4.3 flow 私有运行态 `runtimeState.flows[flowId]`
|
||||
|
||||
每个 flow 自己保管自己的业务运行态。当前 OpenAI 至少应拆成:
|
||||
|
||||
- `auth`:`oauthUrl`、`localhostUrl`
|
||||
- `platformBinding`:`sub2api*`、`codex2api*`
|
||||
- `plus`:`plusCheckoutTabId`、`plusCheckoutUrl`、`plusBillingAddress`
|
||||
- `phoneVerification`:`currentPhoneActivation`、`signupPhoneActivation`、`reusablePhoneActivation`
|
||||
- `luckmail`:`currentLuckmailPurchase`、`currentLuckmailMailCursor`
|
||||
- `identity`:OpenAI 特有的登录方式冻结结果、`step8VerificationTargetEmail` 等
|
||||
|
||||
### 4.4 持久配置 `settings`
|
||||
|
||||
持久配置必须按“共享 / 服务 / flow 私有”拆开,不再把所有配置都平铺到同一个 namespace。
|
||||
|
||||
特别注意:
|
||||
|
||||
- `signupMethod` 先保留在 `flows.openai`,不要急着抽成全局通用枚举。
|
||||
- `plusModeEnabled`、`plusPaymentMethod`、`gopay*`、`paypal*` 都属于 OpenAI flow 私有配置。
|
||||
- `phoneVerificationEnabled` 当前也属于 OpenAI flow 私有配置。
|
||||
|
||||
## 5. 旧步骤兼容层怎么做
|
||||
|
||||
迁移阶段仍要保留 `currentStep / stepStatuses`,但它们不再是主数据,只是 `legacyStepCompat` 的派生视图。
|
||||
|
||||
建议规则:
|
||||
|
||||
1. 新的 canonical 状态只写 `activeFlowId / currentNodeId / nodeStatuses`
|
||||
2. OpenAI flow 通过 node-to-step 映射生成 `legacyStepCompat`
|
||||
3. `getState()` 对旧模块仍返回:
|
||||
- `currentStep`
|
||||
- `stepStatuses`
|
||||
- OpenAI 旧字段镜像
|
||||
4. `setStepStatus(step, status)` 内部先更新 node,再回写 legacy step 视图
|
||||
|
||||
这样可以保证:
|
||||
|
||||
- `background/auto-run-controller.js` 先不重写也能跑
|
||||
- `background/logging-status.js` 先不重写也能继续渲染
|
||||
- `background/account-run-history.js` 仍能按旧语义落盘
|
||||
|
||||
## 6. 账号记录与自动运行的兼容策略
|
||||
|
||||
### 6.1 自动运行
|
||||
|
||||
`background/auto-run-controller.js` 当前按数字步骤推断进度、失败点和恢复点。迁移阶段要增加一层统一 selector:
|
||||
|
||||
- `getActiveRunProgress(state)`
|
||||
- `getLegacyStepCompat(state)`
|
||||
- `inferResumeNode(state, flowId)`
|
||||
|
||||
第一阶段可以继续让 OpenAI flow 通过旧 step 恢复;第二个 flow 接入时再真正改成 node-based resume。
|
||||
|
||||
### 6.2 账号记录
|
||||
|
||||
`background/account-run-history.js` 不能只记“失败在第几步”,还要开始记录:
|
||||
|
||||
- `activeFlowId`
|
||||
- `activeRunId`
|
||||
- `currentNodeId`
|
||||
- `nodeStatuses` 摘要
|
||||
- `legacyFailedStep`(仅 OpenAI 兼容)
|
||||
|
||||
否则未来多 flow 下,单看 `step7_failed` 已经没有意义。
|
||||
|
||||
## 7. 命名约束
|
||||
|
||||
仓库里已经存在别的 `flow_id` 语义,用在 GPC / GoPay 远端任务里。为了避免冲突:
|
||||
|
||||
- 扩展内部运行态统一使用 `activeFlowId`
|
||||
- 当前轮标识统一使用 `activeRunId`
|
||||
- 节点标识统一使用 `currentNodeId`
|
||||
- 不新增裸字段 `flowId`
|
||||
|
||||
`flow_id` 只保留给外部接口 payload 兼容使用。
|
||||
|
||||
## 8. 第一阶段迁移顺序
|
||||
|
||||
1. 新增状态 selector / patch helper,不改业务步骤行为。
|
||||
2. 给 OpenAI flow 建立 `flowState.openai` 命名空间,同时保留旧字段镜像。
|
||||
3. 把日志、自动运行、账号记录改为优先读 selector,不直接拼 `stepStatuses`。
|
||||
4. 把新加字段一律放进 `shared / services / flows.openai`,禁止继续向 `DEFAULT_STATE` 顶层加 OpenAI 字段。
|
||||
5. 第二个 flow 接入前,再清理旧 step 镜像的写路径。
|
||||
|
||||
## 9. 本文对应解决的缺口
|
||||
|
||||
本文主要补齐以下缺口:
|
||||
|
||||
- `DEFAULT_STATE` 扁平模型没有命名空间
|
||||
- 旧步骤状态与新 node 状态如何并存
|
||||
- 自动运行 / 日志 / 账号记录如何不被状态迁移打断
|
||||
- `registrationEmailState` 当前仍隐含“手机号是唯一可保留主身份”的假设
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
# 多注册流程邮件分层设计
|
||||
|
||||
本文专门解决“邮件轮询虽然看起来像公共能力,但实际 OpenAI 规则已经写进 provider 脚本和后台轮询里”这个问题。
|
||||
|
||||
## 1. 先说结论
|
||||
|
||||
邮件相关能力必须拆成两层,不能再只写一句“mail polling 通用化”:
|
||||
|
||||
1. `mail provider driver`
|
||||
2. `flow mail rules`
|
||||
|
||||
前者负责“怎么从 Gmail / 163 / 2925 / Inbucket / API 邮箱里拿到邮件”,后者负责“哪封邮件算当前 flow 需要的验证码 / magic link / 激活链接”。
|
||||
|
||||
## 2. 当前源码里的真实耦合
|
||||
|
||||
### 2.1 后台轮询 payload 已经带着 OpenAI 过滤条件
|
||||
|
||||
`background/verification-flow.js` 当前在 `getVerificationPollPayload()` 里直接写死:
|
||||
|
||||
- `senderFilters: ['openai', 'noreply', 'verify', 'auth', ...]`
|
||||
- `subjectFilters: ['verify', 'verification', 'code', '验证码', 'confirm', ...]`
|
||||
|
||||
这不是 provider 通用逻辑,而是 OpenAI flow 规则。
|
||||
|
||||
### 2.2 内容脚本也已经写死 OpenAI / ChatGPT 正则
|
||||
|
||||
当前多个 provider 脚本里直接内嵌了 OpenAI / ChatGPT 识别:
|
||||
|
||||
- `content/gmail-mail.js`
|
||||
- `content/mail-163.js`
|
||||
- `content/mail-2925.js`
|
||||
- `content/inbucket-mail.js`
|
||||
|
||||
例如:
|
||||
|
||||
- `openai`
|
||||
- `chatgpt`
|
||||
- `verification`
|
||||
- `log-in code`
|
||||
- `strictChatGPTCodeOnly`
|
||||
|
||||
这意味着现在不是“通用 provider + OpenAI 规则”,而是“OpenAI 规则渗透进 provider 实现本身”。
|
||||
|
||||
### 2.3 LuckMail 不能直接算进共享邮件层
|
||||
|
||||
LuckMail 当前还有一个额外边界:它不只是“邮箱提供商”,还绑定了 OpenAI 项目购邮与复用语义。
|
||||
|
||||
当前事实包括:
|
||||
|
||||
- `DEFAULT_LUCKMAIL_PROJECT_CODE = 'openai'`
|
||||
- sidepanel 明确只展示 `openai` 项目的 LuckMail 邮箱
|
||||
|
||||
所以 LuckMail 当前应留在 OpenAI flow 内,不直接并入通用 `mailProviders`。
|
||||
|
||||
## 3. 目标分层
|
||||
|
||||
## 3.1 第一层:`mail provider driver`
|
||||
|
||||
这一层只负责 provider 访问与消息归一化,不理解具体网站业务。
|
||||
|
||||
职责包括:
|
||||
|
||||
- 打开 provider 页面或请求 provider API
|
||||
- 等待页面 ready / 会话可用
|
||||
- 列邮件、开邮件、取正文、删邮件
|
||||
- 会话级去重
|
||||
- 输出统一格式的消息对象
|
||||
|
||||
建议输出结构:
|
||||
|
||||
```js
|
||||
{
|
||||
providerId: 'gmail',
|
||||
messageId: 'abc123',
|
||||
receivedAt: 1710000000000,
|
||||
sender: 'OpenAI <noreply@openai.com>',
|
||||
subject: 'Your code is 123456',
|
||||
previewText: 'Your code is 123456',
|
||||
normalizedText: 'your code is 123456',
|
||||
html: '<html>...</html>',
|
||||
links: ['https://...'],
|
||||
targetHints: ['user@example.com'],
|
||||
metadata: {},
|
||||
}
|
||||
```
|
||||
|
||||
这一层不要再写:
|
||||
|
||||
- “这是不是 OpenAI 邮件”
|
||||
- “是不是 ChatGPT 登录码”
|
||||
- “这个 code 是否必须 6 位”
|
||||
|
||||
## 3.2 第二层:`flow mail rules`
|
||||
|
||||
这一层由具体 flow 定义:
|
||||
|
||||
- 要找的邮件类型
|
||||
- 过滤条件
|
||||
- 选择规则
|
||||
- 提取规则
|
||||
- 命中后的消费动作
|
||||
|
||||
建议接口:
|
||||
|
||||
```js
|
||||
flow.mailRules = {
|
||||
signupCode: {
|
||||
buildQuery(state) {},
|
||||
matchMessage(message, state) {},
|
||||
extractArtifact(message, state) {},
|
||||
afterConsume(message, provider, state) {},
|
||||
},
|
||||
loginCode: {
|
||||
buildQuery(state) {},
|
||||
matchMessage(message, state) {},
|
||||
extractArtifact(message, state) {},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
- `buildQuery` 负责时间窗、目标邮箱、允许的发件人线索
|
||||
- `matchMessage` 负责判定这是不是当前 flow 的邮件
|
||||
- `extractArtifact` 负责提取 `code / magic-link / activation-link`
|
||||
- `afterConsume` 负责删除邮件、记录 cursor、保存已试 code
|
||||
|
||||
## 4. 建议的共享 mail service 接口
|
||||
|
||||
```js
|
||||
mailService.poll({
|
||||
providerId: 'gmail',
|
||||
rule: flow.mailRules.signupCode,
|
||||
state,
|
||||
maxAttempts: 5,
|
||||
intervalMs: 3000,
|
||||
});
|
||||
```
|
||||
|
||||
内部流程:
|
||||
|
||||
1. provider driver 按 query 拉取候选消息
|
||||
2. rule 决定哪封命中
|
||||
3. rule 提取 artifact
|
||||
4. service 返回统一结果
|
||||
|
||||
返回值示例:
|
||||
|
||||
```js
|
||||
{
|
||||
ok: true,
|
||||
artifact: {
|
||||
type: 'code',
|
||||
value: '123456',
|
||||
},
|
||||
message: { ...normalizedMessage },
|
||||
}
|
||||
```
|
||||
|
||||
## 5. OpenAI flow 当前应该拆出的规则
|
||||
|
||||
OpenAI 至少需要单独拆出这些规则文件:
|
||||
|
||||
- `flows/openai/mail-rules/signup-code.js`
|
||||
- `flows/openai/mail-rules/login-code.js`
|
||||
- `flows/openai/mail-rules/add-email-code.js`
|
||||
|
||||
它们负责承接现在散落在这些地方的规则:
|
||||
|
||||
- `verification-flow.js` 中的 sender / subject filters
|
||||
- `gmail-mail.js` / `mail-163.js` / `mail-2925.js` / `inbucket-mail.js` 中的 OpenAI / ChatGPT 正则
|
||||
- `strictChatGPTCodeOnly`
|
||||
- Step 4 与 Step 8 不同的时间窗和目标邮箱逻辑
|
||||
|
||||
## 6. provider driver 的拆分建议
|
||||
|
||||
### 6.1 可以进入共享层的 provider
|
||||
|
||||
这些 provider 的访问方式本身有共享价值,可以做成共享 mail driver:
|
||||
|
||||
- Gmail
|
||||
- 163 / 126 / 163 VIP
|
||||
- 2925
|
||||
- Inbucket
|
||||
- iCloud Mail
|
||||
- Hotmail helper / Graph Mail
|
||||
- Cloud Mail / SkyMail
|
||||
|
||||
### 6.2 暂时不进入共享层的 provider
|
||||
|
||||
- LuckMail:当前仍是 OpenAI 项目购邮与验证码轮询能力的一部分
|
||||
|
||||
如果未来第二个 flow 也明确复用 LuckMail,且复用的是“同一套 project / token / 生命周期”,再考虑把它抽出来。
|
||||
|
||||
## 7. `registrationEmailState` 与邮件层的关系
|
||||
|
||||
`registrationEmailState` 负责“当前流程邮箱身份”,不是“provider 拉信规则”。
|
||||
|
||||
所以后续边界应是:
|
||||
|
||||
- `registrationEmailState`:运行态身份记录
|
||||
- `mail provider driver`:拉信能力
|
||||
- `flow mail rules`:判定与提取
|
||||
|
||||
不要再在 `registrationEmailState` 或 provider driver 里夹带 OpenAI `add-email` 业务判断。
|
||||
|
||||
## 8. 迁移顺序
|
||||
|
||||
1. 先把 `background/verification-flow.js` 里的查询构造迁到 `flows/openai/mail-rules/*`
|
||||
2. 再把各 provider 脚本里的 OpenAI / ChatGPT 正则搬出到 rule 层
|
||||
3. 保留 provider 里的“消息抓取 / 页面操作 / 删除策略”
|
||||
4. 等第二个 flow 接入时,只新增它自己的 `mail-rules`,不改 Gmail / 163 / 2925 driver
|
||||
|
||||
## 9. 本文对应解决的缺口
|
||||
|
||||
本文主要补齐以下缺口:
|
||||
|
||||
- “Mail polling 通用化”表述过于粗糙,没有说明 provider 与 rule 两层
|
||||
- provider 内容脚本里已经嵌入 OpenAI 规则
|
||||
- `strictChatGPTCodeOnly` 这类开关的归属边界不清
|
||||
- LuckMail 当前其实还是 OpenAI flow 私有邮件能力,不是共享 provider
|
||||
|
||||
Reference in New Issue
Block a user