refactor flows into canonical runtime architecture
This commit is contained in:
+139
-121
@@ -1,11 +1,17 @@
|
||||
// background.js — Service Worker: orchestration, state, tab management, message routing
|
||||
// background.js — Service Worker: orchestration, state, tab management, message routing
|
||||
|
||||
importScripts(
|
||||
'shared/flow-registry.js',
|
||||
'flows/openai/index.js',
|
||||
'flows/openai/workflow.js',
|
||||
'flows/kiro/index.js',
|
||||
'flows/kiro/workflow.js',
|
||||
'flows/index.js',
|
||||
'core/flow-kernel/flow-registry.js',
|
||||
'shared/contribution-registry.js',
|
||||
'shared/settings-schema.js',
|
||||
'shared/source-registry.js',
|
||||
'shared/flow-capabilities.js',
|
||||
'core/flow-kernel/settings-schema.js',
|
||||
'imports/legacy/settings-importer.js',
|
||||
'core/flow-kernel/source-registry.js',
|
||||
'core/flow-kernel/flow-capabilities.js',
|
||||
'shared/kiro-timeouts.js',
|
||||
'managed-alias-utils.js',
|
||||
'mail2925-utils.js',
|
||||
@@ -25,15 +31,15 @@ importScripts(
|
||||
'background/cpa-api.js',
|
||||
'background/panel-bridge.js',
|
||||
'background/registration-email-state.js',
|
||||
'background/workflow-engine.js',
|
||||
'background/runtime-state.js',
|
||||
'background/kiro/state.js',
|
||||
'background/kiro/credential-artifact.js',
|
||||
'core/flow-kernel/workflow-engine.js',
|
||||
'core/flow-kernel/runtime-state.js',
|
||||
'flows/kiro/background/state.js',
|
||||
'flows/kiro/background/credential-artifact.js',
|
||||
'background/contribution/adapters/kiro-builder-id.js',
|
||||
'background/kiro/register-runner.js',
|
||||
'background/kiro/desktop-client.js',
|
||||
'background/kiro/desktop-authorize-runner.js',
|
||||
'background/kiro/publisher-kiro-rs.js',
|
||||
'flows/kiro/background/register-runner.js',
|
||||
'flows/kiro/background/desktop-client.js',
|
||||
'flows/kiro/background/desktop-authorize-runner.js',
|
||||
'flows/kiro/background/publisher-kiro-rs.js',
|
||||
'background/generated-email-helpers.js',
|
||||
'background/signup-flow-helpers.js',
|
||||
'background/mail-rule-registry.js',
|
||||
@@ -41,30 +47,30 @@ importScripts(
|
||||
'background/message-router.js',
|
||||
'background/verification-flow.js',
|
||||
'background/auto-run-controller.js',
|
||||
'background/tab-runtime.js',
|
||||
'core/flow-kernel/tab-runtime.js',
|
||||
'background/navigation-utils.js',
|
||||
'background/logging-status.js',
|
||||
'background/steps/registry.js',
|
||||
'core/flow-kernel/logging-status.js',
|
||||
'core/flow-kernel/step-registry.js',
|
||||
'data/step-definitions.js',
|
||||
'data/address-sources.js',
|
||||
'background/steps/open-chatgpt.js',
|
||||
'background/steps/submit-signup-email.js',
|
||||
'background/steps/fill-password.js',
|
||||
'background/steps/fetch-signup-code.js',
|
||||
'background/steps/fill-profile.js',
|
||||
'background/steps/wait-registration-success.js',
|
||||
'background/steps/create-plus-checkout.js',
|
||||
'background/steps/fill-plus-checkout.js',
|
||||
'background/steps/gopay-manual-confirm.js',
|
||||
'background/steps/paypal-approve.js',
|
||||
'background/steps/gopay-approve.js',
|
||||
'background/steps/plus-return-confirm.js',
|
||||
'background/steps/sub2api-session-import.js',
|
||||
'background/steps/cpa-session-import.js',
|
||||
'background/steps/oauth-login.js',
|
||||
'background/steps/fetch-login-code.js',
|
||||
'background/steps/confirm-oauth.js',
|
||||
'background/steps/platform-verify.js',
|
||||
'flows/openai/background/steps/open-chatgpt.js',
|
||||
'flows/openai/background/steps/submit-signup-email.js',
|
||||
'flows/openai/background/steps/fill-password.js',
|
||||
'flows/openai/background/steps/fetch-signup-code.js',
|
||||
'flows/openai/background/steps/fill-profile.js',
|
||||
'flows/openai/background/steps/wait-registration-success.js',
|
||||
'flows/openai/background/steps/create-plus-checkout.js',
|
||||
'flows/openai/background/steps/fill-plus-checkout.js',
|
||||
'flows/openai/background/steps/gopay-manual-confirm.js',
|
||||
'flows/openai/background/steps/paypal-approve.js',
|
||||
'flows/openai/background/steps/gopay-approve.js',
|
||||
'flows/openai/background/steps/plus-return-confirm.js',
|
||||
'flows/openai/background/steps/sub2api-session-import.js',
|
||||
'flows/openai/background/steps/cpa-session-import.js',
|
||||
'flows/openai/background/steps/oauth-login.js',
|
||||
'flows/openai/background/steps/fetch-login-code.js',
|
||||
'flows/openai/background/steps/confirm-oauth.js',
|
||||
'flows/openai/background/steps/platform-verify.js',
|
||||
'data/names.js',
|
||||
'hotmail-utils.js',
|
||||
'microsoft-email.js',
|
||||
@@ -498,15 +504,6 @@ function buildStatePatchWithRuntimeState(currentState = {}, updates = {}) {
|
||||
if (runtimeStateHelpers?.buildSessionStatePatch) {
|
||||
nextPatch = runtimeStateHelpers.buildSessionStatePatch(currentState, nextPatch);
|
||||
}
|
||||
if (kiroStateHelpers?.buildSessionStatePatch) {
|
||||
const kiroPatch = kiroStateHelpers.buildSessionStatePatch(currentState, updates);
|
||||
if (kiroPatch && Object.keys(kiroPatch).length > 0) {
|
||||
nextPatch = {
|
||||
...nextPatch,
|
||||
...kiroPatch,
|
||||
};
|
||||
}
|
||||
}
|
||||
return nextPatch;
|
||||
}
|
||||
|
||||
@@ -894,7 +891,7 @@ function buildResolvedStepDefinitionState(state = {}) {
|
||||
signupMethod: requestedSignupMethod,
|
||||
}, {
|
||||
activeFlowId: requestedActiveFlowId,
|
||||
panelMode: state?.panelMode,
|
||||
targetId: state?.targetId,
|
||||
signupMethod: requestedSignupMethod,
|
||||
})
|
||||
: null;
|
||||
@@ -910,7 +907,6 @@ function buildResolvedStepDefinitionState(state = {}) {
|
||||
...state,
|
||||
activeFlowId: resolvedActiveFlowId,
|
||||
flowId: resolvedActiveFlowId,
|
||||
panelMode: stepDefinitionOptions.panelMode || capabilityState?.effectivePanelMode || state?.panelMode,
|
||||
targetId: stepDefinitionOptions.targetId || capabilityState?.effectiveTargetId || state?.targetId,
|
||||
plusModeEnabled: stepDefinitionOptions.plusModeEnabled === undefined
|
||||
? plusModeEnabled
|
||||
@@ -1178,9 +1174,8 @@ function setupDeclarativeNetRequestRules() {
|
||||
// ============================================================
|
||||
|
||||
const PERSISTED_SETTING_DEFAULTS = {
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
kiroTargetId: 'kiro-rs',
|
||||
kiroRsUrl: String(self.MultiPageFlowRegistry?.DEFAULT_KIRO_RS_URL || '').trim(),
|
||||
kiroRsKey: '',
|
||||
vpsUrl: '',
|
||||
@@ -1371,9 +1366,7 @@ const PERSISTED_SETTING_KEYS = Object.keys(PERSISTED_SETTING_DEFAULTS);
|
||||
const PERSISTED_SETTINGS_SCHEMA_KEYS = ['settingsSchemaVersion', 'settingsState'];
|
||||
const SETTINGS_SCHEMA_VIEW_KEYS = Object.freeze([
|
||||
'activeFlowId',
|
||||
'openaiIntegrationTargetId',
|
||||
'panelMode',
|
||||
'kiroTargetId',
|
||||
'targetId',
|
||||
'vpsUrl',
|
||||
'vpsPassword',
|
||||
'localCpaStep9Mode',
|
||||
@@ -1417,7 +1410,6 @@ const DEFAULT_STATE = {
|
||||
currentNodeId: '',
|
||||
nodeStatuses: { ...DEFAULT_NODE_STATUSES },
|
||||
runtimeState: runtimeStateHelpers?.buildDefaultRuntimeState?.() || null,
|
||||
kiroRuntime: kiroStateHelpers?.buildDefaultRuntimeState?.() || null,
|
||||
...CONTRIBUTION_RUNTIME_DEFAULTS,
|
||||
accounts: [], // 已生成账号记录:{ email, password, createdAt }。
|
||||
accountRunHistory: [], // 账号运行历史快照,实际持久化在 chrome.storage.local。
|
||||
@@ -1819,7 +1811,7 @@ function resolveCurrentFlowCapabilities(state = {}, options = {}) {
|
||||
}
|
||||
return registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: options?.activeFlowId ?? state?.activeFlowId,
|
||||
panelMode: options?.panelMode ?? state?.panelMode,
|
||||
targetId: options?.targetId ?? state?.targetId,
|
||||
signupMethod: options?.signupMethod ?? state?.signupMethod,
|
||||
state,
|
||||
});
|
||||
@@ -1832,7 +1824,7 @@ function validateAutoRunStartState(state = {}, options = {}) {
|
||||
}
|
||||
return registry.validateAutoRunStart({
|
||||
activeFlowId: options?.activeFlowId ?? state?.activeFlowId,
|
||||
panelMode: options?.panelMode ?? state?.panelMode,
|
||||
targetId: options?.targetId ?? state?.targetId,
|
||||
signupMethod: options?.signupMethod ?? state?.signupMethod,
|
||||
state,
|
||||
});
|
||||
@@ -1851,7 +1843,7 @@ function validateModeSwitchState(state = {}, options = {}) {
|
||||
return registry.validateModeSwitch({
|
||||
activeFlowId: options?.activeFlowId ?? state?.activeFlowId,
|
||||
changedKeys: options?.changedKeys,
|
||||
panelMode: options?.panelMode ?? state?.panelMode,
|
||||
targetId: options?.targetId ?? state?.targetId,
|
||||
signupMethod: options?.signupMethod ?? state?.signupMethod,
|
||||
state,
|
||||
});
|
||||
@@ -1868,7 +1860,7 @@ function canUsePhoneSignup(state = {}) {
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: state?.activeFlowId,
|
||||
panelMode: state?.panelMode,
|
||||
targetId: state?.targetId,
|
||||
signupMethod: state?.signupMethod,
|
||||
state,
|
||||
})
|
||||
@@ -1898,7 +1890,7 @@ function resolveSignupMethod(state = {}) {
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: state?.activeFlowId,
|
||||
panelMode: state?.panelMode,
|
||||
targetId: state?.targetId,
|
||||
signupMethod: method,
|
||||
state,
|
||||
})
|
||||
@@ -3049,18 +3041,13 @@ function normalizeStepExecutionRangeByFlow(value = {}) {
|
||||
|
||||
function normalizePersistentSettingValue(key, value) {
|
||||
switch (key) {
|
||||
case 'panelMode':
|
||||
return normalizePanelMode(value);
|
||||
case 'targetId':
|
||||
return String(value || '').trim().toLowerCase();
|
||||
case 'activeFlowId':
|
||||
if (typeof self.MultiPageFlowRegistry?.normalizeFlowId === 'function') {
|
||||
return self.MultiPageFlowRegistry.normalizeFlowId(value, DEFAULT_ACTIVE_FLOW_ID);
|
||||
}
|
||||
return String(value || '').trim().toLowerCase() === 'kiro' ? 'kiro' : DEFAULT_ACTIVE_FLOW_ID;
|
||||
case 'kiroTargetId':
|
||||
if (typeof self.MultiPageFlowRegistry?.normalizeTargetId === 'function') {
|
||||
return self.MultiPageFlowRegistry.normalizeTargetId('kiro', value, 'kiro-rs');
|
||||
}
|
||||
return String(value || '').trim().toLowerCase() === 'kiro-rs' ? 'kiro-rs' : 'kiro-rs';
|
||||
case 'kiroRsUrl':
|
||||
return String(value || '').trim();
|
||||
case 'kiroRsKey':
|
||||
@@ -3575,7 +3562,7 @@ function buildPersistentSettingsPayload(input = {}, options = {}) {
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'phoneVerificationEnabled')
|
||||
|| Object.prototype.hasOwnProperty.call(payload, 'plusModeEnabled')
|
||||
|| Object.prototype.hasOwnProperty.call(payload, 'signupMethod')
|
||||
|| Object.prototype.hasOwnProperty.call(payload, 'panelMode')
|
||||
|| Object.prototype.hasOwnProperty.call(payload, 'targetId')
|
||||
|| Object.prototype.hasOwnProperty.call(payload, 'activeFlowId')) {
|
||||
payload.signupMethod = resolveSignupMethod(nextSignupConstraintState);
|
||||
}
|
||||
@@ -3689,6 +3676,13 @@ function mergeSettingsStatePatch(baseValue = {}, patchValue = {}) {
|
||||
function buildSettingsStatePatchFromFlatUpdates(updates = {}) {
|
||||
const patch = {};
|
||||
const hasUpdate = (key) => Object.prototype.hasOwnProperty.call(updates, key);
|
||||
const normalizePatchFlowId = (value = '', fallback = DEFAULT_ACTIVE_FLOW_ID) => {
|
||||
if (typeof self.MultiPageFlowRegistry?.normalizeFlowId === 'function') {
|
||||
return self.MultiPageFlowRegistry.normalizeFlowId(value, fallback);
|
||||
}
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
return normalized || String(fallback || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID;
|
||||
};
|
||||
const assignIfUpdated = (key, path) => {
|
||||
if (hasUpdate(key)) {
|
||||
setSettingsStatePatchValue(patch, path, updates[key]);
|
||||
@@ -3696,26 +3690,29 @@ function buildSettingsStatePatchFromFlatUpdates(updates = {}) {
|
||||
};
|
||||
|
||||
assignIfUpdated('activeFlowId', ['activeFlowId']);
|
||||
if (hasUpdate('openaiIntegrationTargetId') || hasUpdate('panelMode')) {
|
||||
if (hasUpdate('selectedTargetId') || hasUpdate('targetId')) {
|
||||
const flowId = normalizePatchFlowId(
|
||||
updates.activeFlowId ?? updates.flowId,
|
||||
DEFAULT_ACTIVE_FLOW_ID
|
||||
);
|
||||
setSettingsStatePatchValue(
|
||||
patch,
|
||||
['flows', 'openai', 'integrationTargetId'],
|
||||
hasUpdate('openaiIntegrationTargetId') ? updates.openaiIntegrationTargetId : updates.panelMode
|
||||
['flows', flowId, 'selectedTargetId'],
|
||||
hasUpdate('selectedTargetId') ? updates.selectedTargetId : updates.targetId
|
||||
);
|
||||
}
|
||||
assignIfUpdated('kiroTargetId', ['flows', 'kiro', 'targetId']);
|
||||
assignIfUpdated('vpsUrl', ['flows', 'openai', 'integrationTargets', 'cpa', 'vpsUrl']);
|
||||
assignIfUpdated('vpsPassword', ['flows', 'openai', 'integrationTargets', 'cpa', 'vpsPassword']);
|
||||
assignIfUpdated('localCpaStep9Mode', ['flows', 'openai', 'integrationTargets', 'cpa', 'localCpaStep9Mode']);
|
||||
assignIfUpdated('sub2apiUrl', ['flows', 'openai', 'integrationTargets', 'sub2api', 'sub2apiUrl']);
|
||||
assignIfUpdated('sub2apiEmail', ['flows', 'openai', 'integrationTargets', 'sub2api', 'sub2apiEmail']);
|
||||
assignIfUpdated('sub2apiPassword', ['flows', 'openai', 'integrationTargets', 'sub2api', 'sub2apiPassword']);
|
||||
assignIfUpdated('sub2apiGroupName', ['flows', 'openai', 'integrationTargets', 'sub2api', 'sub2apiGroupName']);
|
||||
assignIfUpdated('sub2apiGroupNames', ['flows', 'openai', 'integrationTargets', 'sub2api', 'sub2apiGroupNames']);
|
||||
assignIfUpdated('sub2apiAccountPriority', ['flows', 'openai', 'integrationTargets', 'sub2api', 'sub2apiAccountPriority']);
|
||||
assignIfUpdated('sub2apiDefaultProxyName', ['flows', 'openai', 'integrationTargets', 'sub2api', 'sub2apiDefaultProxyName']);
|
||||
assignIfUpdated('codex2apiUrl', ['flows', 'openai', 'integrationTargets', 'codex2api', 'codex2apiUrl']);
|
||||
assignIfUpdated('codex2apiAdminKey', ['flows', 'openai', 'integrationTargets', 'codex2api', 'codex2apiAdminKey']);
|
||||
assignIfUpdated('vpsUrl', ['flows', 'openai', 'targets', 'cpa', 'vpsUrl']);
|
||||
assignIfUpdated('vpsPassword', ['flows', 'openai', 'targets', 'cpa', 'vpsPassword']);
|
||||
assignIfUpdated('localCpaStep9Mode', ['flows', 'openai', 'targets', 'cpa', 'localCpaStep9Mode']);
|
||||
assignIfUpdated('sub2apiUrl', ['flows', 'openai', 'targets', 'sub2api', 'sub2apiUrl']);
|
||||
assignIfUpdated('sub2apiEmail', ['flows', 'openai', 'targets', 'sub2api', 'sub2apiEmail']);
|
||||
assignIfUpdated('sub2apiPassword', ['flows', 'openai', 'targets', 'sub2api', 'sub2apiPassword']);
|
||||
assignIfUpdated('sub2apiGroupName', ['flows', 'openai', 'targets', 'sub2api', 'sub2apiGroupName']);
|
||||
assignIfUpdated('sub2apiGroupNames', ['flows', 'openai', 'targets', 'sub2api', 'sub2apiGroupNames']);
|
||||
assignIfUpdated('sub2apiAccountPriority', ['flows', 'openai', 'targets', 'sub2api', 'sub2apiAccountPriority']);
|
||||
assignIfUpdated('sub2apiDefaultProxyName', ['flows', 'openai', 'targets', 'sub2api', 'sub2apiDefaultProxyName']);
|
||||
assignIfUpdated('codex2apiUrl', ['flows', 'openai', 'targets', 'codex2api', 'codex2apiUrl']);
|
||||
assignIfUpdated('codex2apiAdminKey', ['flows', 'openai', 'targets', 'codex2api', 'codex2apiAdminKey']);
|
||||
assignIfUpdated('customPassword', ['services', 'account', 'customPassword']);
|
||||
assignIfUpdated('signupMethod', ['flows', 'openai', 'signup', 'signupMethod']);
|
||||
assignIfUpdated('phoneVerificationEnabled', ['flows', 'openai', 'signup', 'phoneVerificationEnabled']);
|
||||
@@ -3850,6 +3847,18 @@ function buildAutoRunFreshResetSettingsState(prevState = {}, activeFlowId = DEFA
|
||||
const currentSettingsState = isPlainObjectValue(prevState?.settingsState)
|
||||
? prevState.settingsState
|
||||
: {};
|
||||
const settingsSchemaApi = typeof getSettingsSchemaApi === 'function'
|
||||
? getSettingsSchemaApi()
|
||||
: null;
|
||||
const normalizedCurrentSettingsState = settingsSchemaApi?.normalizeSettingsState
|
||||
? settingsSchemaApi.normalizeSettingsState({
|
||||
...prevState,
|
||||
activeFlowId,
|
||||
settingsState: currentSettingsState,
|
||||
}, {
|
||||
activeFlowId,
|
||||
})
|
||||
: currentSettingsState;
|
||||
const normalizedStepExecutionRangeByFlow = normalizeStepExecutionRangeByFlow(prevState?.stepExecutionRangeByFlow || {});
|
||||
const nextSettingsStatePatch = {
|
||||
activeFlowId,
|
||||
@@ -3868,7 +3877,9 @@ function buildAutoRunFreshResetSettingsState(prevState = {}, activeFlowId = DEFA
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
integrationTargetId: prevState?.openaiIntegrationTargetId || prevState?.panelMode,
|
||||
selectedTargetId: settingsSchemaApi?.getSelectedTargetId
|
||||
? settingsSchemaApi.getSelectedTargetId(normalizedCurrentSettingsState, 'openai')
|
||||
: undefined,
|
||||
autoRun: normalizedStepExecutionRangeByFlow.openai
|
||||
? {
|
||||
stepExecutionRange: normalizedStepExecutionRangeByFlow.openai,
|
||||
@@ -3876,7 +3887,9 @@ function buildAutoRunFreshResetSettingsState(prevState = {}, activeFlowId = DEFA
|
||||
: undefined,
|
||||
},
|
||||
kiro: {
|
||||
targetId: prevState?.kiroTargetId,
|
||||
selectedTargetId: settingsSchemaApi?.getSelectedTargetId
|
||||
? settingsSchemaApi.getSelectedTargetId(normalizedCurrentSettingsState, 'kiro')
|
||||
: undefined,
|
||||
autoRun: normalizedStepExecutionRangeByFlow.kiro
|
||||
? {
|
||||
stepExecutionRange: normalizedStepExecutionRangeByFlow.kiro,
|
||||
@@ -3918,15 +3931,14 @@ function buildFreshAutoRunKeepState(prevState = {}) {
|
||||
|
||||
keepState.activeFlowId = activeFlowId;
|
||||
keepState.flowId = activeFlowId;
|
||||
if (Object.prototype.hasOwnProperty.call(sourceState, 'panelMode')) {
|
||||
keepState.panelMode = normalizePanelMode(sourceState.panelMode);
|
||||
const settingsSchemaApi = typeof getSettingsSchemaApi === 'function'
|
||||
? getSettingsSchemaApi()
|
||||
: null;
|
||||
if (settingsSchemaApi?.getSelectedTargetId) {
|
||||
keepState.targetId = settingsSchemaApi.getSelectedTargetId(settingsState, activeFlowId);
|
||||
}
|
||||
if (typeof kiroStateHelpers?.buildFreshKeepState === 'function') {
|
||||
Object.assign(keepState, kiroStateHelpers.buildFreshKeepState(sourceState));
|
||||
} else if (Object.prototype.hasOwnProperty.call(sourceState, 'kiroTargetId')) {
|
||||
keepState.kiroTargetId = self.MultiPageFlowRegistry?.normalizeTargetId
|
||||
? self.MultiPageFlowRegistry.normalizeTargetId('kiro', sourceState.kiroTargetId, 'kiro-rs')
|
||||
: String(sourceState.kiroTargetId || 'kiro-rs').trim().toLowerCase();
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(sourceState, 'settingsSchemaVersion')) {
|
||||
keepState.settingsSchemaVersion = Number(sourceState.settingsSchemaVersion) || 0;
|
||||
@@ -4172,7 +4184,15 @@ async function importSettingsBundle(configBundle) {
|
||||
throw new Error('\u914d\u7f6e\u6587\u4ef6\u7f3a\u5c11 settings \u914d\u7f6e\u6bb5\u3002');
|
||||
}
|
||||
|
||||
const importedSettings = buildPersistentSettingsPayload(configBundle.settings, {
|
||||
const settingsImporter = self.MultiPageLegacySettingsImporter?.createSettingsImporter?.({
|
||||
flowRegistry: self.MultiPageFlowRegistry,
|
||||
settingsSchemaApi: typeof getSettingsSchemaApi === 'function' ? getSettingsSchemaApi() : null,
|
||||
defaultFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
}) || null;
|
||||
const importedSettingsSource = typeof settingsImporter?.importSettings === 'function'
|
||||
? settingsImporter.importSettings(configBundle.settings)
|
||||
: configBundle.settings;
|
||||
const importedSettings = buildPersistentSettingsPayload(importedSettingsSource, {
|
||||
fillDefaults: true,
|
||||
requireKnownKeys: true,
|
||||
});
|
||||
@@ -4190,7 +4210,7 @@ async function importSettingsBundle(configBundle) {
|
||||
Object.prototype.hasOwnProperty.call(importedSettings, 'phoneVerificationEnabled')
|
||||
|| Object.prototype.hasOwnProperty.call(importedSettings, 'plusModeEnabled')
|
||||
|| Object.prototype.hasOwnProperty.call(importedSettings, 'signupMethod')
|
||||
|| Object.prototype.hasOwnProperty.call(importedSettings, 'panelMode')
|
||||
|| Object.prototype.hasOwnProperty.call(importedSettings, 'targetId')
|
||||
|| Object.prototype.hasOwnProperty.call(importedSettings, 'activeFlowId')
|
||||
|| Object.prototype.hasOwnProperty.call(importedSettings, 'accountContributionEnabled')
|
||||
) {
|
||||
@@ -4436,7 +4456,7 @@ function buildAccountContributionState(enabled, persistedSettings = {}, currentS
|
||||
...(routing ? {
|
||||
contributionSource: routing.source,
|
||||
contributionTargetGroupName: routing.targetGroupName,
|
||||
panelMode: routing.source,
|
||||
targetId: routing.source,
|
||||
} : {}),
|
||||
customPassword: '',
|
||||
accountRunHistoryTextEnabled: false,
|
||||
@@ -4449,7 +4469,7 @@ function buildAccountContributionState(enabled, persistedSettings = {}, currentS
|
||||
accountContributionExpected: false,
|
||||
contributionAdapterId: '',
|
||||
flowContributionRuntime: {},
|
||||
panelMode: persistedSettings.panelMode || DEFAULT_STATE.panelMode,
|
||||
targetId: persistedSettings.targetId || DEFAULT_STATE.targetId,
|
||||
customPassword: persistedSettings.customPassword || '',
|
||||
accountRunHistoryTextEnabled: Boolean(persistedSettings.accountRunHistoryTextEnabled),
|
||||
};
|
||||
@@ -4472,7 +4492,7 @@ async function setAccountContributionMode(enabled, options = {}) {
|
||||
}
|
||||
broadcastDataUpdate({
|
||||
...contributionBroadcast,
|
||||
panelMode: nextState.panelMode,
|
||||
targetId: nextState.targetId,
|
||||
customPassword: nextState.customPassword,
|
||||
accountRunHistoryTextEnabled: nextState.accountRunHistoryTextEnabled,
|
||||
accountRunHistoryHelperBaseUrl: nextState.accountRunHistoryHelperBaseUrl,
|
||||
@@ -8542,10 +8562,10 @@ function getPanelMode(state = {}) {
|
||||
if (typeof navigationUtils !== 'undefined' && navigationUtils?.getPanelMode) {
|
||||
return navigationUtils.getPanelMode(state);
|
||||
}
|
||||
if (state.panelMode === 'sub2api') {
|
||||
if (state.targetId === 'sub2api') {
|
||||
return 'sub2api';
|
||||
}
|
||||
if (state.panelMode === 'codex2api') {
|
||||
if (state.targetId === 'codex2api') {
|
||||
return 'codex2api';
|
||||
}
|
||||
return 'cpa';
|
||||
@@ -8661,7 +8681,6 @@ function matchesSourceUrlFamily(source, candidateUrl, referenceUrl) {
|
||||
const reference = parseUrlSafely(referenceUrl);
|
||||
switch (source) {
|
||||
case 'openai-auth':
|
||||
case 'signup-page':
|
||||
return isSignupPageHost(candidate.hostname) || isSignupEntryHost(candidate.hostname);
|
||||
case 'duck-mail':
|
||||
return candidate.hostname === 'duckduckgo.com' && candidate.pathname.startsWith('/email/');
|
||||
@@ -8975,7 +8994,6 @@ function getSourceLabel(source) {
|
||||
'openai-auth': '认证页',
|
||||
'gmail-mail': 'Gmail 邮箱',
|
||||
'sidepanel': '侧边栏',
|
||||
'signup-page': '认证页',
|
||||
'vps-panel': 'CPA 面板',
|
||||
'sub2api-panel': 'SUB2API 后台',
|
||||
'codex2api-panel': 'Codex2API 后台',
|
||||
@@ -11544,7 +11562,7 @@ async function executeNodeAndWait(nodeId, delayAfter = 2000) {
|
||||
}
|
||||
|
||||
if (normalizedNodeId === 'fill-profile') {
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
const signupTabId = await getTabId('openai-auth');
|
||||
if (signupTabId) {
|
||||
await addLog('自动运行:填写资料节点已收到完成信号,正在等待当前页面完成加载并稳定...', 'info');
|
||||
await waitForTabStableComplete(signupTabId, {
|
||||
@@ -12953,7 +12971,7 @@ async function runAutoSequenceFromNodeGraph(startNodeId, context = {}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
const signupTabId = await getTabId('openai-auth');
|
||||
if (signupTabId) {
|
||||
await chrome.tabs.update(signupTabId, { active: true });
|
||||
}
|
||||
@@ -13236,9 +13254,9 @@ async function resumeAutoRun() {
|
||||
// ============================================================
|
||||
|
||||
const SIGNUP_ENTRY_URL = 'https://chatgpt.com/';
|
||||
const SIGNUP_PAGE_INJECT_FILES = ['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'];
|
||||
const KIRO_REGISTER_INJECT_FILES = ['shared/source-registry.js', 'shared/kiro-timeouts.js', 'content/utils.js', 'content/kiro/register-page.js'];
|
||||
const KIRO_DESKTOP_AUTHORIZE_INJECT_FILES = ['shared/source-registry.js', 'shared/kiro-timeouts.js', 'content/utils.js', 'content/kiro/desktop-authorize-page.js'];
|
||||
const OPENAI_AUTH_INJECT_FILES = ['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'];
|
||||
const KIRO_REGISTER_INJECT_FILES = ['flows/openai/index.js', 'flows/kiro/index.js', 'flows/index.js', 'core/flow-kernel/flow-registry.js', 'core/flow-kernel/source-registry.js', 'shared/kiro-timeouts.js', 'content/utils.js', 'flows/kiro/content/register-page.js'];
|
||||
const KIRO_DESKTOP_AUTHORIZE_INJECT_FILES = ['flows/openai/index.js', 'flows/kiro/index.js', 'flows/index.js', 'core/flow-kernel/flow-registry.js', 'core/flow-kernel/source-registry.js', 'shared/kiro-timeouts.js', 'content/utils.js', 'flows/kiro/content/desktop-authorize-page.js'];
|
||||
const panelBridge = self.MultiPageBackgroundPanelBridge?.createPanelBridge({
|
||||
chrome,
|
||||
addLog,
|
||||
@@ -13287,7 +13305,7 @@ const signupFlowHelpers = self.MultiPageSignupFlowHelpers?.createSignupFlowHelpe
|
||||
setEmailState,
|
||||
setState,
|
||||
SIGNUP_ENTRY_URL,
|
||||
SIGNUP_PAGE_INJECT_FILES,
|
||||
OPENAI_AUTH_INJECT_FILES,
|
||||
waitForTabStableComplete,
|
||||
waitForTabUrlMatch,
|
||||
});
|
||||
@@ -13418,7 +13436,7 @@ const step2Executor = self.MultiPageBackgroundStep2?.createStep2Executor({
|
||||
resolveSignupMethod,
|
||||
resolveSignupEmailForFlow,
|
||||
sendToContentScriptResilient,
|
||||
SIGNUP_PAGE_INJECT_FILES,
|
||||
OPENAI_AUTH_INJECT_FILES,
|
||||
waitForTabStableComplete,
|
||||
});
|
||||
const step3Executor = self.MultiPageBackgroundStep3?.createStep3Executor({
|
||||
@@ -13432,7 +13450,7 @@ const step3Executor = self.MultiPageBackgroundStep3?.createStep3Executor({
|
||||
sendToContentScript,
|
||||
setPasswordState,
|
||||
setState,
|
||||
SIGNUP_PAGE_INJECT_FILES,
|
||||
OPENAI_AUTH_INJECT_FILES,
|
||||
});
|
||||
|
||||
async function ensureIcloudMailSessionForVerification(options = {}) {
|
||||
@@ -13917,7 +13935,7 @@ const messageRouter = self.MultiPageBackgroundMessageRouter?.createMessageRouter
|
||||
},
|
||||
finalizeStep3Completion: async () => {
|
||||
const currentState = await getState();
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
const signupTabId = await getTabId('openai-auth');
|
||||
return signupFlowHelpers.finalizeSignupPasswordSubmitInTab(
|
||||
signupTabId,
|
||||
currentState.password || currentState.customPassword || '',
|
||||
@@ -14143,7 +14161,7 @@ async function executeStep2(state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Step 3: Fill Password (via signup-page.js)
|
||||
// Step 3: Fill Password (via openai-auth.js)
|
||||
// ============================================================
|
||||
|
||||
async function executeStep3(state) {
|
||||
@@ -14151,7 +14169,7 @@ async function executeStep3(state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Step 4: Get Signup Verification Code (qq-mail.js polls, then fills in signup-page.js)
|
||||
// Step 4: Get Signup Verification Code (qq-mail.js polls, then fills in openai-auth.js)
|
||||
// ============================================================
|
||||
|
||||
function getMailConfig(state) {
|
||||
@@ -14305,7 +14323,7 @@ async function executeStep4(state) {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Step 5: Fill Name & Birthday (via signup-page.js)
|
||||
// Step 5: Fill Name & Birthday (via openai-auth.js)
|
||||
// ============================================================
|
||||
|
||||
async function executeStep5(state) {
|
||||
@@ -14659,7 +14677,7 @@ async function getLoginAuthStateFromContent(options = {}) {
|
||||
const logStep = visibleStep > 0 ? visibleStep : null;
|
||||
const { logMessage = '认证页正在切换,等待页面重新就绪后继续确认验证码页状态...' } = options;
|
||||
const result = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
{
|
||||
type: 'GET_LOGIN_AUTH_STATE',
|
||||
source: 'background',
|
||||
@@ -14684,7 +14702,7 @@ async function getLoginAuthStateFromContent(options = {}) {
|
||||
|
||||
async function getStep5SubmitStateFromContent(options = {}) {
|
||||
const result = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
{
|
||||
type: 'GET_STEP5_SUBMIT_STATE',
|
||||
source: 'background',
|
||||
@@ -14709,7 +14727,7 @@ async function getStep5SubmitStateFromContent(options = {}) {
|
||||
|
||||
async function recoverStep5SubmitRetryPageOnTab(options = {}) {
|
||||
const result = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
{
|
||||
type: 'RECOVER_STEP5_SUBMIT_RETRY_PAGE',
|
||||
source: 'background',
|
||||
@@ -14849,7 +14867,7 @@ async function ensureStep8VerificationPageReady(options = {}) {
|
||||
const recoverTimeoutMs = 15000;
|
||||
if (typeof sendToContentScriptResilient === 'function') {
|
||||
recoverResult = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
recoverMessage,
|
||||
{
|
||||
timeoutMs: recoverTimeoutMs,
|
||||
@@ -14861,7 +14879,7 @@ async function ensureStep8VerificationPageReady(options = {}) {
|
||||
}
|
||||
);
|
||||
} else if (typeof sendToContentScript === 'function') {
|
||||
recoverResult = await sendToContentScript('signup-page', recoverMessage, {
|
||||
recoverResult = await sendToContentScript('openai-auth', recoverMessage, {
|
||||
responseTimeoutMs: recoverTimeoutMs,
|
||||
});
|
||||
}
|
||||
@@ -15098,9 +15116,9 @@ async function shouldDeferStep9CallbackTimeout(details = {}) {
|
||||
|
||||
async function ensureStep8SignupPageReady(tabId, options = {}) {
|
||||
const visibleStep = Math.floor(Number(options.visibleStep || options.logStep || options.step) || 0);
|
||||
await ensureContentScriptReadyOnTab('signup-page', tabId, {
|
||||
inject: SIGNUP_PAGE_INJECT_FILES,
|
||||
injectSource: 'signup-page',
|
||||
await ensureContentScriptReadyOnTab('openai-auth', tabId, {
|
||||
inject: OPENAI_AUTH_INJECT_FILES,
|
||||
injectSource: 'openai-auth',
|
||||
timeoutMs: options.timeoutMs ?? 15000,
|
||||
retryDelayMs: options.retryDelayMs ?? 600,
|
||||
logMessage: options.logMessage || '',
|
||||
@@ -15142,7 +15160,7 @@ async function readAuthTabSnapshot(tabId) {
|
||||
|
||||
async function getStep8PageState(tabId, responseTimeoutMs = 1500, visibleStep = 9) {
|
||||
try {
|
||||
const result = await sendTabMessageWithTimeout(tabId, 'signup-page', {
|
||||
const result = await sendTabMessageWithTimeout(tabId, 'openai-auth', {
|
||||
type: 'STEP8_GET_STATE',
|
||||
source: 'background',
|
||||
payload: { visibleStep },
|
||||
@@ -15219,7 +15237,7 @@ async function prepareStep8DebuggerClick(tabId, options = {}) {
|
||||
logStepKey: 'confirm-oauth',
|
||||
logMessage: '认证页内容脚本已失联,正在恢复后继续定位按钮...',
|
||||
});
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'STEP8_FIND_AND_CLICK',
|
||||
source: 'background',
|
||||
payload: { visibleStep, nodeId: 'confirm-oauth' },
|
||||
@@ -15249,7 +15267,7 @@ async function triggerStep8ContentStrategy(tabId, strategy, options = {}) {
|
||||
logStepKey: 'confirm-oauth',
|
||||
logMessage: '认证页内容脚本已失联,正在恢复后继续点击“继续”按钮...',
|
||||
});
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'STEP8_TRIGGER_CONTINUE',
|
||||
source: 'background',
|
||||
payload: {
|
||||
@@ -15287,7 +15305,7 @@ async function recoverAuthRetryPageOnTab(tabId, payload = {}, options = {}) {
|
||||
logStepKey: 'confirm-oauth',
|
||||
logMessage: options.readyLogMessage || '认证页内容脚本已失联,正在恢复后继续处理重试页...',
|
||||
});
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'RECOVER_AUTH_RETRY_PAGE',
|
||||
source: 'background',
|
||||
payload: { nodeId: 'confirm-oauth', ...(payload || {}) },
|
||||
|
||||
@@ -106,8 +106,7 @@
|
||||
return {
|
||||
activeFlowId: state.activeFlowId,
|
||||
flowId: state.flowId || state.activeFlowId,
|
||||
panelMode: state.panelMode,
|
||||
kiroTargetId: state.kiroTargetId,
|
||||
targetId: state.targetId,
|
||||
vpsUrl: state.vpsUrl,
|
||||
vpsPassword: state.vpsPassword,
|
||||
customPassword: state.customPassword,
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
'openai-auth': '认证页',
|
||||
'gmail-mail': 'Gmail 邮箱',
|
||||
'sidepanel': '侧边栏',
|
||||
'signup-page': '认证页',
|
||||
'vps-panel': 'CPA 面板',
|
||||
'sub2api-panel': 'SUB2API 后台',
|
||||
'codex2api-panel': 'Codex2API 后台',
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
}
|
||||
return capabilityRegistry.validateAutoRunStart({
|
||||
activeFlowId: options?.activeFlowId ?? validationState?.activeFlowId,
|
||||
panelMode: options?.panelMode ?? validationState?.panelMode,
|
||||
targetId: options?.targetId ?? validationState?.targetId,
|
||||
signupMethod: options?.signupMethod ?? validationState?.signupMethod,
|
||||
state: validationState,
|
||||
});
|
||||
@@ -113,7 +113,7 @@
|
||||
return capabilityRegistry.validateModeSwitch({
|
||||
activeFlowId: options?.activeFlowId ?? validationState?.activeFlowId,
|
||||
changedKeys: options?.changedKeys,
|
||||
panelMode: options?.panelMode ?? validationState?.panelMode,
|
||||
targetId: options?.targetId ?? validationState?.targetId,
|
||||
signupMethod: options?.signupMethod ?? validationState?.signupMethod,
|
||||
state: validationState,
|
||||
});
|
||||
@@ -217,10 +217,6 @@
|
||||
return String(targetId || fallbackSourceId).trim().toLowerCase() || fallbackSourceId;
|
||||
}
|
||||
|
||||
function mapAutoRunTargetIdToPanelMode(targetId = '', fallback = 'cpa') {
|
||||
return String(targetId || fallback || 'cpa').trim().toLowerCase() || 'cpa';
|
||||
}
|
||||
|
||||
function buildAutoRunFlowStateUpdates(payload = {}) {
|
||||
const hasActiveFlowId = Object.prototype.hasOwnProperty.call(payload, 'activeFlowId');
|
||||
const hasTargetId = Object.prototype.hasOwnProperty.call(payload, 'targetId');
|
||||
@@ -233,11 +229,11 @@
|
||||
flowId: activeFlowId,
|
||||
};
|
||||
if (hasTargetId) {
|
||||
if (activeFlowId === 'kiro') {
|
||||
updates.kiroTargetId = normalizeMessageTargetId('kiro', payload.targetId, 'kiro-rs');
|
||||
} else {
|
||||
updates.panelMode = mapAutoRunTargetIdToPanelMode(payload.targetId, 'cpa');
|
||||
}
|
||||
updates.targetId = normalizeMessageTargetId(
|
||||
activeFlowId,
|
||||
payload.targetId,
|
||||
activeFlowId === 'kiro' ? 'kiro-rs' : 'cpa'
|
||||
);
|
||||
}
|
||||
return updates;
|
||||
}
|
||||
@@ -297,10 +293,10 @@
|
||||
}
|
||||
|
||||
const signupTabId = typeof getTabId === 'function'
|
||||
? await getTabId('signup-page')
|
||||
? await getTabId('openai-auth')
|
||||
: null;
|
||||
const signupTabAlive = signupTabId && typeof isTabAlive === 'function'
|
||||
? await isTabAlive('signup-page')
|
||||
? await isTabAlive('openai-auth')
|
||||
: Boolean(signupTabId);
|
||||
|
||||
if (!signupTabId || !signupTabAlive) {
|
||||
@@ -1309,7 +1305,7 @@
|
||||
const state = await getState();
|
||||
const autoRunStartValidation = validateAutoRunStart(state, {
|
||||
activeFlowId: autoRunFlowStateUpdates.activeFlowId ?? state?.activeFlowId,
|
||||
panelMode: autoRunFlowStateUpdates.panelMode ?? state?.panelMode,
|
||||
targetId: autoRunFlowStateUpdates.targetId ?? state?.targetId,
|
||||
state,
|
||||
});
|
||||
if (autoRunStartValidation?.ok === false) {
|
||||
@@ -1352,7 +1348,7 @@
|
||||
const state = await getState();
|
||||
const autoRunStartValidation = validateAutoRunStart(state, {
|
||||
activeFlowId: autoRunFlowStateUpdates.activeFlowId ?? state?.activeFlowId,
|
||||
panelMode: autoRunFlowStateUpdates.panelMode ?? state?.panelMode,
|
||||
targetId: autoRunFlowStateUpdates.targetId ?? state?.targetId,
|
||||
state,
|
||||
});
|
||||
if (autoRunStartValidation?.ok === false) {
|
||||
@@ -1451,7 +1447,7 @@
|
||||
Object.prototype.hasOwnProperty.call(updates, 'phoneVerificationEnabled')
|
||||
|| Object.prototype.hasOwnProperty.call(updates, 'plusModeEnabled')
|
||||
|| Object.prototype.hasOwnProperty.call(updates, 'signupMethod')
|
||||
|| Object.prototype.hasOwnProperty.call(updates, 'panelMode')
|
||||
|| Object.prototype.hasOwnProperty.call(updates, 'targetId')
|
||||
|| Object.prototype.hasOwnProperty.call(updates, 'activeFlowId')
|
||||
|| Object.prototype.hasOwnProperty.call(updates, 'accountContributionEnabled')
|
||||
) {
|
||||
@@ -1600,10 +1596,8 @@
|
||||
);
|
||||
const selectedPlusAccountAccessStrategy = getPlusAccountAccessStrategyLabel(
|
||||
stateUpdates.plusAccountAccessStrategy ?? currentState?.plusAccountAccessStrategy ?? 'oauth',
|
||||
stateUpdates.panelMode
|
||||
?? currentState?.panelMode
|
||||
?? stateUpdates.openaiIntegrationTargetId
|
||||
?? currentState?.openaiIntegrationTargetId
|
||||
stateUpdates.targetId
|
||||
?? currentState?.targetId
|
||||
?? 'cpa'
|
||||
);
|
||||
await addLog(
|
||||
@@ -1620,10 +1614,8 @@
|
||||
} else if (plusAccountAccessStrategyChanged && nextPlusModeEnabled) {
|
||||
const selectedPlusAccountAccessStrategy = getPlusAccountAccessStrategyLabel(
|
||||
stateUpdates.plusAccountAccessStrategy ?? currentState?.plusAccountAccessStrategy ?? 'oauth',
|
||||
stateUpdates.panelMode
|
||||
?? currentState?.panelMode
|
||||
?? stateUpdates.openaiIntegrationTargetId
|
||||
?? currentState?.openaiIntegrationTargetId
|
||||
stateUpdates.targetId
|
||||
?? currentState?.targetId
|
||||
?? 'cpa'
|
||||
);
|
||||
await addLog(`Plus 账号接入策略已切换为 ${selectedPlusAccountAccessStrategy},已更新对应的 Plus 尾链。`, 'info');
|
||||
@@ -1661,7 +1653,7 @@
|
||||
);
|
||||
const targetId = normalizeMessageTargetId(
|
||||
activeFlowId,
|
||||
message.payload?.targetId || currentState?.kiroTargetId || 'kiro-rs',
|
||||
message.payload?.targetId || currentState?.targetId || 'kiro-rs',
|
||||
'kiro-rs'
|
||||
);
|
||||
const nestedTargetConfig = currentState?.settingsState?.flows?.kiro?.targets?.[targetId]
|
||||
|
||||
@@ -42,10 +42,10 @@
|
||||
}
|
||||
|
||||
function getPanelMode(state = {}) {
|
||||
if (state.panelMode === 'sub2api') {
|
||||
if (state.targetId === 'sub2api') {
|
||||
return 'sub2api';
|
||||
}
|
||||
if (state.panelMode === 'codex2api') {
|
||||
if (state.targetId === 'codex2api') {
|
||||
return 'codex2api';
|
||||
}
|
||||
return 'cpa';
|
||||
@@ -128,7 +128,6 @@
|
||||
|
||||
switch (source) {
|
||||
case 'openai-auth':
|
||||
case 'signup-page':
|
||||
return isSignupPageHost(candidate.hostname) || isSignupEntryHost(candidate.hostname);
|
||||
case 'duck-mail':
|
||||
return candidate.hostname === 'duckduckgo.com' && candidate.pathname.startsWith('/email/');
|
||||
|
||||
@@ -4585,7 +4585,7 @@
|
||||
visibleStep,
|
||||
logStepKey: 'phone-verification',
|
||||
});
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'STEP8_GET_STATE',
|
||||
source: 'background',
|
||||
payload: { visibleStep },
|
||||
@@ -4676,7 +4676,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(30000, { step: visibleStep, actionLabel: '提交添加手机号' })
|
||||
: 30000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'SUBMIT_PHONE_NUMBER',
|
||||
source: 'background',
|
||||
payload: {
|
||||
@@ -4723,7 +4723,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(45000, { step: visibleStep, actionLabel: '提交手机验证码' })
|
||||
: 45000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'SUBMIT_PHONE_VERIFICATION_CODE',
|
||||
source: 'background',
|
||||
payload: {
|
||||
@@ -4756,7 +4756,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(65000, { step: visibleStep, actionLabel: 'resend phone verification code' })
|
||||
: 65000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'RESEND_PHONE_VERIFICATION_CODE',
|
||||
source: 'background',
|
||||
payload: options || {},
|
||||
@@ -4780,7 +4780,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(45000, { step: visibleStep, actionLabel: '提交注册手机验证码' })
|
||||
: 45000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'SUBMIT_PHONE_VERIFICATION_CODE',
|
||||
step: visibleStep,
|
||||
source: 'background',
|
||||
@@ -4809,7 +4809,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(65000, { step: visibleStep, actionLabel: '重新发送注册手机验证码' })
|
||||
: 65000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'RESEND_VERIFICATION_CODE',
|
||||
step: visibleStep,
|
||||
source: 'background',
|
||||
@@ -4834,7 +4834,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(30000, { step: visibleStep, actionLabel: 'return to add-phone page' })
|
||||
: 30000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'RETURN_TO_ADD_PHONE',
|
||||
source: 'background',
|
||||
payload: {},
|
||||
@@ -4863,7 +4863,7 @@
|
||||
}
|
||||
const visibleStep = normalizeLogStep(activePhoneVerificationLogStep) || 9;
|
||||
try {
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'CHECK_PHONE_RESEND_ERROR',
|
||||
source: 'background',
|
||||
payload: { visibleStep },
|
||||
@@ -6135,7 +6135,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(45000, { step: visibleStep, actionLabel: '提交登录手机验证码' })
|
||||
: 45000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'SUBMIT_PHONE_VERIFICATION_CODE',
|
||||
step: visibleStep,
|
||||
source: 'background',
|
||||
@@ -6164,7 +6164,7 @@
|
||||
const timeoutMs = typeof getOAuthFlowStepTimeoutMs === 'function'
|
||||
? await getOAuthFlowStepTimeoutMs(65000, { step: visibleStep, actionLabel: '重新发送登录手机验证码' })
|
||||
: 65000;
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'RESEND_VERIFICATION_CODE',
|
||||
step: visibleStep,
|
||||
source: 'background',
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
setEmailState,
|
||||
setState,
|
||||
SIGNUP_ENTRY_URL,
|
||||
SIGNUP_PAGE_INJECT_FILES,
|
||||
OPENAI_AUTH_INJECT_FILES,
|
||||
waitForTabStableComplete = null,
|
||||
waitForTabUrlMatch,
|
||||
} = deps;
|
||||
@@ -57,16 +57,16 @@
|
||||
}
|
||||
|
||||
async function openSignupEntryTab(step = 1) {
|
||||
const tabId = await reuseOrCreateTab('signup-page', SIGNUP_ENTRY_URL, {
|
||||
inject: SIGNUP_PAGE_INJECT_FILES,
|
||||
injectSource: 'signup-page',
|
||||
const tabId = await reuseOrCreateTab('openai-auth', SIGNUP_ENTRY_URL, {
|
||||
inject: OPENAI_AUTH_INJECT_FILES,
|
||||
injectSource: 'openai-auth',
|
||||
});
|
||||
|
||||
await waitForSignupEntryTabToSettle(tabId, step);
|
||||
|
||||
await ensureContentScriptReadyOnTab('signup-page', tabId, {
|
||||
inject: SIGNUP_PAGE_INJECT_FILES,
|
||||
injectSource: 'signup-page',
|
||||
await ensureContentScriptReadyOnTab('openai-auth', tabId, {
|
||||
inject: OPENAI_AUTH_INJECT_FILES,
|
||||
injectSource: 'openai-auth',
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: `步骤 ${step}:ChatGPT 官网仍在加载,正在重试连接内容脚本...`,
|
||||
@@ -77,7 +77,7 @@
|
||||
|
||||
async function ensureSignupEntryPageReady(step = 1) {
|
||||
const tabId = await openSignupEntryTab(step);
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'ENSURE_SIGNUP_ENTRY_READY',
|
||||
step,
|
||||
source: 'background',
|
||||
@@ -186,9 +186,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
await ensureContentScriptReadyOnTab('signup-page', tabId, {
|
||||
inject: SIGNUP_PAGE_INJECT_FILES,
|
||||
injectSource: 'signup-page',
|
||||
await ensureContentScriptReadyOnTab('openai-auth', tabId, {
|
||||
inject: OPENAI_AUTH_INJECT_FILES,
|
||||
injectSource: 'openai-auth',
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: landingState === 'password_page'
|
||||
@@ -204,7 +204,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'ENSURE_SIGNUP_PASSWORD_PAGE_READY',
|
||||
step,
|
||||
source: 'background',
|
||||
@@ -244,9 +244,9 @@
|
||||
throw new Error(`认证页面标签页已关闭,无法完成步骤 ${step} 的提交后确认。`);
|
||||
}
|
||||
|
||||
await ensureContentScriptReadyOnTab('signup-page', tabId, {
|
||||
inject: SIGNUP_PAGE_INJECT_FILES,
|
||||
injectSource: 'signup-page',
|
||||
await ensureContentScriptReadyOnTab('openai-auth', tabId, {
|
||||
inject: OPENAI_AUTH_INJECT_FILES,
|
||||
injectSource: 'openai-auth',
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: `步骤 ${step}:认证页仍在切换,正在等待页面恢复后继续确认提交流程...`,
|
||||
@@ -254,7 +254,7 @@
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await sendToContentScriptResilient('signup-page', {
|
||||
result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'PREPARE_SIGNUP_VERIFICATION',
|
||||
step,
|
||||
source: 'background',
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
const requestTimeoutMs = Math.max(1200, Math.min(5000, timeoutMs));
|
||||
const result = typeof sendToContentScriptResilient === 'function'
|
||||
? await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
request,
|
||||
{
|
||||
timeoutMs: requestTimeoutMs,
|
||||
@@ -251,7 +251,7 @@
|
||||
logMessage: `步骤 ${step}:验证码提交后页面正在切换,等待页面恢复并确认授权状态...`,
|
||||
}
|
||||
)
|
||||
: await sendToContentScript('signup-page', request, {
|
||||
: await sendToContentScript('openai-auth', request, {
|
||||
responseTimeoutMs: requestTimeoutMs,
|
||||
});
|
||||
|
||||
@@ -516,7 +516,7 @@
|
||||
|
||||
async function requestVerificationCodeResend(step, options = {}) {
|
||||
throwIfStopped();
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
const signupTabId = await getTabId('openai-auth');
|
||||
if (!signupTabId) {
|
||||
throw new Error('认证页面标签页已关闭,无法重新请求验证码。');
|
||||
}
|
||||
@@ -525,7 +525,7 @@
|
||||
await chrome.tabs.update(signupTabId, { active: true });
|
||||
throwIfStopped();
|
||||
|
||||
const result = await sendToContentScript('signup-page', {
|
||||
const result = await sendToContentScript('openai-auth', {
|
||||
type: 'RESEND_VERIFICATION_CODE',
|
||||
step,
|
||||
source: 'background',
|
||||
@@ -1111,7 +1111,7 @@
|
||||
async function submitVerificationCode(step, code, options = {}) {
|
||||
const completionStep = getCompletionStep(step, options);
|
||||
const authLoginStep = completionStep >= 11 ? 10 : 7;
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
const signupTabId = await getTabId('openai-auth');
|
||||
if (!signupTabId) {
|
||||
throw new Error('认证页面标签页已关闭,无法填写验证码。');
|
||||
}
|
||||
@@ -1143,7 +1143,7 @@
|
||||
const shouldAvoidReplaySubmit = step === 8;
|
||||
if (typeof sendToContentScriptResilient === 'function' && !shouldAvoidReplaySubmit) {
|
||||
try {
|
||||
result = await sendToContentScriptResilient('signup-page', message, {
|
||||
result = await sendToContentScriptResilient('openai-auth', message, {
|
||||
timeoutMs: Math.max(baseResponseTimeoutMs + 15000, 30000),
|
||||
retryDelayMs: 700,
|
||||
responseTimeoutMs: baseResponseTimeoutMs,
|
||||
@@ -1206,7 +1206,7 @@
|
||||
}
|
||||
} else if (shouldAvoidReplaySubmit) {
|
||||
try {
|
||||
result = await sendToContentScript('signup-page', message, {
|
||||
result = await sendToContentScript('openai-auth', message, {
|
||||
responseTimeoutMs: baseResponseTimeoutMs,
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -1255,7 +1255,7 @@
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
result = await sendToContentScript('signup-page', message, {
|
||||
result = await sendToContentScript('openai-auth', message, {
|
||||
responseTimeoutMs: baseResponseTimeoutMs,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||
const PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION = 'cpa_codex_session';
|
||||
const VALID_OPENAI_TARGET_IDS = Array.isArray(flowRegistryApi.OPENAI_TARGET_IDS)
|
||||
? flowRegistryApi.OPENAI_TARGET_IDS.slice()
|
||||
: ['cpa', 'sub2api', 'codex2api'];
|
||||
const VALID_OPENAI_TARGET_IDS = typeof flowRegistryApi.getTargetDefinitions === 'function'
|
||||
? Object.keys(flowRegistryApi.getTargetDefinitions('openai') || {})
|
||||
: (Array.isArray(flowRegistryApi.OPENAI_TARGET_IDS)
|
||||
? flowRegistryApi.OPENAI_TARGET_IDS.slice()
|
||||
: ['cpa', 'sub2api', 'codex2api']);
|
||||
const REGISTERED_FLOW_IDS = Array.isArray(flowRegistryApi.getRegisteredFlowIds?.())
|
||||
? flowRegistryApi.getRegisteredFlowIds().map((flowId) => String(flowId || '').trim().toLowerCase()).filter(Boolean)
|
||||
: [DEFAULT_FLOW_ID];
|
||||
@@ -63,38 +65,18 @@
|
||||
const MODE_SWITCH_RELEVANT_KEYS = Object.freeze([
|
||||
'activeFlowId',
|
||||
'accountContributionEnabled',
|
||||
'panelMode',
|
||||
'phoneVerificationEnabled',
|
||||
'plusModeEnabled',
|
||||
'signupMethod',
|
||||
'plusAccountAccessStrategy',
|
||||
'openaiIntegrationTargetId',
|
||||
'kiroTargetId',
|
||||
'targetId',
|
||||
]);
|
||||
|
||||
const OPENAI_TARGET_CAPABILITIES = Object.freeze({
|
||||
cpa: Object.freeze({
|
||||
supportsPhoneSignup: true,
|
||||
requiresPhoneSignupWarning: true,
|
||||
supportedPlusAccountAccessStrategies: Object.freeze([
|
||||
PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH,
|
||||
PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION,
|
||||
]),
|
||||
}),
|
||||
sub2api: Object.freeze({
|
||||
supportsPhoneSignup: true,
|
||||
requiresPhoneSignupWarning: false,
|
||||
supportedPlusAccountAccessStrategies: Object.freeze([
|
||||
PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH,
|
||||
PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION,
|
||||
]),
|
||||
}),
|
||||
codex2api: Object.freeze({
|
||||
supportsPhoneSignup: true,
|
||||
requiresPhoneSignupWarning: false,
|
||||
supportedPlusAccountAccessStrategies: Object.freeze([PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH]),
|
||||
}),
|
||||
});
|
||||
const OPENAI_TARGET_CAPABILITIES = Object.freeze(
|
||||
typeof flowRegistryApi.getTargetCapabilityDefinitions === 'function'
|
||||
? (flowRegistryApi.getTargetCapabilityDefinitions('openai') || {})
|
||||
: {}
|
||||
);
|
||||
|
||||
function normalizeFlowId(value = '', fallback = DEFAULT_FLOW_ID) {
|
||||
if (typeof flowRegistryApi.normalizeFlowId === 'function') {
|
||||
@@ -254,33 +236,18 @@
|
||||
}
|
||||
|
||||
function normalizeRequestedTargetId(activeFlowId, state = {}, options = {}) {
|
||||
if (activeFlowId === 'openai') {
|
||||
return normalizeOpenAiTargetId(
|
||||
options?.targetId
|
||||
?? options?.integrationTargetId
|
||||
?? options?.panelMode
|
||||
?? state?.openaiIntegrationTargetId
|
||||
?? state?.panelMode,
|
||||
DEFAULT_OPENAI_TARGET_ID
|
||||
);
|
||||
}
|
||||
|
||||
const rawTargetId = activeFlowId === 'kiro'
|
||||
? (
|
||||
options?.targetId
|
||||
?? state?.kiroTargetId
|
||||
?? flowRegistryApi.getDefaultTargetId?.(activeFlowId)
|
||||
?? ''
|
||||
)
|
||||
: (
|
||||
options?.targetId
|
||||
?? state?.targetId
|
||||
?? state?.openaiIntegrationTargetId
|
||||
?? state?.panelMode
|
||||
?? state?.kiroTargetId
|
||||
?? flowRegistryApi.getDefaultTargetId?.(activeFlowId)
|
||||
?? ''
|
||||
);
|
||||
const schemaTargetId = settingsSchema?.getSelectedTargetId
|
||||
? settingsSchema.getSelectedTargetId({
|
||||
...state,
|
||||
activeFlowId,
|
||||
}, activeFlowId)
|
||||
: '';
|
||||
const rawTargetId = options?.targetId
|
||||
?? options?.selectedTargetId
|
||||
?? state?.targetId
|
||||
?? schemaTargetId
|
||||
?? flowRegistryApi.getDefaultTargetId?.(activeFlowId)
|
||||
?? '';
|
||||
|
||||
if (
|
||||
isRegisteredFlowId(activeFlowId)
|
||||
@@ -312,32 +279,9 @@
|
||||
}
|
||||
|
||||
function resolveEffectiveTargetId(activeFlowId, state = {}, requestedTargetId = DEFAULT_OPENAI_TARGET_ID) {
|
||||
if (!isRegisteredFlowId(activeFlowId)) {
|
||||
return normalizeRequestedTargetId(activeFlowId, state, {
|
||||
targetId: requestedTargetId,
|
||||
});
|
||||
}
|
||||
if (settingsSchema?.getSelectedTargetId) {
|
||||
const targetId = settingsSchema.getSelectedTargetId({
|
||||
...state,
|
||||
activeFlowId,
|
||||
}, activeFlowId);
|
||||
if (targetId) {
|
||||
return targetId;
|
||||
}
|
||||
}
|
||||
if (typeof flowRegistryApi.normalizeTargetId === 'function') {
|
||||
return flowRegistryApi.normalizeTargetId(
|
||||
activeFlowId,
|
||||
activeFlowId === 'openai'
|
||||
? (state?.openaiIntegrationTargetId || state?.panelMode || requestedTargetId)
|
||||
: (state?.kiroTargetId || requestedTargetId),
|
||||
flowRegistryApi.getDefaultTargetId?.(activeFlowId)
|
||||
);
|
||||
}
|
||||
return activeFlowId === 'openai'
|
||||
? normalizeOpenAiTargetId(requestedTargetId)
|
||||
: String(requestedTargetId || '').trim().toLowerCase();
|
||||
return normalizeRequestedTargetId(activeFlowId, state, {
|
||||
targetId: requestedTargetId,
|
||||
});
|
||||
}
|
||||
|
||||
function resolveSidepanelCapabilities(options = {}) {
|
||||
@@ -444,13 +388,11 @@
|
||||
canUsePhoneSignup: canSelectPhoneSignup,
|
||||
canUseSelectedTarget: targetSupported,
|
||||
effectivePlusAccountAccessStrategy,
|
||||
effectivePanelMode: effectiveTargetId,
|
||||
effectiveSignupMethod,
|
||||
effectiveSignupMethods,
|
||||
effectiveTargetId,
|
||||
flowCapabilities: flowState,
|
||||
panelCapabilities: targetState,
|
||||
panelMode: effectiveTargetId,
|
||||
requestedPlusAccountAccessStrategy,
|
||||
requestedSignupMethod,
|
||||
requestedTargetId,
|
||||
@@ -460,8 +402,6 @@
|
||||
&& Boolean(targetState.requiresPhoneSignupWarning),
|
||||
stepDefinitionOptions: {
|
||||
activeFlowId,
|
||||
integrationTargetId: effectiveTargetId,
|
||||
panelMode: effectiveTargetId,
|
||||
targetId: effectiveTargetId,
|
||||
plusAccountAccessStrategy: effectivePlusAccountAccessStrategy,
|
||||
plusModeEnabled: runtimeLocks.plusModeEnabled,
|
||||
@@ -576,14 +516,12 @@
|
||||
const shouldReconcileSignupMethod = MODE_SWITCH_RELEVANT_KEYS.some((key) => changedKeySet.has(key));
|
||||
|
||||
if (
|
||||
(changedKeySet.has('panelMode') || changedKeySet.has('openaiIntegrationTargetId') || changedKeySet.has('kiroTargetId'))
|
||||
changedKeySet.has('targetId')
|
||||
&& Array.isArray(capabilityState.supportedTargetIds)
|
||||
&& capabilityState.supportedTargetIds.length > 0
|
||||
&& capabilityState.canUseSelectedTarget === false
|
||||
) {
|
||||
normalizedUpdates.panelMode = capabilityState.effectiveTargetId;
|
||||
normalizedUpdates.openaiIntegrationTargetId = capabilityState.effectiveTargetId;
|
||||
normalizedUpdates.kiroTargetId = capabilityState.effectiveTargetId;
|
||||
normalizedUpdates.targetId = capabilityState.effectiveTargetId;
|
||||
errors.push({
|
||||
code: 'panel_mode_unsupported',
|
||||
message: `当前 flow 不支持 ${getTargetLabel(capabilityState.activeFlowId, capabilityState.requestedTargetId)} 来源。`,
|
||||
@@ -0,0 +1,300 @@
|
||||
(function attachMultiPageFlowRegistry(root, factory) {
|
||||
root.MultiPageFlowRegistry = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createFlowRegistryModule() {
|
||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||
const flowsIndexApi = rootScope.MultiPageFlowsIndex || {};
|
||||
|
||||
const DEFAULT_FLOW_ID = 'openai';
|
||||
const SHARED_SERVICE_IDS = Object.freeze(['account', 'email', 'proxy']);
|
||||
|
||||
const DEFAULT_FLOW_CAPABILITIES = Object.freeze({
|
||||
supportsEmailSignup: true,
|
||||
supportsPhoneSignup: false,
|
||||
supportsPhoneVerificationSettings: false,
|
||||
supportsPlusMode: false,
|
||||
supportsContributionMode: false,
|
||||
supportsAccountContribution: false,
|
||||
supportsOpenAiOAuthContribution: false,
|
||||
contributionAdapterIds: [],
|
||||
supportedTargetIds: [],
|
||||
supportsLuckmail: false,
|
||||
supportsOauthTimeoutBudget: false,
|
||||
canSwitchFlow: true,
|
||||
stepDefinitionMode: 'default',
|
||||
targetSelectorLabel: '\u6765\u6e90',
|
||||
});
|
||||
|
||||
function freezeDeep(value) {
|
||||
if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
|
||||
return value;
|
||||
}
|
||||
Object.getOwnPropertyNames(value).forEach((key) => {
|
||||
freezeDeep(value[key]);
|
||||
});
|
||||
return Object.freeze(value);
|
||||
}
|
||||
|
||||
const SHARED_SETTINGS_GROUP_DEFINITIONS = freezeDeep({
|
||||
'service-account': {
|
||||
id: 'service-account',
|
||||
label: '\u8d26\u6237',
|
||||
rowIds: ['row-custom-password'],
|
||||
},
|
||||
'service-email': {
|
||||
id: 'service-email',
|
||||
label: '\u90ae\u7bb1\u670d\u52a1',
|
||||
},
|
||||
'service-proxy': {
|
||||
id: 'service-proxy',
|
||||
label: 'IP \u4ee3\u7406',
|
||||
sectionIds: ['ip-proxy-section'],
|
||||
},
|
||||
});
|
||||
|
||||
function buildFlowDefinitions() {
|
||||
if (typeof flowsIndexApi.getFlowDefinitions !== 'function') {
|
||||
return {};
|
||||
}
|
||||
return flowsIndexApi.getFlowDefinitions() || {};
|
||||
}
|
||||
|
||||
const FLOW_DEFINITIONS = freezeDeep(buildFlowDefinitions());
|
||||
const REGISTERED_FLOW_IDS = Object.freeze(Object.keys(FLOW_DEFINITIONS));
|
||||
|
||||
function buildSettingsGroupDefinitions() {
|
||||
const next = {
|
||||
...SHARED_SETTINGS_GROUP_DEFINITIONS,
|
||||
};
|
||||
Object.values(FLOW_DEFINITIONS).forEach((flowDefinition) => {
|
||||
Object.assign(next, flowDefinition?.settingsGroups || {});
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
const SETTINGS_GROUP_DEFINITIONS = freezeDeep(buildSettingsGroupDefinitions());
|
||||
|
||||
function normalizeFlowId(value = '', fallback = DEFAULT_FLOW_ID) {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized && Object.prototype.hasOwnProperty.call(FLOW_DEFINITIONS, normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
const fallbackValue = String(fallback || '').trim().toLowerCase();
|
||||
if (fallbackValue && Object.prototype.hasOwnProperty.call(FLOW_DEFINITIONS, fallbackValue)) {
|
||||
return fallbackValue;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(FLOW_DEFINITIONS, DEFAULT_FLOW_ID)) {
|
||||
return DEFAULT_FLOW_ID;
|
||||
}
|
||||
return REGISTERED_FLOW_IDS[0] || DEFAULT_FLOW_ID;
|
||||
}
|
||||
|
||||
function getRegisteredFlowIds() {
|
||||
return REGISTERED_FLOW_IDS.slice();
|
||||
}
|
||||
|
||||
function getFlowDefinition(flowId) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
return FLOW_DEFINITIONS[normalizedFlowId] || null;
|
||||
}
|
||||
|
||||
function getFlowLabel(flowId) {
|
||||
return getFlowDefinition(flowId)?.label || normalizeFlowId(flowId);
|
||||
}
|
||||
|
||||
function getDefaultTargetId(flowId) {
|
||||
const flowDefinition = getFlowDefinition(flowId);
|
||||
return String(flowDefinition?.defaultTargetId || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function normalizeTargetId(flowId, targetId = '', fallback = undefined) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const targetDefinitions = getFlowDefinition(normalizedFlowId)?.targets || {};
|
||||
const targetKeys = Object.keys(targetDefinitions);
|
||||
if (!targetKeys.length) {
|
||||
return String(targetId || fallback || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
const normalizedTargetId = String(targetId || '').trim().toLowerCase();
|
||||
if (normalizedTargetId && Object.prototype.hasOwnProperty.call(targetDefinitions, normalizedTargetId)) {
|
||||
return normalizedTargetId;
|
||||
}
|
||||
|
||||
const fallbackValue = String(fallback || '').trim().toLowerCase();
|
||||
if (fallbackValue && Object.prototype.hasOwnProperty.call(targetDefinitions, fallbackValue)) {
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
const defaultTargetId = getDefaultTargetId(normalizedFlowId);
|
||||
if (defaultTargetId && Object.prototype.hasOwnProperty.call(targetDefinitions, defaultTargetId)) {
|
||||
return defaultTargetId;
|
||||
}
|
||||
|
||||
return targetKeys[0];
|
||||
}
|
||||
|
||||
function normalizeOpenAiTargetId(value = '', fallback = undefined) {
|
||||
return normalizeTargetId('openai', value, fallback);
|
||||
}
|
||||
|
||||
function normalizeKiroTargetId(value = '', fallback = undefined) {
|
||||
return normalizeTargetId('kiro', value, fallback);
|
||||
}
|
||||
|
||||
function getTargetDefinitions(flowId) {
|
||||
return getFlowDefinition(flowId)?.targets || {};
|
||||
}
|
||||
|
||||
function getTargetDefinition(flowId, targetId) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const normalizedTargetId = normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
targetId,
|
||||
getDefaultTargetId(normalizedFlowId)
|
||||
);
|
||||
return getTargetDefinitions(normalizedFlowId)[normalizedTargetId] || null;
|
||||
}
|
||||
|
||||
function getTargetOptions(flowId) {
|
||||
return Object.values(getTargetDefinitions(flowId));
|
||||
}
|
||||
|
||||
function getTargetLabel(flowId, targetId) {
|
||||
return getTargetDefinition(flowId, targetId)?.label
|
||||
|| normalizeTargetId(flowId, targetId);
|
||||
}
|
||||
|
||||
function getPublicationTargetDefinitions(flowId) {
|
||||
return getFlowDefinition(flowId)?.publicationTargets || {};
|
||||
}
|
||||
|
||||
function getPublicationTargetDefinition(flowId, publicationTargetId) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const flowDefinition = getFlowDefinition(normalizedFlowId);
|
||||
const normalizedPublicationTargetId = String(
|
||||
publicationTargetId || flowDefinition?.defaultPublicationTargetId || ''
|
||||
).trim().toLowerCase();
|
||||
return getPublicationTargetDefinitions(normalizedFlowId)[normalizedPublicationTargetId] || null;
|
||||
}
|
||||
|
||||
function getFlowCapabilities(flowId) {
|
||||
return {
|
||||
...DEFAULT_FLOW_CAPABILITIES,
|
||||
...(getFlowDefinition(flowId)?.capabilities || {}),
|
||||
};
|
||||
}
|
||||
|
||||
function getTargetCapabilityDefinitions(flowId) {
|
||||
return getFlowDefinition(flowId)?.targetCapabilities || {};
|
||||
}
|
||||
|
||||
function getTargetCapabilities(flowId, targetId) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const normalizedTargetId = normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
targetId,
|
||||
getDefaultTargetId(normalizedFlowId)
|
||||
);
|
||||
return getTargetCapabilityDefinitions(normalizedFlowId)[normalizedTargetId] || null;
|
||||
}
|
||||
|
||||
function getVisibleGroupIds(flowId, targetId, options = {}) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const flowDefinition = getFlowDefinition(normalizedFlowId);
|
||||
const normalizedTargetId = normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
targetId,
|
||||
getDefaultTargetId(normalizedFlowId)
|
||||
);
|
||||
const targetDefinition = getTargetDefinition(normalizedFlowId, normalizedTargetId);
|
||||
const includeSharedServices = options?.includeSharedServices !== false;
|
||||
const serviceGroups = includeSharedServices
|
||||
? (Array.isArray(flowDefinition?.services)
|
||||
? flowDefinition.services.map((serviceId) => `service-${serviceId}`)
|
||||
: [])
|
||||
: [];
|
||||
return Array.from(new Set([
|
||||
...(Array.isArray(flowDefinition?.baseGroups) ? flowDefinition.baseGroups : []),
|
||||
...(Array.isArray(targetDefinition?.groups) ? targetDefinition.groups : []),
|
||||
...serviceGroups,
|
||||
]));
|
||||
}
|
||||
|
||||
function getSettingsGroupDefinition(groupId) {
|
||||
const normalizedGroupId = String(groupId || '').trim();
|
||||
return SETTINGS_GROUP_DEFINITIONS[normalizedGroupId] || null;
|
||||
}
|
||||
|
||||
function getSettingsGroupDefinitions() {
|
||||
return SETTINGS_GROUP_DEFINITIONS;
|
||||
}
|
||||
|
||||
function getRuntimeSourceDefinitions() {
|
||||
const next = {};
|
||||
Object.values(FLOW_DEFINITIONS).forEach((flowDefinition) => {
|
||||
Object.assign(next, flowDefinition?.runtimeSources || {});
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
function getDriverDefinitions() {
|
||||
const next = {};
|
||||
Object.values(FLOW_DEFINITIONS).forEach((flowDefinition) => {
|
||||
Object.assign(next, flowDefinition?.driverDefinitions || {});
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
function getSourceAliases() {
|
||||
const next = {};
|
||||
Object.values(FLOW_DEFINITIONS).forEach((flowDefinition) => {
|
||||
Object.assign(next, flowDefinition?.sourceAliases || {});
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
const OPENAI_TARGET_IDS = Object.freeze(Object.keys(getTargetDefinitions('openai')));
|
||||
const DEFAULT_OPENAI_TARGET_ID = String(getDefaultTargetId('openai') || OPENAI_TARGET_IDS[0] || 'cpa');
|
||||
const DEFAULT_KIRO_TARGET_ID = String(getDefaultTargetId('kiro') || 'kiro-rs');
|
||||
const DEFAULT_KIRO_PUBLICATION_TARGET_ID = String(
|
||||
getFlowDefinition('kiro')?.defaultPublicationTargetId || DEFAULT_KIRO_TARGET_ID
|
||||
);
|
||||
const DEFAULT_KIRO_RS_URL = String(
|
||||
getFlowDefinition('kiro')?.defaultTargetState?.baseUrl || ''
|
||||
).trim();
|
||||
|
||||
return {
|
||||
DEFAULT_FLOW_CAPABILITIES,
|
||||
DEFAULT_FLOW_ID,
|
||||
DEFAULT_KIRO_PUBLICATION_TARGET_ID,
|
||||
DEFAULT_KIRO_RS_URL,
|
||||
DEFAULT_KIRO_TARGET_ID,
|
||||
DEFAULT_OPENAI_TARGET_ID,
|
||||
FLOW_DEFINITIONS,
|
||||
OPENAI_TARGET_IDS,
|
||||
SETTINGS_GROUP_DEFINITIONS,
|
||||
SHARED_SERVICE_IDS,
|
||||
getDriverDefinitions,
|
||||
getDefaultTargetId,
|
||||
getFlowCapabilities,
|
||||
getFlowDefinition,
|
||||
getFlowLabel,
|
||||
getPublicationTargetDefinition,
|
||||
getPublicationTargetDefinitions,
|
||||
getRegisteredFlowIds,
|
||||
getRuntimeSourceDefinitions,
|
||||
getSettingsGroupDefinition,
|
||||
getSettingsGroupDefinitions,
|
||||
getSourceAliases,
|
||||
getTargetCapabilities,
|
||||
getTargetCapabilityDefinitions,
|
||||
getTargetDefinition,
|
||||
getTargetDefinitions,
|
||||
getTargetLabel,
|
||||
getTargetOptions,
|
||||
getVisibleGroupIds,
|
||||
normalizeFlowId,
|
||||
normalizeKiroTargetId,
|
||||
normalizeOpenAiTargetId,
|
||||
normalizeTargetId,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,257 @@
|
||||
(function attachBackgroundLoggingStatus(root, factory) {
|
||||
root.MultiPageBackgroundLoggingStatus = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundLoggingStatusModule() {
|
||||
function createLoggingStatus(deps = {}) {
|
||||
const {
|
||||
chrome,
|
||||
DEFAULT_STATE,
|
||||
getStepIdByNodeIdForState,
|
||||
getState,
|
||||
isRecoverableStep9AuthFailure,
|
||||
LOG_PREFIX,
|
||||
setState,
|
||||
sourceRegistry = null,
|
||||
STOP_ERROR_MESSAGE,
|
||||
} = deps;
|
||||
|
||||
function getSourceLabel(source) {
|
||||
if (sourceRegistry?.getSourceLabel) {
|
||||
return sourceRegistry.getSourceLabel(source);
|
||||
}
|
||||
const labels = {
|
||||
'openai-auth': '认证页',
|
||||
'gmail-mail': 'Gmail 邮箱',
|
||||
'sidepanel': '侧边栏',
|
||||
'vps-panel': 'CPA 面板',
|
||||
'sub2api-panel': 'SUB2API 后台',
|
||||
'codex2api-panel': 'Codex2API 后台',
|
||||
'qq-mail': 'QQ 邮箱',
|
||||
'mail-163': '163 邮箱',
|
||||
'mail-2925': '2925 邮箱',
|
||||
'inbucket-mail': 'Inbucket 邮箱',
|
||||
'duck-mail': 'Duck 邮箱',
|
||||
'hotmail-api': 'Hotmail(API对接/本地助手)',
|
||||
'luckmail-api': 'LuckMail(API 购邮)',
|
||||
'cloudflare-temp-email': 'Cloudflare Temp Email',
|
||||
'cloudmail': 'Cloud Mail',
|
||||
'plus-checkout': 'Plus Checkout',
|
||||
'paypal-flow': 'PayPal 授权页',
|
||||
'gopay-flow': 'GoPay 授权页',
|
||||
'unknown-source': '未知来源',
|
||||
};
|
||||
return labels[source] || source || '未知来源';
|
||||
}
|
||||
|
||||
function normalizeLogStep(value) {
|
||||
const step = Math.floor(Number(value) || 0);
|
||||
return step > 0 ? step : null;
|
||||
}
|
||||
|
||||
function buildLogEntry(message, level = 'info', options = {}) {
|
||||
const normalizedOptions = options && typeof options === 'object' ? options : {};
|
||||
const step = normalizeLogStep(normalizedOptions.step);
|
||||
const stepKey = String(normalizedOptions.stepKey || '').trim();
|
||||
const nodeId = String(normalizedOptions.nodeId || normalizedOptions.nodeKey || stepKey || '').trim();
|
||||
return {
|
||||
message: String(message || ''),
|
||||
level,
|
||||
timestamp: Date.now(),
|
||||
step,
|
||||
stepKey,
|
||||
nodeId,
|
||||
};
|
||||
}
|
||||
|
||||
async function addLog(message, level = 'info', options = {}) {
|
||||
const state = await getState();
|
||||
const logs = state.logs || [];
|
||||
const entry = buildLogEntry(message, level, options);
|
||||
logs.push(entry);
|
||||
if (logs.length > 500) logs.splice(0, logs.length - 500);
|
||||
await setState({ logs });
|
||||
chrome.runtime.sendMessage({ type: 'LOG_ENTRY', payload: entry }).catch(() => { });
|
||||
}
|
||||
|
||||
async function setNodeStatus(nodeId, status) {
|
||||
const normalizedNodeId = String(nodeId || '').trim();
|
||||
if (!normalizedNodeId) {
|
||||
throw new Error('setNodeStatus 缺少 nodeId。');
|
||||
}
|
||||
const state = await getState();
|
||||
const nodeStatuses = { ...(state.nodeStatuses || {}) };
|
||||
nodeStatuses[normalizedNodeId] = status;
|
||||
await setState({
|
||||
nodeStatuses,
|
||||
currentNodeId: normalizedNodeId,
|
||||
});
|
||||
chrome.runtime.sendMessage({
|
||||
type: 'NODE_STATUS_CHANGED',
|
||||
payload: { nodeId: normalizedNodeId, status },
|
||||
}).catch(() => { });
|
||||
}
|
||||
|
||||
function getErrorMessage(error) {
|
||||
return String(typeof error === 'string' ? error : error?.message || '')
|
||||
.replace(/^GPC_TASK_ENDED::/i, '')
|
||||
.replace(/^AUTO_RUN_STEP_IDLE_RESTART::/i, '');
|
||||
}
|
||||
|
||||
function isVerificationMailPollingError(error) {
|
||||
const message = getErrorMessage(error);
|
||||
return /未在 .*邮箱中找到新的匹配邮件|未在 Hotmail 收件箱中找到新的匹配验证码|邮箱轮询结束,但未获取到验证码|无法获取新的(?:注册|登录)验证码|页面未能重新就绪|页面通信异常|内容脚本\s+\d+(?:\.\d+)?\s*秒内未响应|did not respond in \d+s|405\s+method\s+not\s+allowed|route\s+error.*405|did\s+not\s+provide\s+an?\s+[`'"]?action|post\s+request\s+to\s+["']?\/(?:email|phone)-verification/i.test(message);
|
||||
}
|
||||
|
||||
function isAddPhoneAuthFailure(error) {
|
||||
const message = getErrorMessage(error);
|
||||
if (/\u624b\u673a\u53f7\u8f93\u5165\u6a21\u5f0f|phone\s+entry/i.test(message)) {
|
||||
return false;
|
||||
}
|
||||
return /https:\/\/auth\.openai\.com\/(?:add-phone|phone-verification)(?:[/?#]|$)|\badd-phone\b|phone-verification|\u6dfb\u52a0\u624b\u673a\u53f7|\u624b\u673a\u53f7\u7801|\u624b\u673a\u9a8c\u8bc1\u7801\u9875|\u624b\u673a\u9a8c\u8bc1\u9875|\u8fdb\u5165\u624b\u673a\u53f7\u9875\u9762|\u624b\u673a\u53f7\u9875|\u624b\u673a\u53f7\u9875\u9762|phone\s+number|telephone/i.test(message);
|
||||
}
|
||||
|
||||
function getLoginAuthStateLabel(state) {
|
||||
switch (state) {
|
||||
case 'verification_page':
|
||||
return '登录验证码页';
|
||||
case 'password_page':
|
||||
return '密码页';
|
||||
case 'email_page':
|
||||
return '邮箱输入页';
|
||||
case 'login_timeout_error_page':
|
||||
return '登录超时报错页';
|
||||
case 'oauth_consent_page':
|
||||
return 'OAuth 授权页';
|
||||
case 'add_phone_page':
|
||||
return '手机号页';
|
||||
case 'add_email_page':
|
||||
return '添加邮箱页';
|
||||
case 'phone_verification_page':
|
||||
return '手机验证码页';
|
||||
default:
|
||||
return '未知页面';
|
||||
}
|
||||
}
|
||||
|
||||
function isRestartCurrentAttemptError(error) {
|
||||
const message = String(typeof error === 'string' ? error : error?.message || '');
|
||||
return /当前邮箱已存在,需要重新开始新一轮|SIGNUP_PHONE_PASSWORD_MISMATCH::/i.test(message);
|
||||
}
|
||||
|
||||
function isSignupUserAlreadyExistsFailure(error) {
|
||||
const message = getErrorMessage(error);
|
||||
return /SIGNUP_USER_ALREADY_EXISTS::|user_already_exists/i.test(message);
|
||||
}
|
||||
|
||||
function isKiroProxyFailure(error) {
|
||||
const message = getErrorMessage(error);
|
||||
return /Kiro\s*(?:注册页|桌面授权页).*(?:CloudFront\s*拒绝请求|AWS\s*请求异常)|(?:当前代理\s*IP|出口区域异常).*(?:切换代理|更换代理)|AWS\s*风控.*(?:切换代理|更换代理)/i.test(message);
|
||||
}
|
||||
|
||||
function isStep9RecoverableAuthError(error) {
|
||||
const message = String(typeof error === 'string' ? error : error?.message || '');
|
||||
return /STEP9_OAUTH_RETRY::/i.test(message)
|
||||
|| isRecoverableStep9AuthFailure(message);
|
||||
}
|
||||
|
||||
function isLegacyStep9RecoverableAuthError(error) {
|
||||
const message = String(typeof error === 'string' ? error : error?.message || '');
|
||||
return /STEP9_OAUTH_TIMEOUT::|认证失败:\s*(?:Timeout waiting for OAuth callback|timeout of \d+ms exceeded)/i.test(message);
|
||||
}
|
||||
|
||||
function isStepDoneStatus(status) {
|
||||
return status === 'completed' || status === 'manual_completed' || status === 'skipped';
|
||||
}
|
||||
|
||||
function getFirstUnfinishedStep(statuses = {}) {
|
||||
const nodeStatuses = statuses && typeof statuses === 'object' ? statuses : {};
|
||||
const nodeIds = Object.keys(DEFAULT_STATE.nodeStatuses || {});
|
||||
for (const nodeId of nodeIds) {
|
||||
if (!isStepDoneStatus(nodeStatuses[nodeId] || 'pending')) {
|
||||
return typeof getStepIdByNodeIdForState === 'function'
|
||||
? getStepIdByNodeIdForState(nodeId, {})
|
||||
: null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function hasSavedProgress(statuses = {}) {
|
||||
return Object.values({ ...DEFAULT_STATE.nodeStatuses, ...statuses }).some((status) => status !== 'pending');
|
||||
}
|
||||
|
||||
function getRunningSteps(statuses = {}) {
|
||||
return Object.entries({ ...DEFAULT_STATE.nodeStatuses, ...statuses })
|
||||
.filter(([, status]) => status === 'running')
|
||||
.map(([nodeId]) => (typeof getStepIdByNodeIdForState === 'function' ? getStepIdByNodeIdForState(nodeId, {}) : null))
|
||||
.filter((step) => Number.isInteger(step) && step > 0)
|
||||
.sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
function getFirstUnfinishedNode(statuses = {}) {
|
||||
const nodeIds = Object.keys(DEFAULT_STATE.nodeStatuses || {});
|
||||
for (const nodeId of nodeIds) {
|
||||
if (!isStepDoneStatus(statuses[nodeId] || 'pending')) {
|
||||
return nodeId;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function hasSavedNodeProgress(statuses = {}) {
|
||||
return Object.values({ ...DEFAULT_STATE.nodeStatuses, ...statuses }).some((status) => status !== 'pending');
|
||||
}
|
||||
|
||||
function getRunningNodes(statuses = {}) {
|
||||
return Object.entries({ ...DEFAULT_STATE.nodeStatuses, ...statuses })
|
||||
.filter(([, status]) => status === 'running')
|
||||
.map(([nodeId]) => nodeId);
|
||||
}
|
||||
|
||||
function getAutoRunStatusPayload(phase, payload = {}) {
|
||||
return {
|
||||
autoRunning: phase === 'scheduled'
|
||||
|| phase === 'running'
|
||||
|| phase === 'waiting_step'
|
||||
|| phase === 'waiting_email'
|
||||
|| phase === 'retrying'
|
||||
|| phase === 'waiting_interval',
|
||||
autoRunPhase: phase,
|
||||
autoRunCurrentRun: payload.currentRun ?? 0,
|
||||
autoRunTotalRuns: payload.totalRuns ?? 1,
|
||||
autoRunAttemptRun: payload.attemptRun ?? 0,
|
||||
autoRunSessionId: Math.max(0, Math.floor(Number(payload.sessionId ?? payload.autoRunSessionId) || 0)),
|
||||
scheduledAutoRunAt: Number.isFinite(Number(payload.scheduledAt)) ? Number(payload.scheduledAt) : null,
|
||||
autoRunCountdownAt: Number.isFinite(Number(payload.countdownAt)) ? Number(payload.countdownAt) : null,
|
||||
autoRunCountdownTitle: payload.countdownTitle === undefined ? '' : String(payload.countdownTitle || ''),
|
||||
autoRunCountdownNote: payload.countdownNote === undefined ? '' : String(payload.countdownNote || ''),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
addLog,
|
||||
getAutoRunStatusPayload,
|
||||
getFirstUnfinishedNode,
|
||||
isAddPhoneAuthFailure,
|
||||
getErrorMessage,
|
||||
getFirstUnfinishedStep,
|
||||
getLoginAuthStateLabel,
|
||||
getRunningNodes,
|
||||
getRunningSteps,
|
||||
getSourceLabel,
|
||||
hasSavedNodeProgress,
|
||||
hasSavedProgress,
|
||||
isKiroProxyFailure,
|
||||
isLegacyStep9RecoverableAuthError,
|
||||
isRestartCurrentAttemptError,
|
||||
isSignupUserAlreadyExistsFailure,
|
||||
isStep9RecoverableAuthError,
|
||||
isStepDoneStatus,
|
||||
isVerificationMailPollingError,
|
||||
setNodeStatus,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createLoggingStatus,
|
||||
};
|
||||
});
|
||||
@@ -140,6 +140,24 @@
|
||||
return value;
|
||||
}
|
||||
|
||||
function deepMerge(baseValue, patchValue) {
|
||||
if (Array.isArray(patchValue)) {
|
||||
return patchValue.map((item) => cloneValue(item));
|
||||
}
|
||||
if (!isPlainObject(patchValue)) {
|
||||
return patchValue === undefined ? cloneValue(baseValue) : patchValue;
|
||||
}
|
||||
|
||||
const baseObject = isPlainObject(baseValue) ? baseValue : {};
|
||||
const next = {
|
||||
...cloneValue(baseObject),
|
||||
};
|
||||
Object.entries(patchValue).forEach(([key, value]) => {
|
||||
next[key] = deepMerge(baseObject[key], value);
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
function normalizePlainObject(value) {
|
||||
return isPlainObject(value) ? value : {};
|
||||
}
|
||||
@@ -277,6 +295,7 @@
|
||||
'activeRunId',
|
||||
'currentNodeId',
|
||||
'nodeStatuses',
|
||||
'kiroRuntime',
|
||||
...RUNTIME_TOP_LEVEL_FIELDS,
|
||||
]);
|
||||
|
||||
@@ -358,6 +377,43 @@
|
||||
return next;
|
||||
}
|
||||
|
||||
function buildRuntimeStateSeed(currentRuntimeState = {}, updates = {}) {
|
||||
const normalizedUpdates = normalizePlainObject(updates);
|
||||
let nextRuntimeState = deepMerge(currentRuntimeState, normalizePlainObject(normalizedUpdates.runtimeState));
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'sharedState')) {
|
||||
nextRuntimeState = deepMerge(nextRuntimeState, {
|
||||
sharedState: normalizePlainObject(normalizedUpdates.sharedState),
|
||||
});
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'shared')) {
|
||||
nextRuntimeState = deepMerge(nextRuntimeState, {
|
||||
sharedState: normalizePlainObject(normalizedUpdates.shared),
|
||||
});
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'serviceState')) {
|
||||
nextRuntimeState = deepMerge(nextRuntimeState, {
|
||||
serviceState: normalizePlainObject(normalizedUpdates.serviceState),
|
||||
});
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'services')) {
|
||||
nextRuntimeState = deepMerge(nextRuntimeState, {
|
||||
serviceState: normalizePlainObject(normalizedUpdates.services),
|
||||
});
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'flowState')) {
|
||||
nextRuntimeState = deepMerge(nextRuntimeState, {
|
||||
flowState: normalizePlainObject(normalizedUpdates.flowState),
|
||||
});
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'flows')) {
|
||||
nextRuntimeState = deepMerge(nextRuntimeState, {
|
||||
flowState: normalizePlainObject(normalizedUpdates.flows),
|
||||
});
|
||||
}
|
||||
return nextRuntimeState;
|
||||
}
|
||||
|
||||
function buildRuntimeStateDefault() {
|
||||
return {
|
||||
flowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
@@ -388,6 +444,19 @@
|
||||
...buildRuntimeStateDefault(),
|
||||
...cloneValue(normalizePlainObject(state.runtimeState)),
|
||||
};
|
||||
const projectedKiroRuntime = isPlainObject(normalizePlainObject(state.flowState).kiro)
|
||||
? normalizePlainObject(state.flowState.kiro)
|
||||
: {};
|
||||
const canonicalKiroRuntime = deepMerge(
|
||||
normalizePlainObject(normalizePlainObject(baseRuntimeState.flowState).kiro),
|
||||
projectedKiroRuntime
|
||||
);
|
||||
if (Object.keys(canonicalKiroRuntime).length > 0) {
|
||||
baseRuntimeState.flowState = {
|
||||
...cloneValue(normalizePlainObject(baseRuntimeState.flowState)),
|
||||
kiro: canonicalKiroRuntime,
|
||||
};
|
||||
}
|
||||
const activeFlowId = normalizeFlowId(
|
||||
Object.prototype.hasOwnProperty.call(state, 'activeFlowId')
|
||||
? state.activeFlowId
|
||||
@@ -472,9 +541,10 @@
|
||||
|
||||
function buildSessionStatePatch(currentState = {}, updates = {}) {
|
||||
const currentRuntimeState = ensureRuntimeState(currentState);
|
||||
const runtimeStateSeed = buildRuntimeStateSeed(currentRuntimeState, updates);
|
||||
const runtimeState = ensureRuntimeState({
|
||||
runtimeState: currentRuntimeState,
|
||||
...projectRuntimeViewFields(currentRuntimeState),
|
||||
runtimeState: runtimeStateSeed,
|
||||
...projectRuntimeViewFields(runtimeStateSeed),
|
||||
...buildRuntimeInputFromPatch(updates),
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
function buildDefaultSettingsState() {
|
||||
return {
|
||||
schemaVersion: 4,
|
||||
schemaVersion: 5,
|
||||
activeFlowId: defaultFlowId,
|
||||
services: {
|
||||
account: {
|
||||
@@ -77,8 +77,8 @@
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
integrationTargetId: defaultOpenAiTargetId,
|
||||
integrationTargets: {
|
||||
selectedTargetId: defaultOpenAiTargetId,
|
||||
targets: {
|
||||
cpa: {
|
||||
vpsUrl: '',
|
||||
vpsPassword: '',
|
||||
@@ -120,7 +120,7 @@
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
targetId: defaultKiroTargetId,
|
||||
selectedTargetId: defaultKiroTargetId,
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
baseUrl: defaultKiroRsUrl,
|
||||
@@ -139,8 +139,12 @@
|
||||
};
|
||||
}
|
||||
|
||||
function getIntegrationTargetValue(settingsState, pathGetter, fallback = {}) {
|
||||
return cloneValue(pathGetter(isPlainObject(settingsState) ? settingsState : {}) || fallback);
|
||||
function getTargetValue(settingsState, pathGetter, legacyPathGetter = null, fallback = {}) {
|
||||
const sourceState = isPlainObject(settingsState) ? settingsState : {};
|
||||
const resolvedValue = pathGetter(sourceState)
|
||||
|| (typeof legacyPathGetter === 'function' ? legacyPathGetter(sourceState) : null)
|
||||
|| fallback;
|
||||
return cloneValue(resolvedValue);
|
||||
}
|
||||
|
||||
function normalizeSettingsState(input = {}, options = {}) {
|
||||
@@ -155,20 +159,25 @@
|
||||
?? defaults.activeFlowId,
|
||||
defaults.activeFlowId
|
||||
);
|
||||
const openaiIntegrationTargetId = normalizeTargetId(
|
||||
const openaiSelectedTargetId = normalizeTargetId(
|
||||
'openai',
|
||||
nested?.flows?.openai?.integrationTargetId
|
||||
?? input?.openaiIntegrationTargetId
|
||||
?? input?.panelMode
|
||||
?? defaults.flows.openai.integrationTargetId,
|
||||
defaults.flows.openai.integrationTargetId
|
||||
nested?.flows?.openai?.selectedTargetId
|
||||
?? nested?.flows?.openai?.integrationTargetId
|
||||
?? (activeFlowId === 'openai'
|
||||
? (input?.selectedTargetId ?? input?.targetId)
|
||||
: undefined)
|
||||
?? defaults.flows.openai.selectedTargetId,
|
||||
defaults.flows.openai.selectedTargetId
|
||||
);
|
||||
const kiroTargetId = normalizeTargetId(
|
||||
const kiroSelectedTargetId = normalizeTargetId(
|
||||
'kiro',
|
||||
nested?.flows?.kiro?.targetId
|
||||
?? input?.kiroTargetId
|
||||
?? defaults.flows.kiro.targetId,
|
||||
defaults.flows.kiro.targetId
|
||||
nested?.flows?.kiro?.selectedTargetId
|
||||
?? nested?.flows?.kiro?.targetId
|
||||
?? (activeFlowId === 'kiro'
|
||||
? (input?.selectedTargetId ?? input?.targetId)
|
||||
: undefined)
|
||||
?? defaults.flows.kiro.selectedTargetId,
|
||||
defaults.flows.kiro.selectedTargetId
|
||||
);
|
||||
const stepExecutionRangeByFlow = isPlainObject(input?.stepExecutionRangeByFlow)
|
||||
? input.stepExecutionRangeByFlow
|
||||
@@ -212,76 +221,101 @@
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
integrationTargetId: openaiIntegrationTargetId,
|
||||
integrationTargets: {
|
||||
selectedTargetId: openaiSelectedTargetId,
|
||||
targets: {
|
||||
cpa: {
|
||||
...defaults.flows.openai.integrationTargets.cpa,
|
||||
...getIntegrationTargetValue(nested, (state) => state.flows?.openai?.integrationTargets?.cpa),
|
||||
...defaults.flows.openai.targets.cpa,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.targets?.cpa,
|
||||
(state) => state.flows?.openai?.integrationTargets?.cpa
|
||||
),
|
||||
vpsUrl: String(
|
||||
input?.vpsUrl
|
||||
?? nested?.flows?.openai?.targets?.cpa?.vpsUrl
|
||||
?? nested?.flows?.openai?.integrationTargets?.cpa?.vpsUrl
|
||||
?? ''
|
||||
).trim(),
|
||||
vpsPassword: String(
|
||||
input?.vpsPassword
|
||||
?? nested?.flows?.openai?.targets?.cpa?.vpsPassword
|
||||
?? nested?.flows?.openai?.integrationTargets?.cpa?.vpsPassword
|
||||
?? ''
|
||||
),
|
||||
localCpaStep9Mode: String(
|
||||
input?.localCpaStep9Mode
|
||||
?? nested?.flows?.openai?.targets?.cpa?.localCpaStep9Mode
|
||||
?? nested?.flows?.openai?.integrationTargets?.cpa?.localCpaStep9Mode
|
||||
?? defaults.flows.openai.integrationTargets.cpa.localCpaStep9Mode
|
||||
).trim() || defaults.flows.openai.integrationTargets.cpa.localCpaStep9Mode,
|
||||
?? defaults.flows.openai.targets.cpa.localCpaStep9Mode
|
||||
).trim() || defaults.flows.openai.targets.cpa.localCpaStep9Mode,
|
||||
},
|
||||
sub2api: {
|
||||
...defaults.flows.openai.integrationTargets.sub2api,
|
||||
...getIntegrationTargetValue(nested, (state) => state.flows?.openai?.integrationTargets?.sub2api),
|
||||
...defaults.flows.openai.targets.sub2api,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.targets?.sub2api,
|
||||
(state) => state.flows?.openai?.integrationTargets?.sub2api
|
||||
),
|
||||
sub2apiUrl: String(
|
||||
input?.sub2apiUrl
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiUrl
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiUrl
|
||||
?? ''
|
||||
).trim(),
|
||||
sub2apiEmail: String(
|
||||
input?.sub2apiEmail
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiEmail
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiEmail
|
||||
?? ''
|
||||
).trim(),
|
||||
sub2apiPassword: String(
|
||||
input?.sub2apiPassword
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiPassword
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiPassword
|
||||
?? ''
|
||||
),
|
||||
sub2apiGroupName: String(
|
||||
input?.sub2apiGroupName
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiGroupName
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiGroupName
|
||||
?? defaults.flows.openai.integrationTargets.sub2api.sub2apiGroupName
|
||||
).trim() || defaults.flows.openai.integrationTargets.sub2api.sub2apiGroupName,
|
||||
?? defaults.flows.openai.targets.sub2api.sub2apiGroupName
|
||||
).trim() || defaults.flows.openai.targets.sub2api.sub2apiGroupName,
|
||||
sub2apiGroupNames: Array.isArray(input?.sub2apiGroupNames)
|
||||
? input.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: (Array.isArray(nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiGroupNames)
|
||||
? nested.flows.openai.integrationTargets.sub2api.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: [...defaults.flows.openai.integrationTargets.sub2api.sub2apiGroupNames]),
|
||||
: (Array.isArray(nested?.flows?.openai?.targets?.sub2api?.sub2apiGroupNames)
|
||||
? nested.flows.openai.targets.sub2api.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: (Array.isArray(nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiGroupNames)
|
||||
? nested.flows.openai.integrationTargets.sub2api.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: [...defaults.flows.openai.targets.sub2api.sub2apiGroupNames])),
|
||||
sub2apiAccountPriority: Math.max(1, Number(
|
||||
input?.sub2apiAccountPriority
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiAccountPriority
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiAccountPriority
|
||||
?? defaults.flows.openai.integrationTargets.sub2api.sub2apiAccountPriority
|
||||
) || defaults.flows.openai.integrationTargets.sub2api.sub2apiAccountPriority),
|
||||
?? defaults.flows.openai.targets.sub2api.sub2apiAccountPriority
|
||||
) || defaults.flows.openai.targets.sub2api.sub2apiAccountPriority),
|
||||
sub2apiDefaultProxyName: String(
|
||||
input?.sub2apiDefaultProxyName
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiDefaultProxyName
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiDefaultProxyName
|
||||
?? ''
|
||||
).trim(),
|
||||
},
|
||||
codex2api: {
|
||||
...defaults.flows.openai.integrationTargets.codex2api,
|
||||
...getIntegrationTargetValue(nested, (state) => state.flows?.openai?.integrationTargets?.codex2api),
|
||||
...defaults.flows.openai.targets.codex2api,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.targets?.codex2api,
|
||||
(state) => state.flows?.openai?.integrationTargets?.codex2api
|
||||
),
|
||||
codex2apiUrl: String(
|
||||
input?.codex2apiUrl
|
||||
?? nested?.flows?.openai?.targets?.codex2api?.codex2apiUrl
|
||||
?? nested?.flows?.openai?.integrationTargets?.codex2api?.codex2apiUrl
|
||||
?? ''
|
||||
).trim(),
|
||||
codex2apiAdminKey: String(
|
||||
input?.codex2apiAdminKey
|
||||
?? nested?.flows?.openai?.targets?.codex2api?.codex2apiAdminKey
|
||||
?? nested?.flows?.openai?.integrationTargets?.codex2api?.codex2apiAdminKey
|
||||
?? ''
|
||||
).trim(),
|
||||
@@ -349,11 +383,14 @@
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
targetId: kiroTargetId,
|
||||
selectedTargetId: kiroSelectedTargetId,
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
...defaults.flows.kiro.targets['kiro-rs'],
|
||||
...getIntegrationTargetValue(nested, (state) => state.flows?.kiro?.targets?.['kiro-rs']),
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.kiro?.targets?.['kiro-rs']
|
||||
),
|
||||
baseUrl: String(
|
||||
input?.kiroRsUrl
|
||||
?? input?.kiroRsBaseUrl
|
||||
@@ -419,20 +456,24 @@
|
||||
const normalizedState = normalizeSettingsState(settingsState);
|
||||
const normalizedFlowId = normalizeFlowId(flowId, normalizedState.activeFlowId);
|
||||
const flowSettings = normalizedState?.flows?.[normalizedFlowId] || {};
|
||||
if (normalizedFlowId === 'kiro') {
|
||||
return normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
flowSettings?.targetId,
|
||||
defaultKiroTargetId
|
||||
);
|
||||
}
|
||||
return normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
flowSettings?.integrationTargetId,
|
||||
defaultOpenAiTargetId
|
||||
flowSettings?.selectedTargetId,
|
||||
normalizedFlowId === 'kiro' ? defaultKiroTargetId : defaultOpenAiTargetId
|
||||
);
|
||||
}
|
||||
|
||||
function getTargetSettings(settingsState = {}, flowId, targetId = '') {
|
||||
const normalizedState = normalizeSettingsState(settingsState);
|
||||
const normalizedFlowId = normalizeFlowId(flowId, normalizedState.activeFlowId);
|
||||
const resolvedTargetId = normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
targetId || getSelectedTargetId(normalizedState, normalizedFlowId),
|
||||
getSelectedTargetId(normalizedState, normalizedFlowId)
|
||||
);
|
||||
return cloneValue(normalizedState?.flows?.[normalizedFlowId]?.targets?.[resolvedTargetId] || {});
|
||||
}
|
||||
|
||||
function buildStepExecutionRangeByFlow(settingsState = {}) {
|
||||
const normalizedState = normalizeSettingsState(settingsState);
|
||||
return {
|
||||
@@ -455,21 +496,19 @@
|
||||
const openaiState = normalizedState.flows.openai;
|
||||
const kiroState = normalizedState.flows.kiro;
|
||||
next.activeFlowId = normalizedState.activeFlowId;
|
||||
next.openaiIntegrationTargetId = getSelectedTargetId(normalizedState, 'openai');
|
||||
next.kiroTargetId = getSelectedTargetId(normalizedState, 'kiro');
|
||||
next.panelMode = next.openaiIntegrationTargetId;
|
||||
next.vpsUrl = openaiState.integrationTargets.cpa.vpsUrl;
|
||||
next.vpsPassword = openaiState.integrationTargets.cpa.vpsPassword;
|
||||
next.localCpaStep9Mode = openaiState.integrationTargets.cpa.localCpaStep9Mode;
|
||||
next.sub2apiUrl = openaiState.integrationTargets.sub2api.sub2apiUrl;
|
||||
next.sub2apiEmail = openaiState.integrationTargets.sub2api.sub2apiEmail;
|
||||
next.sub2apiPassword = openaiState.integrationTargets.sub2api.sub2apiPassword;
|
||||
next.sub2apiGroupName = openaiState.integrationTargets.sub2api.sub2apiGroupName;
|
||||
next.sub2apiGroupNames = cloneValue(openaiState.integrationTargets.sub2api.sub2apiGroupNames);
|
||||
next.sub2apiAccountPriority = openaiState.integrationTargets.sub2api.sub2apiAccountPriority;
|
||||
next.sub2apiDefaultProxyName = openaiState.integrationTargets.sub2api.sub2apiDefaultProxyName;
|
||||
next.codex2apiUrl = openaiState.integrationTargets.codex2api.codex2apiUrl;
|
||||
next.codex2apiAdminKey = openaiState.integrationTargets.codex2api.codex2apiAdminKey;
|
||||
next.targetId = getSelectedTargetId(normalizedState, normalizedState.activeFlowId);
|
||||
next.vpsUrl = openaiState.targets.cpa.vpsUrl;
|
||||
next.vpsPassword = openaiState.targets.cpa.vpsPassword;
|
||||
next.localCpaStep9Mode = openaiState.targets.cpa.localCpaStep9Mode;
|
||||
next.sub2apiUrl = openaiState.targets.sub2api.sub2apiUrl;
|
||||
next.sub2apiEmail = openaiState.targets.sub2api.sub2apiEmail;
|
||||
next.sub2apiPassword = openaiState.targets.sub2api.sub2apiPassword;
|
||||
next.sub2apiGroupName = openaiState.targets.sub2api.sub2apiGroupName;
|
||||
next.sub2apiGroupNames = cloneValue(openaiState.targets.sub2api.sub2apiGroupNames);
|
||||
next.sub2apiAccountPriority = openaiState.targets.sub2api.sub2apiAccountPriority;
|
||||
next.sub2apiDefaultProxyName = openaiState.targets.sub2api.sub2apiDefaultProxyName;
|
||||
next.codex2apiUrl = openaiState.targets.codex2api.codex2apiUrl;
|
||||
next.codex2apiAdminKey = openaiState.targets.codex2api.codex2apiAdminKey;
|
||||
next.customPassword = normalizedState.services.account.customPassword;
|
||||
next.signupMethod = openaiState.signup.signupMethod;
|
||||
next.phoneVerificationEnabled = openaiState.signup.phoneVerificationEnabled;
|
||||
@@ -497,11 +536,12 @@
|
||||
const normalizedFlowId = normalizeFlowId(flowId, normalizedState.activeFlowId);
|
||||
const targetId = getSelectedTargetId(normalizedState, normalizedFlowId);
|
||||
if (normalizedFlowId === 'kiro') {
|
||||
const targetSettings = getTargetSettings(normalizedState, normalizedFlowId, targetId);
|
||||
return {
|
||||
activeFlowId: normalizedFlowId,
|
||||
targetId,
|
||||
kiroRsUrl: normalizedState.flows.kiro.targets['kiro-rs'].baseUrl,
|
||||
kiroRsKey: normalizedState.flows.kiro.targets['kiro-rs'].apiKey,
|
||||
kiroRsUrl: targetSettings.baseUrl || '',
|
||||
kiroRsKey: targetSettings.apiKey || '',
|
||||
};
|
||||
}
|
||||
return {
|
||||
@@ -517,6 +557,7 @@
|
||||
getFlowInputState,
|
||||
getFlowSettings,
|
||||
getSelectedTargetId,
|
||||
getTargetSettings,
|
||||
mergeSettingsState,
|
||||
normalizeSettingsState,
|
||||
};
|
||||
@@ -0,0 +1,486 @@
|
||||
(function attachMultiPageSourceRegistry(root, factory) {
|
||||
root.MultiPageSourceRegistry = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createSourceRegistryModule() {
|
||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||
const flowRegistryApi = rootScope.MultiPageFlowRegistry || {};
|
||||
|
||||
const SHARED_SOURCE_DEFINITIONS = Object.freeze({
|
||||
'qq-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'QQ \u90ae\u7bb1',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'qq-mail-family',
|
||||
driverId: 'content/qq-mail',
|
||||
cleanupScopes: [],
|
||||
detectionMatchers: [
|
||||
{ hostnames: ['mail.qq.com', 'wx.mail.qq.com'] },
|
||||
],
|
||||
familyMatchers: [
|
||||
{ hostnames: ['mail.qq.com', 'wx.mail.qq.com'] },
|
||||
],
|
||||
},
|
||||
'mail-163': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: '163 \u90ae\u7bb1',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'mail-163-family',
|
||||
driverId: 'content/mail-163',
|
||||
cleanupScopes: [],
|
||||
detectionMatchers: [
|
||||
{
|
||||
hostnames: ['mail.163.com', 'mail.126.com', 'webmail.vip.163.com'],
|
||||
hostnameEndsWith: ['.mail.163.com', '.mail.126.com'],
|
||||
matchMode: 'any',
|
||||
},
|
||||
],
|
||||
familyMatchers: [
|
||||
{
|
||||
hostnames: ['mail.163.com', 'mail.126.com', 'webmail.vip.163.com'],
|
||||
hostnameEndsWith: ['.mail.163.com', '.mail.126.com'],
|
||||
matchMode: 'any',
|
||||
},
|
||||
],
|
||||
},
|
||||
'gmail-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'Gmail \u90ae\u7bb1',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'gmail-mail-family',
|
||||
driverId: 'content/gmail-mail',
|
||||
cleanupScopes: [],
|
||||
detectionMatchers: [
|
||||
{ hostnames: ['mail.google.com'] },
|
||||
],
|
||||
familyMatchers: [
|
||||
{ hostnames: ['mail.google.com'] },
|
||||
],
|
||||
},
|
||||
'icloud-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'iCloud \u90ae\u7bb1',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'icloud-mail-family',
|
||||
driverId: 'content/icloud-mail',
|
||||
cleanupScopes: [],
|
||||
detectionMatchers: [
|
||||
{ hostnames: ['www.icloud.com', 'www.icloud.com.cn'] },
|
||||
],
|
||||
familyMatchers: [
|
||||
{ hostnames: ['www.icloud.com', 'www.icloud.com.cn'] },
|
||||
],
|
||||
},
|
||||
'inbucket-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'Inbucket \u90ae\u7bb1',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'inbucket-mail-family',
|
||||
driverId: 'content/inbucket-mail',
|
||||
cleanupScopes: [],
|
||||
familyMatchers: [
|
||||
{ originEqualsReference: true, pathPrefixes: ['/m/'] },
|
||||
],
|
||||
},
|
||||
'mail-2925': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: '2925 \u90ae\u7bb1',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'mail-2925-family',
|
||||
driverId: 'content/mail-2925',
|
||||
cleanupScopes: [],
|
||||
detectionMatchers: [
|
||||
{ hostnames: ['2925.com', 'www.2925.com'] },
|
||||
],
|
||||
familyMatchers: [
|
||||
{ hostnames: ['2925.com', 'www.2925.com'] },
|
||||
],
|
||||
},
|
||||
'duck-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'Duck \u90ae\u7bb1',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'duck-mail-family',
|
||||
driverId: 'content/duck-mail',
|
||||
cleanupScopes: [],
|
||||
detectionMatchers: [
|
||||
{ urlIncludes: 'duckduckgo.com/email/settings/autofill' },
|
||||
],
|
||||
familyMatchers: [
|
||||
{ hostnames: ['duckduckgo.com'], pathPrefixes: ['/email/'] },
|
||||
],
|
||||
},
|
||||
'unknown-source': {
|
||||
flowId: null,
|
||||
kind: 'unknown',
|
||||
label: '\u672a\u77e5\u6765\u6e90',
|
||||
readyPolicy: 'disabled',
|
||||
family: 'unknown-family',
|
||||
driverId: null,
|
||||
cleanupScopes: [],
|
||||
},
|
||||
});
|
||||
|
||||
const SHARED_DRIVER_DEFINITIONS = Object.freeze({
|
||||
'content/qq-mail': {
|
||||
sourceId: 'qq-mail',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/mail-163': {
|
||||
sourceId: 'mail-163',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/gmail-mail': {
|
||||
sourceId: 'gmail-mail',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/icloud-mail': {
|
||||
sourceId: 'icloud-mail',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/mail-2925': {
|
||||
sourceId: 'mail-2925',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/duck-mail': {
|
||||
sourceId: 'duck-mail',
|
||||
commands: ['FETCH_ALIAS_EMAIL'],
|
||||
},
|
||||
});
|
||||
|
||||
function normalizeHostname(hostname = '') {
|
||||
return String(hostname || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function matchesNamedHostFamily(hostname = '', family = '') {
|
||||
const normalizedHost = normalizeHostname(hostname);
|
||||
const normalizedFamily = normalizeHostname(family);
|
||||
if (!normalizedHost || !normalizedFamily) {
|
||||
return false;
|
||||
}
|
||||
return normalizedHost === normalizedFamily
|
||||
|| normalizedHost.endsWith(`.${normalizedFamily}`)
|
||||
|| normalizedHost.startsWith(`${normalizedFamily}.`)
|
||||
|| normalizedHost.includes(`.${normalizedFamily}.`);
|
||||
}
|
||||
|
||||
function parseUrlSafely(rawUrl) {
|
||||
if (!rawUrl) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new URL(rawUrl);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function buildCandidateUrl(url = '', hostname = '') {
|
||||
const candidate = parseUrlSafely(url);
|
||||
if (candidate) {
|
||||
return candidate;
|
||||
}
|
||||
const normalizedHostname = normalizeHostname(hostname);
|
||||
if (!normalizedHostname) {
|
||||
return null;
|
||||
}
|
||||
return parseUrlSafely(`https://${normalizedHostname}/`);
|
||||
}
|
||||
|
||||
function normalizeSourceId(source) {
|
||||
return String(source || '').trim();
|
||||
}
|
||||
|
||||
function normalizeStringArray(values = []) {
|
||||
if (!Array.isArray(values)) {
|
||||
return [];
|
||||
}
|
||||
return values
|
||||
.map((value) => String(value || '').trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function hostnameMatchesSuffix(hostname = '', suffix = '') {
|
||||
const normalizedHost = normalizeHostname(hostname);
|
||||
const normalizedSuffix = normalizeHostname(suffix);
|
||||
if (!normalizedHost || !normalizedSuffix) {
|
||||
return false;
|
||||
}
|
||||
if (normalizedHost === normalizedSuffix) {
|
||||
return true;
|
||||
}
|
||||
const dottedSuffix = normalizedSuffix.startsWith('.')
|
||||
? normalizedSuffix
|
||||
: `.${normalizedSuffix}`;
|
||||
return normalizedHost.endsWith(dottedSuffix);
|
||||
}
|
||||
|
||||
function getRuntimeSourceDefinitions() {
|
||||
return {
|
||||
...(typeof flowRegistryApi.getRuntimeSourceDefinitions === 'function'
|
||||
? flowRegistryApi.getRuntimeSourceDefinitions()
|
||||
: {}),
|
||||
...SHARED_SOURCE_DEFINITIONS,
|
||||
};
|
||||
}
|
||||
|
||||
function getDriverDefinitions() {
|
||||
return {
|
||||
...(typeof flowRegistryApi.getDriverDefinitions === 'function'
|
||||
? flowRegistryApi.getDriverDefinitions()
|
||||
: {}),
|
||||
...SHARED_DRIVER_DEFINITIONS,
|
||||
};
|
||||
}
|
||||
|
||||
function getSourceAliases() {
|
||||
return {
|
||||
...(typeof flowRegistryApi.getSourceAliases === 'function'
|
||||
? flowRegistryApi.getSourceAliases()
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
function createSourceRegistry() {
|
||||
const SOURCE_DEFINITIONS = getRuntimeSourceDefinitions();
|
||||
const DRIVER_DEFINITIONS = getDriverDefinitions();
|
||||
const SOURCE_ALIASES = getSourceAliases();
|
||||
|
||||
function resolveCanonicalSource(source) {
|
||||
const normalized = normalizeSourceId(source);
|
||||
if (!normalized) {
|
||||
return '';
|
||||
}
|
||||
return SOURCE_ALIASES[normalized] || normalized;
|
||||
}
|
||||
|
||||
function getAliasKeysForCanonicalSource(source) {
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
return Object.keys(SOURCE_ALIASES).filter((alias) => SOURCE_ALIASES[alias] === canonical);
|
||||
}
|
||||
|
||||
function getSourceKeys(source) {
|
||||
const normalized = normalizeSourceId(source);
|
||||
const canonical = resolveCanonicalSource(normalized);
|
||||
return Array.from(new Set([
|
||||
canonical,
|
||||
...getAliasKeysForCanonicalSource(canonical),
|
||||
normalized,
|
||||
].filter(Boolean)));
|
||||
}
|
||||
|
||||
function getSourceMeta(source) {
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
const definition = SOURCE_DEFINITIONS[canonical];
|
||||
if (!definition) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: canonical,
|
||||
aliases: getAliasKeysForCanonicalSource(canonical),
|
||||
...definition,
|
||||
};
|
||||
}
|
||||
|
||||
function getSourceLabel(source) {
|
||||
return getSourceMeta(source)?.label || normalizeSourceId(source) || '\u672a\u77e5\u6765\u6e90';
|
||||
}
|
||||
|
||||
function getDriverIdForSource(source) {
|
||||
return getSourceMeta(source)?.driverId || null;
|
||||
}
|
||||
|
||||
function getDriverMeta(sourceOrDriverId) {
|
||||
const directDriverId = normalizeSourceId(sourceOrDriverId);
|
||||
const driverId = Object.prototype.hasOwnProperty.call(DRIVER_DEFINITIONS, directDriverId)
|
||||
? directDriverId
|
||||
: getDriverIdForSource(sourceOrDriverId);
|
||||
if (!driverId || !Object.prototype.hasOwnProperty.call(DRIVER_DEFINITIONS, driverId)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: driverId,
|
||||
...DRIVER_DEFINITIONS[driverId],
|
||||
};
|
||||
}
|
||||
|
||||
function driverAcceptsCommand(sourceOrDriverId, command) {
|
||||
const normalizedCommand = normalizeSourceId(command);
|
||||
if (!normalizedCommand) {
|
||||
return false;
|
||||
}
|
||||
const driver = getDriverMeta(sourceOrDriverId);
|
||||
return Array.isArray(driver?.commands) && driver.commands.includes(normalizedCommand);
|
||||
}
|
||||
|
||||
function matchesUrlRule(rule = {}, candidate, reference) {
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
const matchMode = String(rule?.matchMode || 'all').trim().toLowerCase() === 'any'
|
||||
? 'any'
|
||||
: 'all';
|
||||
const conditions = [];
|
||||
|
||||
const hostnames = normalizeStringArray(rule.hostnames);
|
||||
if (hostnames.length) {
|
||||
conditions.push(hostnames.includes(candidate.hostname));
|
||||
}
|
||||
|
||||
const hostnameFamilies = normalizeStringArray(rule.hostnameFamilies);
|
||||
if (hostnameFamilies.length) {
|
||||
conditions.push(hostnameFamilies.some((family) => matchesNamedHostFamily(candidate.hostname, family)));
|
||||
}
|
||||
|
||||
const hostnameEndsWith = normalizeStringArray(rule.hostnameEndsWith);
|
||||
if (hostnameEndsWith.length) {
|
||||
conditions.push(hostnameEndsWith.some((suffix) => hostnameMatchesSuffix(candidate.hostname, suffix)));
|
||||
}
|
||||
|
||||
if (rule.hostnameRegex) {
|
||||
conditions.push(new RegExp(rule.hostnameRegex, rule.hostnameRegexFlags || '').test(candidate.hostname));
|
||||
}
|
||||
|
||||
if (rule.urlIncludes) {
|
||||
conditions.push(String(candidate.href || '').includes(String(rule.urlIncludes)));
|
||||
}
|
||||
|
||||
const pathPrefixes = normalizeStringArray(rule.pathPrefixes);
|
||||
if (pathPrefixes.length) {
|
||||
conditions.push(pathPrefixes.some((prefix) => candidate.pathname.startsWith(prefix)));
|
||||
}
|
||||
|
||||
if (rule.pathEquals) {
|
||||
conditions.push(candidate.pathname === String(rule.pathEquals));
|
||||
}
|
||||
|
||||
const pathEqualsOneOf = normalizeStringArray(rule.pathEqualsOneOf);
|
||||
if (pathEqualsOneOf.length) {
|
||||
conditions.push(pathEqualsOneOf.includes(candidate.pathname));
|
||||
}
|
||||
|
||||
if (rule.originEqualsReference) {
|
||||
conditions.push(Boolean(reference) && candidate.origin === reference.origin);
|
||||
}
|
||||
|
||||
if (rule.pathEqualsReference) {
|
||||
conditions.push(Boolean(reference) && candidate.pathname === reference.pathname);
|
||||
}
|
||||
|
||||
if (!conditions.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return matchMode === 'any'
|
||||
? conditions.some(Boolean)
|
||||
: conditions.every(Boolean);
|
||||
}
|
||||
|
||||
function matchesSourceDetection(source, url = '', hostname = '') {
|
||||
const candidate = buildCandidateUrl(url, hostname);
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
const detectionMatchers = getSourceMeta(canonical)?.detectionMatchers || [];
|
||||
return detectionMatchers.some((rule) => matchesUrlRule(rule, candidate, null));
|
||||
}
|
||||
|
||||
function isSignupPageHost(hostname = '') {
|
||||
return matchesSourceDetection('openai-auth', '', hostname);
|
||||
}
|
||||
|
||||
function isSignupEntryHost(hostname = '') {
|
||||
return matchesSourceDetection('chatgpt', '', hostname);
|
||||
}
|
||||
|
||||
function is163MailHost(hostname = '') {
|
||||
return matchesSourceDetection('mail-163', '', hostname);
|
||||
}
|
||||
|
||||
function matchesSourceUrlFamily(source, candidateUrl, referenceUrl) {
|
||||
const candidate = parseUrlSafely(candidateUrl);
|
||||
if (!candidate) {
|
||||
return false;
|
||||
}
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
const familyMatchers = getSourceMeta(canonical)?.familyMatchers || [];
|
||||
const reference = parseUrlSafely(referenceUrl);
|
||||
return familyMatchers.some((rule) => matchesUrlRule(rule, candidate, reference));
|
||||
}
|
||||
|
||||
function detectSourceFromLocation({
|
||||
injectedSource,
|
||||
url = '',
|
||||
hostname = '',
|
||||
} = {}) {
|
||||
if (injectedSource) {
|
||||
return resolveCanonicalSource(injectedSource);
|
||||
}
|
||||
|
||||
const candidate = buildCandidateUrl(url, hostname);
|
||||
if (!candidate) {
|
||||
return 'unknown-source';
|
||||
}
|
||||
|
||||
const detectionSourceIds = Object.keys(SOURCE_DEFINITIONS).filter((sourceId) => sourceId !== 'unknown-source');
|
||||
for (const sourceId of detectionSourceIds) {
|
||||
if (matchesSourceDetection(sourceId, candidate.href, candidate.hostname)) {
|
||||
return sourceId;
|
||||
}
|
||||
}
|
||||
|
||||
return 'unknown-source';
|
||||
}
|
||||
|
||||
function shouldReportReadyForFrame(source, isChildFrame) {
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
const readyPolicy = getSourceMeta(canonical)?.readyPolicy || 'allow-child-frame';
|
||||
if (readyPolicy === 'disabled') {
|
||||
return false;
|
||||
}
|
||||
if (!isChildFrame) {
|
||||
return true;
|
||||
}
|
||||
return readyPolicy === 'allow-child-frame';
|
||||
}
|
||||
|
||||
function getCleanupOwnerSource(cleanupScope) {
|
||||
const normalizedCleanupScope = String(cleanupScope || '').trim();
|
||||
const owner = Object.keys(SOURCE_DEFINITIONS).find((sourceId) => {
|
||||
const cleanupScopes = Array.isArray(SOURCE_DEFINITIONS[sourceId]?.cleanupScopes)
|
||||
? SOURCE_DEFINITIONS[sourceId].cleanupScopes
|
||||
: [];
|
||||
return cleanupScopes.includes(normalizedCleanupScope);
|
||||
});
|
||||
return resolveCanonicalSource(owner || '');
|
||||
}
|
||||
|
||||
return {
|
||||
detectSourceFromLocation,
|
||||
driverAcceptsCommand,
|
||||
getCleanupOwnerSource,
|
||||
getDriverIdForSource,
|
||||
getDriverMeta,
|
||||
getSourceKeys,
|
||||
getSourceLabel,
|
||||
getSourceMeta,
|
||||
is163MailHost,
|
||||
isSignupEntryHost,
|
||||
isSignupPageHost,
|
||||
matchesSourceUrlFamily,
|
||||
parseUrlSafely,
|
||||
resolveCanonicalSource,
|
||||
shouldReportReadyForFrame,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createSourceRegistry,
|
||||
};
|
||||
});
|
||||
@@ -76,7 +76,7 @@
|
||||
if (sourceRegistry?.getCleanupOwnerSource) {
|
||||
return sourceRegistry.getCleanupOwnerSource(cleanupScope);
|
||||
}
|
||||
return cleanupScope === 'oauth-localhost-callback' ? 'signup-page' : '';
|
||||
return cleanupScope === 'oauth-localhost-callback' ? 'openai-auth' : '';
|
||||
}
|
||||
|
||||
function normalizeAutomationWindowId(value) {
|
||||
+73
-585
@@ -1,589 +1,80 @@
|
||||
(function attachStepDefinitions(root, factory) {
|
||||
root.MultiPageStepDefinitions = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createStepDefinitionsModule() {
|
||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||
const flowsIndexApi = rootScope.MultiPageFlowsIndex || {};
|
||||
|
||||
const DEFAULT_ACTIVE_FLOW_ID = 'openai';
|
||||
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
||||
const PLUS_PAYMENT_METHOD_PAYPAL_HOSTED = 'paypal-hosted';
|
||||
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
||||
const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper';
|
||||
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||
const PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION = 'cpa_codex_session';
|
||||
const PLUS_PAYMENT_STEP_KEY = 'paypal-approve';
|
||||
const SIGNUP_METHOD_EMAIL = 'email';
|
||||
const SIGNUP_METHOD_PHONE = 'phone';
|
||||
|
||||
const NORMAL_PREFIX_STEP_DEFINITIONS = [
|
||||
{ id: 1, order: 10, key: 'open-chatgpt', title: '打开 ChatGPT 官网', sourceId: 'chatgpt', driverId: null, command: 'open-chatgpt' },
|
||||
{ id: 2, order: 20, key: 'submit-signup-email', title: '注册并输入邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-signup-email' },
|
||||
{ id: 3, order: 30, key: 'fill-password', title: '填写密码并继续', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-password' },
|
||||
{ id: 4, order: 40, key: 'fetch-signup-code', title: '获取注册验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-signup-code' },
|
||||
{ id: 5, order: 50, key: 'fill-profile', title: '填写姓名和生日', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-profile' },
|
||||
{ id: 6, order: 60, key: 'wait-registration-success', title: '等待注册成功', sourceId: 'chatgpt', driverId: null, command: 'wait-registration-success' },
|
||||
];
|
||||
|
||||
const PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS = [
|
||||
{ id: 1, order: 10, key: 'open-chatgpt', title: '打开 ChatGPT 官网', sourceId: 'chatgpt', driverId: null, command: 'open-chatgpt' },
|
||||
{ id: 2, order: 20, key: 'submit-signup-email', title: '注册并输入邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-signup-email' },
|
||||
{ id: 3, order: 30, key: 'fill-password', title: '填写密码并继续', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-password' },
|
||||
{ id: 4, order: 40, key: 'fetch-signup-code', title: '获取注册验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-signup-code' },
|
||||
{ id: 5, order: 50, key: 'fill-profile', title: '填写姓名和生日', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-profile' },
|
||||
{ id: 6, order: 60, key: 'plus-checkout-create', title: '创建 Plus Checkout', sourceId: 'plus-checkout', driverId: 'content/plus-checkout', command: 'plus-checkout-create' },
|
||||
{ id: 7, order: 70, key: 'plus-checkout-billing', title: '填写账单并提交订单', sourceId: 'plus-checkout', driverId: 'content/plus-checkout', command: 'plus-checkout-billing' },
|
||||
{ id: 8, order: 80, key: 'paypal-approve', title: 'PayPal 登录与授权', sourceId: 'paypal-flow', driverId: 'content/paypal-flow', command: 'paypal-approve' },
|
||||
{ id: 9, order: 90, key: 'plus-checkout-return', title: '订阅回跳确认', sourceId: 'plus-checkout', driverId: 'content/plus-checkout', command: 'plus-checkout-return' },
|
||||
];
|
||||
const PLUS_PAYPAL_HOSTED_CHECKOUT_PREFIX_STEP_DEFINITIONS = [
|
||||
...PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS.slice(0, 6),
|
||||
{ id: 7, order: 70, key: 'paypal-hosted-email', title: '无卡直绑填写 PayPal 邮箱', sourceId: 'paypal-flow', driverId: 'content/paypal-flow', command: 'paypal-hosted-email' },
|
||||
{ id: 8, order: 80, key: 'paypal-hosted-card', title: '无卡直绑填写 PayPal 资料', sourceId: 'paypal-flow', driverId: 'content/paypal-flow', command: 'paypal-hosted-card' },
|
||||
{ id: 9, order: 90, key: 'paypal-hosted-create-account', title: '无卡直绑确认创建 PayPal', sourceId: 'paypal-flow', driverId: 'content/paypal-flow', command: 'paypal-hosted-create-account' },
|
||||
{ id: 10, order: 100, key: 'paypal-hosted-review', title: '无卡直绑完成 PayPal 授权', sourceId: 'paypal-flow', driverId: 'content/paypal-flow', command: 'paypal-hosted-review' },
|
||||
];
|
||||
|
||||
const PLUS_GOPAY_PREFIX_STEP_DEFINITIONS = [
|
||||
{ id: 1, order: 10, key: 'open-chatgpt', title: '打开 ChatGPT 官网', sourceId: 'chatgpt', driverId: null, command: 'open-chatgpt' },
|
||||
{ id: 2, order: 20, key: 'submit-signup-email', title: '注册并输入邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-signup-email' },
|
||||
{ id: 3, order: 30, key: 'fill-password', title: '填写密码并继续', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-password' },
|
||||
{ id: 4, order: 40, key: 'fetch-signup-code', title: '获取注册验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-signup-code' },
|
||||
{ id: 5, order: 50, key: 'fill-profile', title: '填写姓名和生日', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-profile' },
|
||||
{ id: 6, order: 60, key: 'plus-checkout-create', title: '打开 GoPay 订阅页', sourceId: 'plus-checkout', driverId: 'content/plus-checkout', command: 'plus-checkout-create' },
|
||||
{ id: 7, order: 70, key: 'gopay-subscription-confirm', title: '等待 GoPay 订阅确认', sourceId: 'gopay-flow', driverId: 'content/gopay-flow', command: 'gopay-subscription-confirm' },
|
||||
];
|
||||
|
||||
const PLUS_GPC_PREFIX_STEP_DEFINITIONS = [
|
||||
{ id: 1, order: 10, key: 'open-chatgpt', title: '打开 ChatGPT 官网', sourceId: 'chatgpt', driverId: null, command: 'open-chatgpt' },
|
||||
{ id: 2, order: 20, key: 'submit-signup-email', title: '注册并输入邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-signup-email' },
|
||||
{ id: 3, order: 30, key: 'fill-password', title: '填写密码并继续', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-password' },
|
||||
{ id: 4, order: 40, key: 'fetch-signup-code', title: '获取注册验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-signup-code' },
|
||||
{ id: 5, order: 50, key: 'fill-profile', title: '填写姓名和生日', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fill-profile' },
|
||||
{ id: 6, order: 60, key: 'plus-checkout-create', title: '创建 GPC 订单', sourceId: 'plus-checkout', driverId: 'content/plus-checkout', command: 'plus-checkout-create' },
|
||||
{ id: 7, order: 70, key: 'plus-checkout-billing', title: '等待 GPC 任务完成', sourceId: 'plus-checkout', driverId: 'content/plus-checkout', command: 'plus-checkout-billing' },
|
||||
];
|
||||
|
||||
function isPhoneSignupReloginAfterBindEmailEnabled(options = {}) {
|
||||
return Boolean(options?.phoneSignupReloginAfterBindEmailEnabled);
|
||||
}
|
||||
|
||||
function createOpenAiAuthTail(startId, startOrder, signupMethod = SIGNUP_METHOD_EMAIL, options = {}) {
|
||||
const id = Number(startId) || 7;
|
||||
const order = Number(startOrder) || id * 10;
|
||||
const commonStart = [
|
||||
{ id, order, key: 'oauth-login', title: '刷新 OAuth 并登录', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'oauth-login' },
|
||||
{ id: id + 1, order: order + 10, key: 'fetch-login-code', title: '获取登录验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-login-code' },
|
||||
];
|
||||
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||
if (isPhoneSignupReloginAfterBindEmailEnabled(options)) {
|
||||
return [
|
||||
...commonStart,
|
||||
{ id: id + 2, order: order + 20, key: 'bind-email', title: '绑定邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'bind-email' },
|
||||
{ id: id + 3, order: order + 30, key: 'fetch-bind-email-code', title: '获取绑定邮箱验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fetch-bind-email-code', mailRuleId: 'openai-login-code' },
|
||||
{ id: id + 4, order: order + 40, key: 'relogin-bound-email', title: '绑定邮箱后刷新 OAuth 并登录(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'oauth-login' },
|
||||
{ id: id + 5, order: order + 50, key: 'fetch-bound-email-login-code', title: '获取登录验证码(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-login-code' },
|
||||
{ id: id + 6, order: order + 60, key: 'post-bound-email-phone-verification', title: '手机号验证', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'post-login-phone-verification' },
|
||||
{ id: id + 7, order: order + 70, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
|
||||
{ id: id + 8, order: order + 80, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
|
||||
];
|
||||
}
|
||||
return [
|
||||
...commonStart,
|
||||
{ id: id + 2, order: order + 20, key: 'bind-email', title: '绑定邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'bind-email' },
|
||||
{ id: id + 3, order: order + 30, key: 'fetch-bind-email-code', title: '获取绑定邮箱验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fetch-bind-email-code', mailRuleId: 'openai-login-code' },
|
||||
{ id: id + 4, order: order + 40, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
|
||||
{ id: id + 5, order: order + 50, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
|
||||
];
|
||||
function normalizeRegisteredFlowIds(values = []) {
|
||||
if (!Array.isArray(values)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
...commonStart,
|
||||
{ id: id + 2, order: order + 20, key: 'post-login-phone-verification', title: '手机号验证', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'post-login-phone-verification' },
|
||||
{ id: id + 3, order: order + 30, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
|
||||
{ id: id + 4, order: order + 40, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
|
||||
];
|
||||
const seen = new Set();
|
||||
return values
|
||||
.map((value) => String(value || '').trim().toLowerCase())
|
||||
.filter((value) => {
|
||||
if (!value || seen.has(value)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(value);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function createSub2ApiSessionImportTail(startId, startOrder) {
|
||||
const id = Number(startId) || 10;
|
||||
const order = Number(startOrder) || id * 10;
|
||||
return [
|
||||
{
|
||||
id,
|
||||
order,
|
||||
key: 'sub2api-session-import',
|
||||
title: '导入当前 ChatGPT 会话到 SUB2API',
|
||||
sourceId: 'sub2api-panel',
|
||||
driverId: 'background/sub2api-session-import',
|
||||
command: 'sub2api-session-import',
|
||||
},
|
||||
];
|
||||
function getRegisteredFlowIds() {
|
||||
return normalizeRegisteredFlowIds(
|
||||
typeof flowsIndexApi.getRegisteredFlowIds === 'function'
|
||||
? flowsIndexApi.getRegisteredFlowIds()
|
||||
: [DEFAULT_ACTIVE_FLOW_ID]
|
||||
).filter((flowId) => Boolean(getFlowWorkflow(flowId)));
|
||||
}
|
||||
|
||||
function createCpaSessionImportTail(startId, startOrder) {
|
||||
const id = Number(startId) || 10;
|
||||
const order = Number(startOrder) || id * 10;
|
||||
return [
|
||||
{
|
||||
id,
|
||||
order,
|
||||
key: 'cpa-session-import',
|
||||
title: '导入当前 ChatGPT 会话到 CPA',
|
||||
sourceId: 'vps-panel',
|
||||
driverId: 'background/cpa-session-import',
|
||||
command: 'cpa-session-import',
|
||||
},
|
||||
];
|
||||
function getFlowWorkflow(flowId) {
|
||||
return typeof flowsIndexApi.getFlowWorkflow === 'function'
|
||||
? flowsIndexApi.getFlowWorkflow(flowId)
|
||||
: null;
|
||||
}
|
||||
|
||||
function normalizePlusAccountAccessStrategy(value = '') {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||
return PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION;
|
||||
}
|
||||
if (normalized === PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION) {
|
||||
return PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION;
|
||||
}
|
||||
return PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||
}
|
||||
|
||||
function resolvePlusSessionImportTail(options = {}, signupMethod = SIGNUP_METHOD_EMAIL) {
|
||||
if (signupMethod !== SIGNUP_METHOD_EMAIL) {
|
||||
return null;
|
||||
}
|
||||
const strategy = normalizePlusAccountAccessStrategy(options?.plusAccountAccessStrategy);
|
||||
if (strategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||
return createSub2ApiSessionImportTail;
|
||||
}
|
||||
if (strategy === PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION) {
|
||||
return createCpaSessionImportTail;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function createOpenAiSteps(prefixSteps, startId, startOrder, signupMethod = SIGNUP_METHOD_EMAIL, options = {}) {
|
||||
const sessionTailFactory = resolvePlusSessionImportTail(options, signupMethod);
|
||||
const tailSteps = sessionTailFactory
|
||||
? sessionTailFactory(startId, startOrder)
|
||||
: createOpenAiAuthTail(startId, startOrder, signupMethod, options);
|
||||
return [
|
||||
...prefixSteps,
|
||||
...tailSteps,
|
||||
];
|
||||
}
|
||||
|
||||
function createHostedCheckoutAuthTail(startId, startOrder, signupMethod = SIGNUP_METHOD_EMAIL, options = {}) {
|
||||
const id = Number(startId) || 7;
|
||||
const order = Number(startOrder) || id * 10;
|
||||
const commonStart = [
|
||||
{ id, order, key: 'oauth-login', title: '刷新 OAuth 并登录', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'oauth-login' },
|
||||
{ id: id + 1, order: order + 10, key: 'fetch-login-code', title: '获取登录验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-login-code' },
|
||||
];
|
||||
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||
if (isPhoneSignupReloginAfterBindEmailEnabled(options)) {
|
||||
return [
|
||||
...commonStart,
|
||||
{ id: id + 2, order: order + 20, key: 'bind-email', title: '绑定邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'bind-email' },
|
||||
{ id: id + 3, order: order + 30, key: 'fetch-bind-email-code', title: '获取绑定邮箱验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fetch-bind-email-code', mailRuleId: 'openai-login-code' },
|
||||
{ id: id + 4, order: order + 40, key: 'relogin-bound-email', title: '绑定邮箱后刷新 OAuth 并登录(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'oauth-login' },
|
||||
{ id: id + 5, order: order + 50, key: 'fetch-bound-email-login-code', title: '获取登录验证码(邮箱)', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'submit-verification-code', mailRuleId: 'openai-login-code' },
|
||||
{ id: id + 6, order: order + 60, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
|
||||
{ id: id + 7, order: order + 70, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
|
||||
];
|
||||
}
|
||||
return [
|
||||
...commonStart,
|
||||
{ id: id + 2, order: order + 20, key: 'bind-email', title: '绑定邮箱', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'bind-email' },
|
||||
{ id: id + 3, order: order + 30, key: 'fetch-bind-email-code', title: '获取绑定邮箱验证码', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'fetch-bind-email-code', mailRuleId: 'openai-login-code' },
|
||||
{ id: id + 4, order: order + 40, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
|
||||
{ id: id + 5, order: order + 50, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
...commonStart,
|
||||
{ id: id + 2, order: order + 20, key: 'confirm-oauth', title: '自动确认 OAuth', sourceId: 'openai-auth', driverId: 'content/signup-page', command: 'confirm-oauth' },
|
||||
{ id: id + 3, order: order + 30, key: 'platform-verify', title: '平台回调验证', sourceId: 'platform-panel', driverId: 'content/platform-panel', command: 'platform-verify' },
|
||||
];
|
||||
}
|
||||
|
||||
function createHostedCheckoutSteps(prefixSteps, startId, startOrder, signupMethod = SIGNUP_METHOD_EMAIL, options = {}) {
|
||||
const sessionTailFactory = resolvePlusSessionImportTail(options, signupMethod);
|
||||
const tailSteps = sessionTailFactory
|
||||
? sessionTailFactory(startId, startOrder)
|
||||
: createHostedCheckoutAuthTail(startId, startOrder, signupMethod, options);
|
||||
return [
|
||||
...prefixSteps,
|
||||
...tailSteps,
|
||||
];
|
||||
}
|
||||
|
||||
const NORMAL_STEP_DEFINITIONS = createOpenAiSteps(NORMAL_PREFIX_STEP_DEFINITIONS, 7, 70, SIGNUP_METHOD_EMAIL);
|
||||
const NORMAL_PHONE_STEP_DEFINITIONS = createOpenAiSteps(NORMAL_PREFIX_STEP_DEFINITIONS, 7, 70, SIGNUP_METHOD_PHONE);
|
||||
const NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS = createOpenAiSteps(NORMAL_PREFIX_STEP_DEFINITIONS, 7, 70, SIGNUP_METHOD_PHONE, { phoneSignupReloginAfterBindEmailEnabled: true });
|
||||
const PLUS_PAYPAL_STEP_DEFINITIONS = createOpenAiSteps(PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_EMAIL);
|
||||
const PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS = createOpenAiSteps(
|
||||
PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS,
|
||||
10,
|
||||
100,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_PAYPAL_CPA_SESSION_STEP_DEFINITIONS = createOpenAiSteps(
|
||||
PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS,
|
||||
10,
|
||||
100,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_PAYPAL_PHONE_STEP_DEFINITIONS = createOpenAiSteps(PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE);
|
||||
const PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS = createOpenAiSteps(PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE, { phoneSignupReloginAfterBindEmailEnabled: true });
|
||||
const PLUS_PAYPAL_HOSTED_CHECKOUT_STEP_DEFINITIONS = createHostedCheckoutSteps(PLUS_PAYPAL_HOSTED_CHECKOUT_PREFIX_STEP_DEFINITIONS, 11, 110, SIGNUP_METHOD_EMAIL);
|
||||
const PLUS_PAYPAL_HOSTED_CHECKOUT_SUB2API_SESSION_STEP_DEFINITIONS = createHostedCheckoutSteps(
|
||||
PLUS_PAYPAL_HOSTED_CHECKOUT_PREFIX_STEP_DEFINITIONS,
|
||||
11,
|
||||
110,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_PAYPAL_HOSTED_CHECKOUT_CPA_SESSION_STEP_DEFINITIONS = createHostedCheckoutSteps(
|
||||
PLUS_PAYPAL_HOSTED_CHECKOUT_PREFIX_STEP_DEFINITIONS,
|
||||
11,
|
||||
110,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_STEP_DEFINITIONS = createHostedCheckoutSteps(PLUS_PAYPAL_HOSTED_CHECKOUT_PREFIX_STEP_DEFINITIONS, 11, 110, SIGNUP_METHOD_PHONE);
|
||||
const PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS = createHostedCheckoutSteps(PLUS_PAYPAL_HOSTED_CHECKOUT_PREFIX_STEP_DEFINITIONS, 11, 110, SIGNUP_METHOD_PHONE, { phoneSignupReloginAfterBindEmailEnabled: true });
|
||||
const PLUS_GOPAY_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GOPAY_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_EMAIL);
|
||||
const PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS = createOpenAiSteps(
|
||||
PLUS_GOPAY_PREFIX_STEP_DEFINITIONS,
|
||||
10,
|
||||
100,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_GOPAY_CPA_SESSION_STEP_DEFINITIONS = createOpenAiSteps(
|
||||
PLUS_GOPAY_PREFIX_STEP_DEFINITIONS,
|
||||
10,
|
||||
100,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_GOPAY_PHONE_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GOPAY_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE);
|
||||
const PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GOPAY_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE, { phoneSignupReloginAfterBindEmailEnabled: true });
|
||||
const PLUS_GPC_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GPC_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_EMAIL);
|
||||
const PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS = createOpenAiSteps(
|
||||
PLUS_GPC_PREFIX_STEP_DEFINITIONS,
|
||||
10,
|
||||
100,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_GPC_CPA_SESSION_STEP_DEFINITIONS = createOpenAiSteps(
|
||||
PLUS_GPC_PREFIX_STEP_DEFINITIONS,
|
||||
10,
|
||||
100,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
{ plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION }
|
||||
);
|
||||
const PLUS_GPC_PHONE_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GPC_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE);
|
||||
const PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GPC_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE, { phoneSignupReloginAfterBindEmailEnabled: true });
|
||||
const KIRO_STEP_DEFINITIONS = [
|
||||
{
|
||||
id: 1,
|
||||
order: 10,
|
||||
key: 'kiro-open-register-page',
|
||||
title: '打开注册页',
|
||||
sourceId: 'kiro-register-page',
|
||||
driverId: 'background/kiro-register',
|
||||
command: 'kiro-open-register-page',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
order: 20,
|
||||
key: 'kiro-submit-email',
|
||||
title: '获取邮箱并继续',
|
||||
sourceId: 'kiro-register-page',
|
||||
driverId: 'background/kiro-register',
|
||||
command: 'kiro-submit-email',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
order: 30,
|
||||
key: 'kiro-submit-name',
|
||||
title: '填写姓名并继续',
|
||||
sourceId: 'kiro-register-page',
|
||||
driverId: 'background/kiro-register',
|
||||
command: 'kiro-submit-name',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
order: 40,
|
||||
key: 'kiro-submit-verification-code',
|
||||
title: '获取验证码并继续',
|
||||
sourceId: 'kiro-register-page',
|
||||
driverId: 'background/kiro-register',
|
||||
command: 'kiro-submit-verification-code',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
order: 50,
|
||||
key: 'kiro-submit-password',
|
||||
title: '设置密码并继续',
|
||||
sourceId: 'kiro-register-page',
|
||||
driverId: 'background/kiro-register',
|
||||
command: 'kiro-submit-password',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
order: 60,
|
||||
key: 'kiro-complete-register-consent',
|
||||
title: '完成注册授权',
|
||||
sourceId: 'kiro-register-page',
|
||||
driverId: 'background/kiro-register',
|
||||
command: 'kiro-complete-register-consent',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
order: 70,
|
||||
key: 'kiro-start-desktop-authorize',
|
||||
title: '启动桌面授权',
|
||||
sourceId: 'kiro-desktop-authorize',
|
||||
driverId: 'background/kiro-desktop-authorize',
|
||||
command: 'kiro-start-desktop-authorize',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
order: 80,
|
||||
key: 'kiro-complete-desktop-authorize',
|
||||
title: '完成桌面授权',
|
||||
sourceId: 'kiro-desktop-authorize',
|
||||
driverId: 'background/kiro-desktop-authorize',
|
||||
command: 'kiro-complete-desktop-authorize',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
order: 90,
|
||||
key: 'kiro-upload-credential',
|
||||
title: '上传凭据到 kiro.rs',
|
||||
sourceId: 'kiro-rs-admin',
|
||||
driverId: 'background/kiro-publisher-kiro-rs',
|
||||
command: 'kiro-upload-credential',
|
||||
},
|
||||
];
|
||||
|
||||
const PHONE_SIGNUP_TITLE_OVERRIDES = Object.freeze({
|
||||
'submit-signup-email': '注册并输入手机号',
|
||||
'fetch-signup-code': '获取手机验证码',
|
||||
});
|
||||
const KIRO_CONTRIBUTION_STEP_TITLE = '贡献上传';
|
||||
|
||||
function isPlusModeEnabled(options = {}) {
|
||||
return Boolean(options?.plusModeEnabled || options?.plusMode);
|
||||
}
|
||||
|
||||
function normalizePlusPaymentMethod(value = '') {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === PLUS_PAYMENT_METHOD_PAYPAL_HOSTED || normalized === 'paypal_direct' || normalized === 'paypal-direct') {
|
||||
return PLUS_PAYMENT_METHOD_PAYPAL_HOSTED;
|
||||
}
|
||||
if (normalized === PLUS_PAYMENT_METHOD_GPC_HELPER) {
|
||||
return PLUS_PAYMENT_METHOD_GPC_HELPER;
|
||||
}
|
||||
return normalized === PLUS_PAYMENT_METHOD_GOPAY ? PLUS_PAYMENT_METHOD_GOPAY : PLUS_PAYMENT_METHOD_PAYPAL;
|
||||
}
|
||||
|
||||
function normalizeSignupMethod(value = '') {
|
||||
return String(value || '').trim().toLowerCase() === SIGNUP_METHOD_PHONE
|
||||
? SIGNUP_METHOD_PHONE
|
||||
: SIGNUP_METHOD_EMAIL;
|
||||
function hasFlow(flowId) {
|
||||
return Boolean(getFlowWorkflow(flowId));
|
||||
}
|
||||
|
||||
function normalizeActiveFlowId(value = '', fallback = DEFAULT_ACTIVE_FLOW_ID) {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized) {
|
||||
if (hasFlow(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
const fallbackValue = String(fallback || '').trim().toLowerCase();
|
||||
return fallbackValue || DEFAULT_ACTIVE_FLOW_ID;
|
||||
if (hasFlow(fallbackValue)) {
|
||||
return fallbackValue;
|
||||
}
|
||||
return getRegisteredFlowIds()[0] || DEFAULT_ACTIVE_FLOW_ID;
|
||||
}
|
||||
|
||||
function getResolvedSignupMethod(options = {}) {
|
||||
return normalizeSignupMethod(options?.resolvedSignupMethod || options?.signupMethod);
|
||||
}
|
||||
|
||||
function getOpenAiModeStepDefinitions(options = {}) {
|
||||
const signupMethod = getResolvedSignupMethod(options);
|
||||
const reloginAfterBindEmail = signupMethod === SIGNUP_METHOD_PHONE
|
||||
&& isPhoneSignupReloginAfterBindEmailEnabled(options);
|
||||
if (!isPlusModeEnabled(options)) {
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||
return reloginAfterBindEmail
|
||||
? NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||
: NORMAL_PHONE_STEP_DEFINITIONS;
|
||||
}
|
||||
return NORMAL_STEP_DEFINITIONS;
|
||||
}
|
||||
const paymentMethod = normalizePlusPaymentMethod(options?.plusPaymentMethod || options?.paymentMethod);
|
||||
const plusAccountAccessStrategy = normalizePlusAccountAccessStrategy(options?.plusAccountAccessStrategy);
|
||||
if (paymentMethod === PLUS_PAYMENT_METHOD_PAYPAL_HOSTED) {
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||
return reloginAfterBindEmail
|
||||
? PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||
: PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||
return PLUS_PAYPAL_HOSTED_CHECKOUT_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION) {
|
||||
return PLUS_PAYPAL_HOSTED_CHECKOUT_CPA_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
return PLUS_PAYPAL_HOSTED_CHECKOUT_STEP_DEFINITIONS;
|
||||
}
|
||||
if (paymentMethod === PLUS_PAYMENT_METHOD_GPC_HELPER) {
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||
return reloginAfterBindEmail
|
||||
? PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||
: PLUS_GPC_PHONE_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||
return PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION) {
|
||||
return PLUS_GPC_CPA_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
return PLUS_GPC_STEP_DEFINITIONS;
|
||||
}
|
||||
if (paymentMethod === PLUS_PAYMENT_METHOD_GOPAY) {
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||
return reloginAfterBindEmail
|
||||
? PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||
: PLUS_GOPAY_PHONE_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||
return PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION) {
|
||||
return PLUS_GOPAY_CPA_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
return PLUS_GOPAY_STEP_DEFINITIONS;
|
||||
}
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||
return reloginAfterBindEmail
|
||||
? PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||
: PLUS_PAYPAL_PHONE_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||
return PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION) {
|
||||
return PLUS_PAYPAL_CPA_SESSION_STEP_DEFINITIONS;
|
||||
}
|
||||
return PLUS_PAYPAL_STEP_DEFINITIONS;
|
||||
}
|
||||
|
||||
function getOpenAiPlusPaymentStepTitle(options = {}) {
|
||||
if (!isPlusModeEnabled(options)) {
|
||||
return '';
|
||||
}
|
||||
const paymentStep = getOpenAiModeStepDefinitions({
|
||||
...options,
|
||||
plusModeEnabled: true,
|
||||
}).find((step) => step.key === PLUS_PAYMENT_STEP_KEY);
|
||||
return paymentStep?.title || '';
|
||||
}
|
||||
|
||||
function getOpenAiResolvedStepTitle(step = {}, options = {}) {
|
||||
if (isPlusModeEnabled(options) && step.key === PLUS_PAYMENT_STEP_KEY) {
|
||||
return getOpenAiPlusPaymentStepTitle(options) || step.title;
|
||||
}
|
||||
const signupMethod = getResolvedSignupMethod(options);
|
||||
if (signupMethod === SIGNUP_METHOD_PHONE && PHONE_SIGNUP_TITLE_OVERRIDES[step.key]) {
|
||||
return PHONE_SIGNUP_TITLE_OVERRIDES[step.key];
|
||||
}
|
||||
return step.title;
|
||||
}
|
||||
|
||||
function isKiroContributionModeEnabled(options = {}) {
|
||||
return Boolean(options?.accountContributionEnabled || options?.state?.accountContributionEnabled);
|
||||
}
|
||||
|
||||
const FLOW_DEFINITION_BUILDERS = Object.freeze({
|
||||
openai: {
|
||||
getAllSteps() {
|
||||
const keyed = new Map();
|
||||
for (const step of [
|
||||
...NORMAL_STEP_DEFINITIONS,
|
||||
...NORMAL_PHONE_STEP_DEFINITIONS,
|
||||
...NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_CPA_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_HOSTED_CHECKOUT_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_HOSTED_CHECKOUT_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_HOSTED_CHECKOUT_CPA_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_STEP_DEFINITIONS,
|
||||
...PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
...PLUS_GOPAY_STEP_DEFINITIONS,
|
||||
...PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_GOPAY_CPA_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
||||
...PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
...PLUS_GPC_STEP_DEFINITIONS,
|
||||
...PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_GPC_CPA_SESSION_STEP_DEFINITIONS,
|
||||
...PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
||||
...PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
]) {
|
||||
keyed.set(`${step.id}:${step.key}`, step);
|
||||
}
|
||||
return Array.from(keyed.values()).sort((left, right) => {
|
||||
const leftOrder = Number.isFinite(left.order) ? left.order : left.id;
|
||||
const rightOrder = Number.isFinite(right.order) ? right.order : right.id;
|
||||
if (leftOrder !== rightOrder) return leftOrder - rightOrder;
|
||||
return left.id - right.id;
|
||||
});
|
||||
},
|
||||
getModeStepDefinitions: getOpenAiModeStepDefinitions,
|
||||
getPlusPaymentStepTitle: getOpenAiPlusPaymentStepTitle,
|
||||
resolveStepTitle: getOpenAiResolvedStepTitle,
|
||||
},
|
||||
kiro: {
|
||||
getAllSteps() {
|
||||
return KIRO_STEP_DEFINITIONS;
|
||||
},
|
||||
getModeStepDefinitions() {
|
||||
return KIRO_STEP_DEFINITIONS;
|
||||
},
|
||||
getPlusPaymentStepTitle() {
|
||||
return '';
|
||||
},
|
||||
resolveStepTitle(step, options = {}) {
|
||||
if (step?.key === 'kiro-upload-credential' && isKiroContributionModeEnabled(options)) {
|
||||
return KIRO_CONTRIBUTION_STEP_TITLE;
|
||||
}
|
||||
return step?.title || '';
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function hasFlow(flowId) {
|
||||
const normalizedFlowId = normalizeActiveFlowId(flowId, '');
|
||||
return Boolean(normalizedFlowId && FLOW_DEFINITION_BUILDERS[normalizedFlowId]);
|
||||
}
|
||||
|
||||
function getRegisteredFlowIds() {
|
||||
return Object.keys(FLOW_DEFINITION_BUILDERS);
|
||||
function hasExplicitActiveFlowId(options = {}) {
|
||||
return Boolean(
|
||||
options
|
||||
&& typeof options === 'object'
|
||||
&& Object.prototype.hasOwnProperty.call(options, 'activeFlowId')
|
||||
&& String(options.activeFlowId || '').trim()
|
||||
);
|
||||
}
|
||||
|
||||
function getFlowDefinitionBuilder(options = {}) {
|
||||
const flowId = normalizeActiveFlowId(options?.activeFlowId, DEFAULT_ACTIVE_FLOW_ID);
|
||||
const rawFlowId = String(options?.activeFlowId || '').trim().toLowerCase();
|
||||
if (hasExplicitActiveFlowId(options) && rawFlowId && !hasFlow(rawFlowId)) {
|
||||
return {
|
||||
flowId: rawFlowId,
|
||||
builder: null,
|
||||
};
|
||||
}
|
||||
const flowId = normalizeActiveFlowId(rawFlowId, DEFAULT_ACTIVE_FLOW_ID);
|
||||
return {
|
||||
flowId,
|
||||
builder: FLOW_DEFINITION_BUILDERS[flowId] || null,
|
||||
builder: getFlowWorkflow(flowId),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -656,7 +147,9 @@
|
||||
}
|
||||
return cloneNodes(builder.getAllSteps(options), options, flowId)
|
||||
.sort((left, right) => {
|
||||
if (left.displayOrder !== right.displayOrder) return left.displayOrder - right.displayOrder;
|
||||
if (left.displayOrder !== right.displayOrder) {
|
||||
return left.displayOrder - right.displayOrder;
|
||||
}
|
||||
return left.nodeId.localeCompare(right.nodeId);
|
||||
});
|
||||
}
|
||||
@@ -712,7 +205,7 @@
|
||||
}
|
||||
|
||||
function getWorkflow(options = {}) {
|
||||
const flowId = normalizeActiveFlowId(options?.activeFlowId, DEFAULT_ACTIVE_FLOW_ID);
|
||||
const { flowId } = getFlowDefinitionBuilder(options);
|
||||
const nodes = getNodes(options);
|
||||
return {
|
||||
flowId,
|
||||
@@ -722,34 +215,32 @@
|
||||
};
|
||||
}
|
||||
|
||||
const defaultWorkflowBuilder = getFlowWorkflow(DEFAULT_ACTIVE_FLOW_ID);
|
||||
const STEP_DEFINITIONS = cloneSteps(
|
||||
defaultWorkflowBuilder?.getVariantStepDefinitions
|
||||
? defaultWorkflowBuilder.getVariantStepDefinitions('normal')
|
||||
: (defaultWorkflowBuilder?.getModeStepDefinitions?.({ activeFlowId: DEFAULT_ACTIVE_FLOW_ID }) || []),
|
||||
{},
|
||||
DEFAULT_ACTIVE_FLOW_ID
|
||||
);
|
||||
const NORMAL_STEP_DEFINITIONS = STEP_DEFINITIONS;
|
||||
const PLUS_STEP_DEFINITIONS = cloneSteps(
|
||||
defaultWorkflowBuilder?.getVariantStepDefinitions
|
||||
? defaultWorkflowBuilder.getVariantStepDefinitions('plusPaypal')
|
||||
: [],
|
||||
{ plusModeEnabled: true },
|
||||
DEFAULT_ACTIVE_FLOW_ID
|
||||
);
|
||||
|
||||
return {
|
||||
DEFAULT_ACTIVE_FLOW_ID,
|
||||
STEP_DEFINITIONS: NORMAL_STEP_DEFINITIONS,
|
||||
NORMAL_STEP_DEFINITIONS,
|
||||
NORMAL_PHONE_STEP_DEFINITIONS,
|
||||
NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
PLUS_STEP_DEFINITIONS: PLUS_PAYPAL_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_HOSTED_CHECKOUT_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_HOSTED_CHECKOUT_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_HOSTED_CHECKOUT_CPA_SESSION_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_STEP_DEFINITIONS,
|
||||
PLUS_PAYPAL_HOSTED_CHECKOUT_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
PLUS_GOPAY_STEP_DEFINITIONS,
|
||||
PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
||||
PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
PLUS_GPC_STEP_DEFINITIONS,
|
||||
PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||
PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
||||
PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||
PLUS_STEP_DEFINITIONS,
|
||||
SIGNUP_METHOD_EMAIL,
|
||||
SIGNUP_METHOD_PHONE,
|
||||
getAllSteps,
|
||||
STEP_DEFINITIONS,
|
||||
getAllNodes,
|
||||
getAllSteps,
|
||||
getLastStepId,
|
||||
getNodeByDisplayOrder,
|
||||
getNodeById,
|
||||
@@ -762,9 +253,6 @@
|
||||
getSteps,
|
||||
getWorkflow,
|
||||
hasFlow,
|
||||
isPlusModeEnabled,
|
||||
normalizeActiveFlowId,
|
||||
normalizePlusPaymentMethod,
|
||||
normalizeSignupMethod,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 步骤与Flow节点化重构开发方案
|
||||
# 步骤与Flow节点化重构开发方案
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
@@ -19,17 +19,17 @@
|
||||
| --- | --- | --- |
|
||||
| 状态 | `background.js` 里仍有 `currentStep`、`stepStatuses` | 数字步骤同时承担状态、顺序和恢复锚点 |
|
||||
| 协议 | `EXECUTE_STEP`、`STEP_COMPLETE`、`STEP_ERROR`、`SKIP_STEP` | 消息协议仍以数字 step 为核心 |
|
||||
| 定义 | `data/step-definitions.js`、`background/steps/registry.js` | 只有 OpenAI 真正注册,且执行仍按数字 id |
|
||||
| 定义 | `data/step-definitions.js`、`core/flow-kernel/step-registry.js` | 只有 OpenAI 真正注册,且执行仍按数字 id |
|
||||
| UI | `sidepanel/sidepanel.js` 按 step 渲染、发送、跳过 | 侧边栏本质上还是数字步骤面板 |
|
||||
| 内容脚本 | `content/signup-page.js` 按 `message.step` 分支 | 页面驱动逻辑被 step number 绑死 |
|
||||
| 运行态 | `background/runtime-state.js` 已有 `currentNodeId`、`nodeStatuses` | 但仍通过 legacy step 视图回写,双模型并存 |
|
||||
| 外围能力 | `shared/source-registry.js`、`shared/flow-capabilities.js`、`background/mail-rule-registry.js` | 已有抽象,但都还没成为唯一事实来源 |
|
||||
| 内容脚本 | `flows/openai/content/openai-auth.js` 按 `message.step` 分支 | 页面驱动逻辑被 step number 绑死 |
|
||||
| 运行态 | `core/flow-kernel/runtime-state.js` 已有 `currentNodeId`、`nodeStatuses` | 但仍通过 legacy step 视图回写,双模型并存 |
|
||||
| 外围能力 | `core/flow-kernel/source-registry.js`、`core/flow-kernel/flow-capabilities.js`、`background/mail-rule-registry.js` | 已有抽象,但都还没成为唯一事实来源 |
|
||||
|
||||
重点文件里最能说明问题的几个点:
|
||||
|
||||
- `background.js`:`DEFAULT_STATE`、`setStepStatus()`、`skipStep()`、`runAutoSequenceFromStep()`、`getStepRegistryForState()` 仍把数字 step 当主流程。
|
||||
- `background/message-router.js`:`STEP_COMPLETE` / `STEP_ERROR` / `EXECUTE_STEP` / `SKIP_STEP` 还在消息层面锁死 step。
|
||||
- `background/runtime-state.js`:已经有 node 相关字段,但还在做 step 兼容派生。
|
||||
- `core/flow-kernel/runtime-state.js`:已经有 node 相关字段,但还在做 step 兼容派生。
|
||||
- `sidepanel/sidepanel.js`:步骤列表、状态展示、手动执行、跳过、自动运行都还围着 step。
|
||||
- `flows/openai/mail-rules.js`、`background/mail-rule-registry.js`:已经说明“规则可以 flow 化”,但目前只有 OpenAI 在用。
|
||||
|
||||
@@ -164,7 +164,7 @@ node = {
|
||||
type: 'task',
|
||||
order: 20, // 仅用于展示,不参与身份
|
||||
sourceId: 'openai-auth',
|
||||
driverId: 'content/signup-page',
|
||||
driverId: 'flows/openai/content/openai-auth',
|
||||
next: ['fill-password'],
|
||||
retryPolicy: { maxAttempts: 3 },
|
||||
recoveryPolicy: { onFailure: 'restart-node' },
|
||||
@@ -241,11 +241,11 @@ flows/<flowId>/
|
||||
|
||||
### 6.3 content scripts
|
||||
|
||||
`content/signup-page.js` 这类脚本要从“按 step 分支”改成“按 node action / command 分支”。
|
||||
`flows/openai/content/openai-auth.js` 这类脚本要从“按 step 分支”改成“按 node action / command 分支”。
|
||||
|
||||
### 6.4 source / driver
|
||||
|
||||
`shared/source-registry.js` 只负责页面来源、标签页生命周期和注入范围。
|
||||
`core/flow-kernel/source-registry.js` 只负责页面来源、标签页生命周期和注入范围。
|
||||
|
||||
`driverRegistry` 只负责“这个 source 能接什么命令”。
|
||||
|
||||
@@ -378,3 +378,4 @@ flows/<flowId>/
|
||||
- 邮件规则是否只从当前 flow definition 派生。
|
||||
- sidepanel 是否能仅通过 workflow nodes 渲染,不新增全局步骤 switch。
|
||||
- 自动运行、历史和日志是否都能用 `flowId/runId/nodeId` 定位。
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -94,9 +94,9 @@
|
||||
|
||||
文件:
|
||||
|
||||
1. `background/kiro/state.js`
|
||||
2. `background/kiro/desktop-authorize-runner.js`
|
||||
3. `background/kiro/publisher-kiro-rs.js`
|
||||
1. `flows/kiro/background/state.js`
|
||||
2. `flows/kiro/background/desktop-authorize-runner.js`
|
||||
3. `flows/kiro/background/publisher-kiro-rs.js`
|
||||
4. `data/step-definitions.js`
|
||||
|
||||
当前事实:
|
||||
@@ -434,7 +434,7 @@ const FLOW_CONTRIBUTION_ADAPTERS = {
|
||||
};
|
||||
```
|
||||
|
||||
### 4.2 修改 `shared/flow-registry.js`
|
||||
### 4.2 修改 `core/flow-kernel/flow-registry.js`
|
||||
|
||||
新增 capability:
|
||||
|
||||
@@ -449,7 +449,7 @@ supportsAccountContribution: true
|
||||
3. `supportsContributionMode` 仅作为迁移字段映射到 `supportsAccountContribution`。
|
||||
4. 新增 flow 只有在注册 adapter 后才能设置 `supportsAccountContribution: true`。
|
||||
|
||||
### 4.3 修改 `shared/flow-capabilities.js`
|
||||
### 4.3 修改 `core/flow-kernel/flow-capabilities.js`
|
||||
|
||||
处理规则:
|
||||
|
||||
@@ -499,7 +499,7 @@ flowContributionRuntime: {
|
||||
新增文件:
|
||||
|
||||
```text
|
||||
background/kiro/credential-artifact.js
|
||||
flows/kiro/background/credential-artifact.js
|
||||
```
|
||||
|
||||
职责:
|
||||
@@ -515,8 +515,8 @@ background/kiro/credential-artifact.js
|
||||
|
||||
修改位置:
|
||||
|
||||
1. `background/kiro/desktop-authorize-runner.js`
|
||||
2. `background/kiro/publisher-kiro-rs.js`
|
||||
1. `flows/kiro/background/desktop-authorize-runner.js`
|
||||
2. `flows/kiro/background/publisher-kiro-rs.js`
|
||||
3. Kiro runner 调度处
|
||||
|
||||
处理规则:
|
||||
@@ -782,7 +782,7 @@ POLL_FLOW_CONTRIBUTION_STATUS
|
||||
|
||||
开发内容:
|
||||
|
||||
1. 新增 `background/kiro/credential-artifact.js`。
|
||||
1. 新增 `flows/kiro/background/credential-artifact.js`。
|
||||
2. 新增 `background/contribution/adapters/kiro-builder-id.js`。
|
||||
3. 复用 Kiro runtime 产物构建 artifact。
|
||||
4. 增加本地校验。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 多注册流程来源与驱动注册设计
|
||||
# 多注册流程来源与驱动注册设计
|
||||
|
||||
本文解决的是另一个会在第二个 flow 接入时立刻爆炸的问题:当前项目虽然有 `tab-runtime`,但“来源 source 是谁、该注入什么脚本、URL family 怎么判定、localhost callback 应该清谁”仍然带着明显的 OpenAI 单流程假设。
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
- `content/utils.js` 的 `detectScriptSource()`
|
||||
- `background/navigation-utils.js` 的 `matchesSourceUrlFamily()`
|
||||
- `background/tab-runtime.js` 的注册表、冲突清理、callback 清理
|
||||
- `core/flow-kernel/tab-runtime.js` 的注册表、冲突清理、callback 清理
|
||||
|
||||
这说明当前的 source 体系不是“可扩展的来源注册表”,而是“OpenAI 时代遗留的 source 命名”。
|
||||
|
||||
@@ -58,10 +58,10 @@ sourceRegistry = {
|
||||
'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',
|
||||
'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'],
|
||||
},
|
||||
@@ -81,7 +81,7 @@ sourceRegistry = {
|
||||
label: 'SUB2API 后台',
|
||||
dynamicOnly: true,
|
||||
familyMatcher: 'sub2api-panel-family',
|
||||
injectFiles: ['content/utils.js', 'content/sub2api-panel.js'],
|
||||
injectFiles: ['content/utils.js', 'flows/openai/content/sub2api-panel.js'],
|
||||
},
|
||||
};
|
||||
```
|
||||
@@ -125,7 +125,7 @@ sourceRegistry = {
|
||||
driverRegistry = {
|
||||
'openai-auth': {
|
||||
sourceId: 'openai-auth',
|
||||
driverId: 'content/signup-page',
|
||||
driverId: 'flows/openai/content/openai-auth',
|
||||
commands: [
|
||||
'OPEN_SIGNUP',
|
||||
'SUBMIT_SIGNUP_IDENTIFIER',
|
||||
@@ -244,3 +244,4 @@ callbackRegistry = {
|
||||
- manifest 与动态注入没有统一入口
|
||||
- `content/utils.js` 的默认 source 回退会污染未来 flow
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -77,8 +77,8 @@ flows/
|
||||
- `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`
|
||||
- `flows/openai/content/phone-auth.js`
|
||||
- `flows/openai/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`
|
||||
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
定义:不离开当前步骤,在当前页面链路内恢复或替换资源。
|
||||
|
||||
典型位置:
|
||||
- `background/steps/fetch-signup-code.js`(步骤 4 页面恢复)
|
||||
- `background/steps/fetch-login-code.js` + `background/verification-flow.js`(步骤 8 邮箱轮询与重发)
|
||||
- `flows/openai/background/steps/fetch-signup-code.js`(步骤 4 页面恢复)
|
||||
- `flows/openai/background/steps/fetch-login-code.js` + `background/verification-flow.js`(步骤 8 邮箱轮询与重发)
|
||||
- `background/phone-verification-flow.js`(步骤 9 号码轮换、重发、回到 add-phone)
|
||||
|
||||
常见动作:
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
(function attachMultiPageFlowsIndex(root, factory) {
|
||||
root.MultiPageFlowsIndex = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createFlowsIndexModule() {
|
||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||
|
||||
const FLOW_ENTRY_DEFINITIONS = Object.freeze({
|
||||
openai: {
|
||||
id: 'openai',
|
||||
path: 'flows/openai/',
|
||||
},
|
||||
kiro: {
|
||||
id: 'kiro',
|
||||
path: 'flows/kiro/',
|
||||
},
|
||||
});
|
||||
|
||||
function normalizeFlowId(value = '') {
|
||||
return String(value || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function getRegisteredFlowIds() {
|
||||
return Object.keys(FLOW_ENTRY_DEFINITIONS);
|
||||
}
|
||||
|
||||
function getFlowEntry(flowId) {
|
||||
const normalized = normalizeFlowId(flowId);
|
||||
const baseEntry = FLOW_ENTRY_DEFINITIONS[normalized];
|
||||
if (!baseEntry) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
...baseEntry,
|
||||
definition: normalized === 'openai'
|
||||
? (rootScope.MultiPageOpenAiFlowDefinition || null)
|
||||
: (rootScope.MultiPageKiroFlowDefinition || null),
|
||||
workflow: normalized === 'openai'
|
||||
? (rootScope.MultiPageOpenAiWorkflow || null)
|
||||
: (rootScope.MultiPageKiroWorkflow || null),
|
||||
};
|
||||
}
|
||||
|
||||
function getFlowDefinition(flowId) {
|
||||
return getFlowEntry(flowId)?.definition || null;
|
||||
}
|
||||
|
||||
function getFlowDefinitions() {
|
||||
const next = {};
|
||||
getRegisteredFlowIds().forEach((flowId) => {
|
||||
const definition = getFlowDefinition(flowId);
|
||||
if (definition) {
|
||||
next[flowId] = definition;
|
||||
}
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
function getFlowWorkflow(flowId) {
|
||||
return getFlowEntry(flowId)?.workflow || null;
|
||||
}
|
||||
|
||||
return {
|
||||
getFlowEntry,
|
||||
getFlowDefinition,
|
||||
getFlowDefinitions,
|
||||
getFlowWorkflow,
|
||||
getRegisteredFlowIds,
|
||||
};
|
||||
});
|
||||
+5
-5
@@ -20,14 +20,15 @@
|
||||
function readKiroRuntime(state = {}) {
|
||||
return kiroStateApi?.ensureRuntimeState
|
||||
? kiroStateApi.ensureRuntimeState(state)
|
||||
: (isPlainObject(state?.kiroRuntime) ? state.kiroRuntime : {});
|
||||
: (isPlainObject(state?.runtimeState?.flowState?.kiro)
|
||||
? state.runtimeState.flowState.kiro
|
||||
: (isPlainObject(state?.flowState?.kiro) ? state.flowState.kiro : {}));
|
||||
}
|
||||
|
||||
function resolveKiroTargetId(state = {}, runtimeState = readKiroRuntime(state)) {
|
||||
return cleanString(
|
||||
state?.settingsState?.flows?.kiro?.targetId
|
||||
|| state?.flows?.kiro?.targetId
|
||||
|| state?.kiroTargetId
|
||||
state?.settingsState?.flows?.kiro?.selectedTargetId
|
||||
|| state?.targetId
|
||||
|| runtimeState?.upload?.targetId
|
||||
|| DEFAULT_TARGET_ID
|
||||
) || DEFAULT_TARGET_ID;
|
||||
@@ -46,7 +47,6 @@
|
||||
return cleanString(
|
||||
runtimeState?.desktopAuth?.region
|
||||
|| state?.settingsState?.flows?.kiro?.targets?.[targetId]?.region
|
||||
|| state?.flows?.kiro?.targets?.[targetId]?.region
|
||||
|| DEFAULT_REGION
|
||||
) || DEFAULT_REGION;
|
||||
}
|
||||
+27
-3
@@ -97,16 +97,40 @@
|
||||
typeof kiroStateApi?.buildDefaultRuntimeState === 'function'
|
||||
? kiroStateApi.buildDefaultRuntimeState()
|
||||
: {},
|
||||
state?.kiroRuntime || {}
|
||||
isPlainObject(state?.runtimeState?.flowState?.kiro)
|
||||
? state.runtimeState.flowState.kiro
|
||||
: (isPlainObject(state?.flowState?.kiro) ? state.flowState.kiro : {})
|
||||
);
|
||||
}
|
||||
|
||||
function mergeRuntimePatch(currentState = {}, patch = {}) {
|
||||
function buildCanonicalRuntimePatch(currentState = {}, nextRuntimeState = {}) {
|
||||
if (typeof kiroStateApi?.buildRuntimeStatePatch === 'function') {
|
||||
return kiroStateApi.buildRuntimeStatePatch(currentState, nextRuntimeState);
|
||||
}
|
||||
const baseRuntimeState = isPlainObject(currentState?.runtimeState)
|
||||
? cloneValue(currentState.runtimeState)
|
||||
: {};
|
||||
const baseFlowState = isPlainObject(baseRuntimeState.flowState)
|
||||
? cloneValue(baseRuntimeState.flowState)
|
||||
: {};
|
||||
return {
|
||||
kiroRuntime: deepMerge(readKiroRuntime(currentState), patch),
|
||||
runtimeState: {
|
||||
...baseRuntimeState,
|
||||
flowState: {
|
||||
...baseFlowState,
|
||||
kiro: deepMerge(readKiroRuntime(currentState), nextRuntimeState),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function mergeRuntimePatch(currentState = {}, patch = {}) {
|
||||
return buildCanonicalRuntimePatch(
|
||||
currentState,
|
||||
deepMerge(readKiroRuntime(currentState), patch)
|
||||
);
|
||||
}
|
||||
|
||||
function normalizePositiveInteger(value, fallback) {
|
||||
const numeric = Math.floor(Number(value));
|
||||
if (Number.isInteger(numeric) && numeric > 0) {
|
||||
@@ -108,20 +108,43 @@
|
||||
function readKiroRuntime(state = {}) {
|
||||
return kiroStateApi?.ensureRuntimeState
|
||||
? kiroStateApi.ensureRuntimeState(state)
|
||||
: (isPlainObject(state?.kiroRuntime) ? state.kiroRuntime : {});
|
||||
: (isPlainObject(state?.runtimeState?.flowState?.kiro)
|
||||
? state.runtimeState.flowState.kiro
|
||||
: (isPlainObject(state?.flowState?.kiro) ? state.flowState.kiro : {}));
|
||||
}
|
||||
|
||||
function buildCanonicalRuntimePatch(currentState = {}, nextRuntimeState = {}) {
|
||||
if (typeof kiroStateApi?.buildRuntimeStatePatch === 'function') {
|
||||
return kiroStateApi.buildRuntimeStatePatch(currentState, nextRuntimeState);
|
||||
}
|
||||
const baseRuntimeState = isPlainObject(currentState?.runtimeState)
|
||||
? cloneValue(currentState.runtimeState)
|
||||
: {};
|
||||
const baseFlowState = isPlainObject(baseRuntimeState.flowState)
|
||||
? cloneValue(baseRuntimeState.flowState)
|
||||
: {};
|
||||
return {
|
||||
runtimeState: {
|
||||
...baseRuntimeState,
|
||||
flowState: {
|
||||
...baseFlowState,
|
||||
kiro: deepMerge(readKiroRuntime(currentState), nextRuntimeState),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function mergeRuntimePatch(currentState = {}, patch = {}) {
|
||||
return {
|
||||
kiroRuntime: deepMerge(readKiroRuntime(currentState), patch),
|
||||
};
|
||||
return buildCanonicalRuntimePatch(
|
||||
currentState,
|
||||
deepMerge(readKiroRuntime(currentState), patch)
|
||||
);
|
||||
}
|
||||
|
||||
function resolveKiroTargetId(state = {}) {
|
||||
return cleanString(
|
||||
state?.settingsState?.flows?.kiro?.targetId
|
||||
|| state?.flows?.kiro?.targetId
|
||||
|| state?.kiroTargetId
|
||||
state?.settingsState?.flows?.kiro?.selectedTargetId
|
||||
|| state?.targetId
|
||||
|| readKiroRuntime(state).upload?.targetId
|
||||
|| DEFAULT_TARGET_ID
|
||||
) || DEFAULT_TARGET_ID;
|
||||
@@ -131,9 +154,7 @@
|
||||
if (targetId !== DEFAULT_TARGET_ID) {
|
||||
throw new Error(`暂不支持 Kiro 发布目标:${targetId}`);
|
||||
}
|
||||
const nestedConfig = state?.settingsState?.flows?.kiro?.targets?.[targetId]
|
||||
|| state?.flows?.kiro?.targets?.[targetId]
|
||||
|| {};
|
||||
const nestedConfig = state?.settingsState?.flows?.kiro?.targets?.[targetId] || {};
|
||||
return {
|
||||
baseUrl: cleanString(nestedConfig.baseUrl || state?.kiroRsUrl),
|
||||
apiKey: normalizeKiroRsApiKey(nestedConfig.apiKey ?? state?.kiroRsKey ?? ''),
|
||||
@@ -188,7 +209,6 @@
|
||||
const region = normalizeRegion(
|
||||
desktopAuth.region
|
||||
|| state?.settingsState?.flows?.kiro?.targets?.[targetId]?.region
|
||||
|| state?.flows?.kiro?.targets?.[targetId]?.region
|
||||
|| DEFAULT_REGION
|
||||
);
|
||||
const email = cleanString(register.email || state?.email);
|
||||
@@ -195,16 +195,40 @@
|
||||
typeof kiroStateApi?.buildDefaultRuntimeState === 'function'
|
||||
? kiroStateApi.buildDefaultRuntimeState()
|
||||
: {},
|
||||
state?.kiroRuntime || {}
|
||||
isPlainObject(state?.runtimeState?.flowState?.kiro)
|
||||
? state.runtimeState.flowState.kiro
|
||||
: (isPlainObject(state?.flowState?.kiro) ? state.flowState.kiro : {})
|
||||
);
|
||||
}
|
||||
|
||||
function mergeRuntimePatch(currentState = {}, patch = {}) {
|
||||
function buildCanonicalRuntimePatch(currentState = {}, nextRuntimeState = {}) {
|
||||
if (typeof kiroStateApi?.buildRuntimeStatePatch === 'function') {
|
||||
return kiroStateApi.buildRuntimeStatePatch(currentState, nextRuntimeState);
|
||||
}
|
||||
const baseRuntimeState = isPlainObject(currentState?.runtimeState)
|
||||
? cloneValue(currentState.runtimeState)
|
||||
: {};
|
||||
const baseFlowState = isPlainObject(baseRuntimeState.flowState)
|
||||
? cloneValue(baseRuntimeState.flowState)
|
||||
: {};
|
||||
return {
|
||||
kiroRuntime: deepMerge(readKiroRuntime(currentState), patch),
|
||||
runtimeState: {
|
||||
...baseRuntimeState,
|
||||
flowState: {
|
||||
...baseFlowState,
|
||||
kiro: deepMerge(readKiroRuntime(currentState), nextRuntimeState),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function mergeRuntimePatch(currentState = {}, patch = {}) {
|
||||
return buildCanonicalRuntimePatch(
|
||||
currentState,
|
||||
deepMerge(readKiroRuntime(currentState), patch)
|
||||
);
|
||||
}
|
||||
|
||||
function getErrorMessage(error) {
|
||||
return error instanceof Error ? error.message : String(error ?? '未知错误');
|
||||
}
|
||||
@@ -1076,7 +1100,7 @@
|
||||
tokenSource: 'desktop_authorization_code_pkce',
|
||||
},
|
||||
upload: {
|
||||
targetId: cleanString(currentState?.kiroTargetId || readKiroRuntime(currentState).upload?.targetId) || DEFAULT_TARGET_ID,
|
||||
targetId: cleanString(currentState?.targetId || readKiroRuntime(currentState).upload?.targetId) || DEFAULT_TARGET_ID,
|
||||
status: 'waiting_register',
|
||||
error: '',
|
||||
credentialId: null,
|
||||
@@ -1361,7 +1385,7 @@
|
||||
const pollingState = {
|
||||
...currentState,
|
||||
email: currentEmail,
|
||||
kiroRuntime: deepMerge(readKiroRuntime(currentState), {
|
||||
...mergeRuntimePatch(currentState, {
|
||||
register: {
|
||||
email: currentEmail,
|
||||
},
|
||||
@@ -58,6 +58,24 @@
|
||||
return Number.isInteger(numeric) ? numeric : fallback;
|
||||
}
|
||||
|
||||
function normalizeNullableIdentifier(value, fallback = null) {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return fallback;
|
||||
}
|
||||
if (typeof value === 'number') {
|
||||
const numeric = Math.floor(value);
|
||||
return Number.isInteger(numeric) ? numeric : fallback;
|
||||
}
|
||||
const normalized = String(value ?? '').trim();
|
||||
if (!normalized) {
|
||||
return fallback;
|
||||
}
|
||||
const numeric = Math.floor(Number(normalized));
|
||||
return Number.isInteger(numeric) && String(numeric) === normalized
|
||||
? numeric
|
||||
: normalized;
|
||||
}
|
||||
|
||||
function normalizeBoolean(value, fallback = false) {
|
||||
if (value === true || value === false) {
|
||||
return value;
|
||||
@@ -174,15 +192,63 @@
|
||||
targetId: normalizeString(merged.upload?.targetId, DEFAULT_TARGET_ID),
|
||||
status: normalizeString(merged.upload?.status),
|
||||
error: normalizeString(merged.upload?.error),
|
||||
credentialId: normalizeNullableInteger(merged.upload?.credentialId),
|
||||
credentialId: normalizeNullableIdentifier(merged.upload?.credentialId),
|
||||
lastMessage: normalizeString(merged.upload?.lastMessage),
|
||||
lastUploadedAt: Math.max(0, normalizeInteger(merged.upload?.lastUploadedAt)),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildCanonicalRuntimeStatePatch(state = {}, runtimeState = {}) {
|
||||
const normalizedRuntimeState = normalizeRuntimeState(runtimeState);
|
||||
const baseRuntimeState = isPlainObject(state?.runtimeState)
|
||||
? cloneValue(state.runtimeState)
|
||||
: {};
|
||||
const baseFlowState = isPlainObject(baseRuntimeState.flowState)
|
||||
? cloneValue(baseRuntimeState.flowState)
|
||||
: {};
|
||||
return {
|
||||
...baseRuntimeState,
|
||||
flowState: {
|
||||
...baseFlowState,
|
||||
kiro: normalizedRuntimeState,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function buildRuntimeStateView(runtimeState = {}) {
|
||||
const normalizedFlowState = isPlainObject(runtimeState?.flowState)
|
||||
? runtimeState.flowState
|
||||
: {};
|
||||
return {
|
||||
flowState: cloneValue(normalizedFlowState),
|
||||
flows: cloneValue(normalizedFlowState),
|
||||
};
|
||||
}
|
||||
|
||||
function buildRuntimeStatePatch(currentState = {}, patch = {}) {
|
||||
if (!isPlainObject(patch)) {
|
||||
return {};
|
||||
}
|
||||
const nextRuntimeState = normalizeRuntimeState(
|
||||
deepMerge(ensureRuntimeState(currentState), patch)
|
||||
);
|
||||
return {
|
||||
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
|
||||
};
|
||||
}
|
||||
|
||||
function ensureRuntimeState(state = {}) {
|
||||
return normalizeRuntimeState(isPlainObject(state?.kiroRuntime) ? state.kiroRuntime : {});
|
||||
const runtimeFlowState = isPlainObject(state?.runtimeState?.flowState)
|
||||
? state.runtimeState.flowState
|
||||
: {};
|
||||
if (isPlainObject(runtimeFlowState.kiro)) {
|
||||
return normalizeRuntimeState(runtimeFlowState.kiro);
|
||||
}
|
||||
if (isPlainObject(state?.flowState?.kiro)) {
|
||||
return normalizeRuntimeState(state.flowState.kiro);
|
||||
}
|
||||
return buildDefaultRuntimeState();
|
||||
}
|
||||
|
||||
function projectRuntimeFields() {
|
||||
@@ -190,31 +256,30 @@
|
||||
}
|
||||
|
||||
function buildStateView(state = {}) {
|
||||
const nextRuntimeState = ensureRuntimeState(state);
|
||||
const runtimeState = buildCanonicalRuntimeStatePatch(state, nextRuntimeState);
|
||||
return {
|
||||
...state,
|
||||
kiroRuntime: ensureRuntimeState(state),
|
||||
runtimeState,
|
||||
...buildRuntimeStateView(runtimeState),
|
||||
};
|
||||
}
|
||||
|
||||
function buildSessionStatePatch(currentState = {}, updates = {}) {
|
||||
if (!isPlainObject(updates?.kiroRuntime)) {
|
||||
const runtimePatch = isPlainObject(updates?.runtimeState?.flowState?.kiro)
|
||||
? updates.runtimeState.flowState.kiro
|
||||
: (isPlainObject(updates?.flowState?.kiro)
|
||||
? updates.flowState.kiro
|
||||
: null);
|
||||
if (!runtimePatch) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const nextRuntimeState = normalizeRuntimeState(
|
||||
deepMerge(ensureRuntimeState(currentState), updates.kiroRuntime)
|
||||
);
|
||||
return {
|
||||
kiroRuntime: nextRuntimeState,
|
||||
};
|
||||
return buildRuntimeStatePatch(currentState, runtimePatch);
|
||||
}
|
||||
|
||||
function buildRuntimeResetPatch(currentState = {}, patch = {}) {
|
||||
return {
|
||||
kiroRuntime: normalizeRuntimeState(
|
||||
deepMerge(ensureRuntimeState(currentState), patch)
|
||||
),
|
||||
};
|
||||
return buildRuntimeStatePatch(currentState, patch);
|
||||
}
|
||||
|
||||
function buildStartRegisterResetPatch(currentState = {}) {
|
||||
@@ -222,7 +287,7 @@
|
||||
const nextRuntimeState = buildDefaultRuntimeState();
|
||||
nextRuntimeState.upload.targetId = currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID;
|
||||
return {
|
||||
kiroRuntime: nextRuntimeState,
|
||||
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -251,43 +316,45 @@
|
||||
},
|
||||
});
|
||||
return {
|
||||
kiroRuntime: nextRuntimeState,
|
||||
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
|
||||
};
|
||||
}
|
||||
|
||||
function buildDesktopResetPatch(currentState = {}) {
|
||||
const currentRuntimeState = ensureRuntimeState(currentState);
|
||||
const nextRuntimeState = normalizeRuntimeState({
|
||||
...currentRuntimeState,
|
||||
session: {
|
||||
...currentRuntimeState.session,
|
||||
currentStage: 'desktop-authorize',
|
||||
desktopTabId: null,
|
||||
pageState: '',
|
||||
pageUrl: '',
|
||||
lastError: '',
|
||||
lastWarning: '',
|
||||
},
|
||||
desktopAuth: buildDefaultRuntimeState().desktopAuth,
|
||||
upload: {
|
||||
...buildDefaultRuntimeState().upload,
|
||||
targetId: currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID,
|
||||
},
|
||||
});
|
||||
return {
|
||||
kiroRuntime: normalizeRuntimeState({
|
||||
...currentRuntimeState,
|
||||
session: {
|
||||
...currentRuntimeState.session,
|
||||
currentStage: 'desktop-authorize',
|
||||
desktopTabId: null,
|
||||
pageState: '',
|
||||
pageUrl: '',
|
||||
lastError: '',
|
||||
lastWarning: '',
|
||||
},
|
||||
desktopAuth: buildDefaultRuntimeState().desktopAuth,
|
||||
upload: {
|
||||
...buildDefaultRuntimeState().upload,
|
||||
targetId: currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID,
|
||||
},
|
||||
}),
|
||||
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
|
||||
};
|
||||
}
|
||||
|
||||
function buildUploadResetPatch(currentState = {}) {
|
||||
const currentRuntimeState = ensureRuntimeState(currentState);
|
||||
const nextRuntimeState = normalizeRuntimeState({
|
||||
...currentRuntimeState,
|
||||
upload: {
|
||||
...buildDefaultRuntimeState().upload,
|
||||
targetId: currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID,
|
||||
},
|
||||
});
|
||||
return {
|
||||
kiroRuntime: normalizeRuntimeState({
|
||||
...currentRuntimeState,
|
||||
upload: {
|
||||
...buildDefaultRuntimeState().upload,
|
||||
targetId: currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID,
|
||||
},
|
||||
}),
|
||||
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -332,9 +399,9 @@
|
||||
const nextRuntimeState = buildDefaultRuntimeState();
|
||||
nextRuntimeState.upload.targetId = currentRuntimeState.upload?.targetId || DEFAULT_TARGET_ID;
|
||||
return {
|
||||
kiroRuntime: nextRuntimeState,
|
||||
...(Object.prototype.hasOwnProperty.call(currentState, 'kiroTargetId')
|
||||
? { kiroTargetId: normalizeString(currentState.kiroTargetId, DEFAULT_TARGET_ID).toLowerCase() }
|
||||
runtimeState: buildCanonicalRuntimeStatePatch(currentState, nextRuntimeState),
|
||||
...(Object.prototype.hasOwnProperty.call(currentState, 'targetId')
|
||||
? { targetId: normalizeString(currentState.targetId, DEFAULT_TARGET_ID).toLowerCase() }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
@@ -348,6 +415,7 @@
|
||||
buildDefaultRuntimeState,
|
||||
buildDownstreamResetPatch,
|
||||
buildFreshKeepState,
|
||||
buildRuntimeStatePatch,
|
||||
buildSessionStatePatch,
|
||||
buildStateView,
|
||||
ensureRuntimeState,
|
||||
@@ -0,0 +1,226 @@
|
||||
(function attachMultiPageKiroFlowDefinition(root, factory) {
|
||||
root.MultiPageKiroFlowDefinition = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createMultiPageKiroFlowDefinition() {
|
||||
function freezeDeep(entry) {
|
||||
if (!entry || typeof entry !== 'object' || Object.isFrozen(entry)) {
|
||||
return entry;
|
||||
}
|
||||
Object.getOwnPropertyNames(entry).forEach((key) => {
|
||||
freezeDeep(entry[key]);
|
||||
});
|
||||
return Object.freeze(entry);
|
||||
}
|
||||
|
||||
const VALUE = freezeDeep({
|
||||
"id": "kiro",
|
||||
"label": "Kiro",
|
||||
"services": [
|
||||
"account",
|
||||
"email",
|
||||
"proxy"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsEmailSignup": true,
|
||||
"supportsPhoneSignup": false,
|
||||
"supportsPhoneVerificationSettings": false,
|
||||
"supportsPlusMode": false,
|
||||
"supportsContributionMode": false,
|
||||
"supportsAccountContribution": true,
|
||||
"supportsOpenAiOAuthContribution": false,
|
||||
"contributionAdapterIds": [
|
||||
"kiro-builder-id"
|
||||
],
|
||||
"supportedTargetIds": [
|
||||
"kiro-rs"
|
||||
],
|
||||
"supportsLuckmail": false,
|
||||
"supportsOauthTimeoutBudget": false,
|
||||
"canSwitchFlow": true,
|
||||
"stepDefinitionMode": "kiro",
|
||||
"targetSelectorLabel": "来源"
|
||||
},
|
||||
"baseGroups": [
|
||||
"kiro-runtime-status"
|
||||
],
|
||||
"targets": {
|
||||
"kiro-rs": {
|
||||
"id": "kiro-rs",
|
||||
"label": "kiro.rs",
|
||||
"groups": [
|
||||
"kiro-target-kiro-rs"
|
||||
]
|
||||
}
|
||||
},
|
||||
"publicationTargets": {
|
||||
"kiro-rs": {
|
||||
"id": "kiro-rs",
|
||||
"label": "kiro.rs"
|
||||
}
|
||||
},
|
||||
"runtimeSources": {
|
||||
"kiro-register-page": {
|
||||
"flowId": "kiro",
|
||||
"kind": "flow-page",
|
||||
"label": "Kiro 注册页",
|
||||
"readyPolicy": "top-frame-only",
|
||||
"family": "kiro-register-page-family",
|
||||
"driverId": "flows/kiro/content/register-page",
|
||||
"cleanupScopes": [],
|
||||
"detectionMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"app.kiro.dev",
|
||||
"kiro.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"hostnames": [
|
||||
"view.awsapps.com",
|
||||
"login.awsapps.com",
|
||||
"amazonaws.com"
|
||||
],
|
||||
"hostnameFamilies": [
|
||||
"signin.aws",
|
||||
"profile.aws"
|
||||
],
|
||||
"hostnameEndsWith": [
|
||||
".amazonaws.com"
|
||||
],
|
||||
"matchMode": "any"
|
||||
}
|
||||
],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"app.kiro.dev",
|
||||
"kiro.dev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"hostnames": [
|
||||
"view.awsapps.com",
|
||||
"login.awsapps.com",
|
||||
"amazonaws.com"
|
||||
],
|
||||
"hostnameFamilies": [
|
||||
"signin.aws",
|
||||
"profile.aws"
|
||||
],
|
||||
"hostnameEndsWith": [
|
||||
".amazonaws.com"
|
||||
],
|
||||
"matchMode": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"kiro-desktop-authorize": {
|
||||
"flowId": "kiro",
|
||||
"kind": "flow-page",
|
||||
"label": "Kiro 桌面授权页",
|
||||
"readyPolicy": "top-frame-only",
|
||||
"family": "kiro-desktop-authorize-family",
|
||||
"driverId": "flows/kiro/content/desktop-authorize-page",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"view.awsapps.com",
|
||||
"login.awsapps.com",
|
||||
"amazonaws.com"
|
||||
],
|
||||
"hostnameFamilies": [
|
||||
"signin.aws",
|
||||
"profile.aws"
|
||||
],
|
||||
"hostnameEndsWith": [
|
||||
".amazonaws.com"
|
||||
],
|
||||
"matchMode": "any"
|
||||
}
|
||||
]
|
||||
},
|
||||
"kiro-rs-admin": {
|
||||
"flowId": "kiro",
|
||||
"kind": "virtual-page",
|
||||
"label": "kiro.rs Admin",
|
||||
"readyPolicy": "disabled",
|
||||
"family": "kiro-rs-admin-family",
|
||||
"driverId": null,
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": []
|
||||
}
|
||||
},
|
||||
"driverDefinitions": {
|
||||
"flows/kiro/content/register-page": {
|
||||
"sourceId": "kiro-register-page",
|
||||
"commands": [
|
||||
"kiro-open-register-page",
|
||||
"kiro-submit-email",
|
||||
"kiro-submit-name",
|
||||
"kiro-submit-verification-code",
|
||||
"kiro-submit-password",
|
||||
"kiro-complete-register-consent"
|
||||
]
|
||||
},
|
||||
"flows/kiro/content/desktop-authorize-page": {
|
||||
"sourceId": "kiro-desktop-authorize",
|
||||
"commands": [
|
||||
"kiro-complete-desktop-authorize"
|
||||
]
|
||||
},
|
||||
"flows/kiro/background/register-runner": {
|
||||
"sourceId": "kiro-register-page",
|
||||
"commands": [
|
||||
"kiro-open-register-page",
|
||||
"kiro-submit-email",
|
||||
"kiro-submit-name",
|
||||
"kiro-submit-verification-code",
|
||||
"kiro-submit-password",
|
||||
"kiro-complete-register-consent"
|
||||
]
|
||||
},
|
||||
"flows/kiro/background/desktop-authorize-runner": {
|
||||
"sourceId": "kiro-desktop-authorize",
|
||||
"commands": [
|
||||
"kiro-start-desktop-authorize",
|
||||
"kiro-complete-desktop-authorize"
|
||||
]
|
||||
},
|
||||
"flows/kiro/background/publisher-kiro-rs": {
|
||||
"sourceId": "kiro-rs-admin",
|
||||
"commands": [
|
||||
"kiro-upload-credential"
|
||||
]
|
||||
}
|
||||
},
|
||||
"defaultTargetId": "kiro-rs",
|
||||
"defaultPublicationTargetId": "kiro-rs",
|
||||
"defaultTargetState": {
|
||||
"baseUrl": "",
|
||||
"apiKey": ""
|
||||
},
|
||||
"settingsGroups": {
|
||||
"kiro-target-kiro-rs": {
|
||||
"id": "kiro-target-kiro-rs",
|
||||
"label": "kiro.rs 配置",
|
||||
"rowIds": [
|
||||
"row-kiro-rs-url",
|
||||
"row-kiro-rs-key",
|
||||
"row-kiro-rs-test-status"
|
||||
]
|
||||
},
|
||||
"kiro-runtime-status": {
|
||||
"id": "kiro-runtime-status",
|
||||
"label": "Kiro 运行态",
|
||||
"rowIds": [
|
||||
"row-kiro-web-status",
|
||||
"row-kiro-login-url",
|
||||
"row-kiro-upload-status"
|
||||
]
|
||||
}
|
||||
},
|
||||
"sourceAliases": {}
|
||||
});
|
||||
|
||||
return VALUE;
|
||||
});
|
||||
@@ -0,0 +1,142 @@
|
||||
(function attachMultiPageKiroWorkflow(root, factory) {
|
||||
root.MultiPageKiroWorkflow = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createMultiPageKiroWorkflow() {
|
||||
const KIRO_CONTRIBUTION_STEP_TITLE = '\u8d21\u732e\u4e0a\u4f20';
|
||||
|
||||
function freezeDeep(entry) {
|
||||
if (!entry || typeof entry !== 'object' || Object.isFrozen(entry)) {
|
||||
return entry;
|
||||
}
|
||||
Object.getOwnPropertyNames(entry).forEach((key) => {
|
||||
freezeDeep(entry[key]);
|
||||
});
|
||||
return Object.freeze(entry);
|
||||
}
|
||||
|
||||
const STEP_VARIANTS = freezeDeep({
|
||||
"default": [
|
||||
{
|
||||
"id": 1,
|
||||
"order": 10,
|
||||
"key": "kiro-open-register-page",
|
||||
"title": "打开注册页",
|
||||
"sourceId": "kiro-register-page",
|
||||
"driverId": "flows/kiro/background/register-runner",
|
||||
"command": "kiro-open-register-page",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"order": 20,
|
||||
"key": "kiro-submit-email",
|
||||
"title": "获取邮箱并继续",
|
||||
"sourceId": "kiro-register-page",
|
||||
"driverId": "flows/kiro/background/register-runner",
|
||||
"command": "kiro-submit-email",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"order": 30,
|
||||
"key": "kiro-submit-name",
|
||||
"title": "填写姓名并继续",
|
||||
"sourceId": "kiro-register-page",
|
||||
"driverId": "flows/kiro/background/register-runner",
|
||||
"command": "kiro-submit-name",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"order": 40,
|
||||
"key": "kiro-submit-verification-code",
|
||||
"title": "获取验证码并继续",
|
||||
"sourceId": "kiro-register-page",
|
||||
"driverId": "flows/kiro/background/register-runner",
|
||||
"command": "kiro-submit-verification-code",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"order": 50,
|
||||
"key": "kiro-submit-password",
|
||||
"title": "设置密码并继续",
|
||||
"sourceId": "kiro-register-page",
|
||||
"driverId": "flows/kiro/background/register-runner",
|
||||
"command": "kiro-submit-password",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"order": 60,
|
||||
"key": "kiro-complete-register-consent",
|
||||
"title": "完成注册授权",
|
||||
"sourceId": "kiro-register-page",
|
||||
"driverId": "flows/kiro/background/register-runner",
|
||||
"command": "kiro-complete-register-consent",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"order": 70,
|
||||
"key": "kiro-start-desktop-authorize",
|
||||
"title": "启动桌面授权",
|
||||
"sourceId": "kiro-desktop-authorize",
|
||||
"driverId": "flows/kiro/background/desktop-authorize-runner",
|
||||
"command": "kiro-start-desktop-authorize",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"order": 80,
|
||||
"key": "kiro-complete-desktop-authorize",
|
||||
"title": "完成桌面授权",
|
||||
"sourceId": "kiro-desktop-authorize",
|
||||
"driverId": "flows/kiro/background/desktop-authorize-runner",
|
||||
"command": "kiro-complete-desktop-authorize",
|
||||
"flowId": "kiro"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"order": 90,
|
||||
"key": "kiro-upload-credential",
|
||||
"title": "上传凭据到 kiro.rs",
|
||||
"sourceId": "kiro-rs-admin",
|
||||
"driverId": "flows/kiro/background/publisher-kiro-rs",
|
||||
"command": "kiro-upload-credential",
|
||||
"flowId": "kiro"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function getVariantStepDefinitions(variantKey = 'default') {
|
||||
return Array.isArray(STEP_VARIANTS[variantKey]) ? STEP_VARIANTS[variantKey] : STEP_VARIANTS.default;
|
||||
}
|
||||
|
||||
function getModeStepDefinitions() {
|
||||
return getVariantStepDefinitions('default');
|
||||
}
|
||||
|
||||
function getAllSteps() {
|
||||
return getVariantStepDefinitions('default');
|
||||
}
|
||||
|
||||
function getPlusPaymentStepTitle() {
|
||||
return '';
|
||||
}
|
||||
|
||||
function resolveStepTitle(step = {}, options = {}) {
|
||||
if (step?.key === 'kiro-upload-credential' && Boolean(options?.accountContributionEnabled || options?.state?.accountContributionEnabled)) {
|
||||
return KIRO_CONTRIBUTION_STEP_TITLE;
|
||||
}
|
||||
return step?.title || '';
|
||||
}
|
||||
|
||||
return {
|
||||
flowId: 'kiro',
|
||||
getAllSteps,
|
||||
getModeStepDefinitions,
|
||||
getPlusPaymentStepTitle,
|
||||
getVariantStepDefinitions,
|
||||
resolveStepTitle,
|
||||
};
|
||||
});
|
||||
@@ -221,14 +221,14 @@
|
||||
(async () => {
|
||||
try {
|
||||
throwIfStep8SettledOrStopped(resolved);
|
||||
signupTabId = await getTabId('signup-page');
|
||||
signupTabId = await getTabId('openai-auth');
|
||||
throwIfStep8SettledOrStopped(resolved);
|
||||
|
||||
if (signupTabId && await isTabAlive('signup-page')) {
|
||||
if (signupTabId && await isTabAlive('openai-auth')) {
|
||||
await chrome.tabs.update(signupTabId, { active: true });
|
||||
await addStepLog(visibleStep, '已切回认证页,正在准备调试器点击...');
|
||||
} else {
|
||||
signupTabId = await reuseOrCreateTab('signup-page', activeState.oauthUrl);
|
||||
signupTabId = await reuseOrCreateTab('openai-auth', activeState.oauthUrl);
|
||||
await addStepLog(visibleStep, '已重新打开认证页,正在准备调试器点击...');
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
root.MultiPageBackgroundCpaSessionImport = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundCpaSessionImportModule() {
|
||||
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/plus-checkout.js'];
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'flows/openai/content/plus-checkout.js'];
|
||||
|
||||
function createCpaSessionImportExecutor(deps = {}) {
|
||||
const {
|
||||
+2
-2
@@ -4,8 +4,8 @@
|
||||
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
||||
const PAYPAL_SOURCE = 'paypal-flow';
|
||||
const PLUS_CHECKOUT_ENTRY_URL = 'https://chatgpt.com/';
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/plus-checkout.js'];
|
||||
const PAYPAL_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/paypal-flow.js'];
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'flows/openai/content/plus-checkout.js'];
|
||||
const PAYPAL_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'flows/openai/content/paypal-flow.js'];
|
||||
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
||||
const PLUS_PAYMENT_METHOD_PAYPAL_HOSTED = 'paypal-hosted';
|
||||
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
||||
+8
-8
@@ -158,7 +158,7 @@
|
||||
}
|
||||
const timeoutMs = Math.max(1000, Number(options.timeoutMs) || 15000);
|
||||
const result = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
{
|
||||
type: 'GET_LOGIN_AUTH_STATE',
|
||||
source: 'background',
|
||||
@@ -208,7 +208,7 @@
|
||||
})
|
||||
: 60000;
|
||||
const result = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
{
|
||||
type: 'SUBMIT_ADD_EMAIL',
|
||||
source: 'background',
|
||||
@@ -439,7 +439,7 @@
|
||||
}
|
||||
|
||||
async function ensureAuthTabForPostLoginStep(state, visibleStep) {
|
||||
const authTabId = await getTabId('signup-page');
|
||||
const authTabId = await getTabId('openai-auth');
|
||||
if (authTabId) {
|
||||
await chrome.tabs.update(authTabId, { active: true });
|
||||
return authTabId;
|
||||
@@ -447,7 +447,7 @@
|
||||
if (!state?.oauthUrl) {
|
||||
throw new Error(`步骤 ${visibleStep}:缺少登录用 OAuth 链接,请先完成刷新 OAuth 并登录。`);
|
||||
}
|
||||
return reuseOrCreateTab('signup-page', state.oauthUrl);
|
||||
return reuseOrCreateTab('openai-auth', state.oauthUrl);
|
||||
}
|
||||
|
||||
async function completePostLoginPhoneVerificationSkippedOnOauth(visibleStep, options = {}) {
|
||||
@@ -708,7 +708,7 @@
|
||||
activeFetchLoginCodeStep = visibleStep;
|
||||
activeFetchLoginCodeStepKey = 'fetch-bound-email-login-code';
|
||||
const preparedState = buildBoundEmailLoginState(state, visibleStep);
|
||||
const authTabId = await getTabId('signup-page');
|
||||
const authTabId = await getTabId('openai-auth');
|
||||
|
||||
if (authTabId) {
|
||||
await chrome.tabs.update(authTabId, { active: true });
|
||||
@@ -716,7 +716,7 @@
|
||||
if (!preparedState.oauthUrl) {
|
||||
throw new Error(`步骤 ${visibleStep}:缺少登录用 OAuth 链接,请先完成绑定邮箱后刷新 OAuth 并登录。`);
|
||||
}
|
||||
await reuseOrCreateTab('signup-page', preparedState.oauthUrl);
|
||||
await reuseOrCreateTab('openai-auth', preparedState.oauthUrl);
|
||||
}
|
||||
|
||||
throwIfStopped();
|
||||
@@ -765,7 +765,7 @@
|
||||
const visibleStep = getVisibleStep(state, 8);
|
||||
activeFetchLoginCodeStep = visibleStep;
|
||||
activeFetchLoginCodeStepKey = 'fetch-login-code';
|
||||
const authTabId = await getTabId('signup-page');
|
||||
const authTabId = await getTabId('openai-auth');
|
||||
|
||||
if (authTabId) {
|
||||
await chrome.tabs.update(authTabId, { active: true });
|
||||
@@ -773,7 +773,7 @@
|
||||
if (!state.oauthUrl) {
|
||||
throw new Error(`缺少登录用 OAuth 链接,请先完成步骤 ${getAuthLoginStepForVisibleStep(visibleStep)}。`);
|
||||
}
|
||||
await reuseOrCreateTab('signup-page', state.oauthUrl);
|
||||
await reuseOrCreateTab('openai-auth', state.oauthUrl);
|
||||
}
|
||||
|
||||
throwIfStopped();
|
||||
+4
-4
@@ -188,7 +188,7 @@
|
||||
async function executeStep4(state) {
|
||||
const stepStartedAt = Date.now();
|
||||
const verificationSessionKey = `4:${stepStartedAt}`;
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
const signupTabId = await getTabId('openai-auth');
|
||||
|
||||
if (!signupTabId) {
|
||||
throw new Error('认证页面标签页已关闭,无法继续步骤 4。请先执行步骤 1 或步骤 2,重新打开认证页后再试。');
|
||||
@@ -228,10 +228,10 @@
|
||||
|
||||
try {
|
||||
prepareResult = typeof sendToContentScript === 'function'
|
||||
? await sendToContentScript('signup-page', prepareRequest, {
|
||||
? await sendToContentScript('openai-auth', prepareRequest, {
|
||||
responseTimeoutMs: prepareResponseTimeoutMs,
|
||||
})
|
||||
: await sendToContentScriptResilient('signup-page', prepareRequest, {
|
||||
: await sendToContentScriptResilient('openai-auth', prepareRequest, {
|
||||
timeoutMs: Math.max(1000, prepareTimeoutMs - (Date.now() - prepareStartAt)),
|
||||
responseTimeoutMs: prepareResponseTimeoutMs,
|
||||
retryDelayMs: 700,
|
||||
@@ -248,7 +248,7 @@
|
||||
throw error;
|
||||
}
|
||||
|
||||
const recoverResult = await sendToContentScriptResilient('signup-page', {
|
||||
const recoverResult = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'RECOVER_AUTH_RETRY_PAGE',
|
||||
step: 4,
|
||||
source: 'background',
|
||||
@@ -13,7 +13,7 @@
|
||||
sendToContentScript,
|
||||
setPasswordState,
|
||||
setState,
|
||||
SIGNUP_PAGE_INJECT_FILES,
|
||||
OPENAI_AUTH_INJECT_FILES,
|
||||
} = deps;
|
||||
|
||||
function normalizeSignupMethod(value = '') {
|
||||
@@ -71,8 +71,8 @@
|
||||
throw new Error('缺少注册账号,请先完成步骤 2。');
|
||||
}
|
||||
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
if (!signupTabId || !(await isTabAlive('signup-page'))) {
|
||||
const signupTabId = await getTabId('openai-auth');
|
||||
if (!signupTabId || !(await isTabAlive('openai-auth'))) {
|
||||
throw new Error('认证页面标签页已关闭,请先重新完成步骤 2。');
|
||||
}
|
||||
|
||||
@@ -90,9 +90,9 @@
|
||||
await setState({ accounts });
|
||||
|
||||
await chrome.tabs.update(signupTabId, { active: true });
|
||||
await ensureContentScriptReadyOnTab('signup-page', signupTabId, {
|
||||
inject: SIGNUP_PAGE_INJECT_FILES,
|
||||
injectSource: 'signup-page',
|
||||
await ensureContentScriptReadyOnTab('openai-auth', signupTabId, {
|
||||
inject: OPENAI_AUTH_INJECT_FILES,
|
||||
injectSource: 'openai-auth',
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: '步骤 3:密码页内容脚本未就绪,正在等待页面恢复...',
|
||||
@@ -104,7 +104,7 @@
|
||||
await addLog(
|
||||
`步骤 3:正在填写密码,${identityLabel},密码为${state.customPassword ? '自定义' : '自动生成'}(${password.length} 位)`
|
||||
);
|
||||
await sendToContentScript('signup-page', {
|
||||
await sendToContentScript('openai-auth', {
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: 'fill-password',
|
||||
step: 3,
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
root.MultiPageBackgroundPlusCheckoutBilling = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundPlusCheckoutBillingModule() {
|
||||
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/plus-checkout.js'];
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'flows/openai/content/plus-checkout.js'];
|
||||
const PLUS_CHECKOUT_URL_PATTERN = /^https:\/\/chatgpt\.com\/checkout(?:\/|$)/i;
|
||||
const PLUS_CHECKOUT_FRAME_READY_DELAY_MS = 500;
|
||||
const PLUS_CHECKOUT_SUBMIT_MAX_ATTEMPTS = 5;
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
await addLog(`步骤 5:已生成姓名 ${firstName} ${lastName},生日 ${year}-${month}-${day}`);
|
||||
|
||||
await sendToContentScript('signup-page', {
|
||||
await sendToContentScript('openai-auth', {
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: 'fill-profile',
|
||||
step: 5,
|
||||
@@ -4,7 +4,7 @@
|
||||
const GOPAY_SOURCE = 'gopay-flow';
|
||||
const GOPAY_OTP_SOURCE = 'gopay-otp-flow';
|
||||
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
||||
const GOPAY_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/gopay-flow.js'];
|
||||
const GOPAY_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'flows/openai/content/gopay-flow.js'];
|
||||
const GOPAY_WAIT_TIMEOUT_MS = 120000;
|
||||
const GOPAY_POLL_INTERVAL_MS = 1000;
|
||||
const GOPAY_LINKING_RETRY_WAIT_MS = 15000;
|
||||
@@ -301,10 +301,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
await reuseOrCreateTab('signup-page', oauthUrl, { forceNew: true });
|
||||
await reuseOrCreateTab('openai-auth', oauthUrl, { forceNew: true });
|
||||
|
||||
const result = await sendToContentScriptResilient(
|
||||
'signup-page',
|
||||
'openai-auth',
|
||||
{
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: state?.nodeId || 'oauth-login',
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundPayPalApproveModule() {
|
||||
const PAYPAL_SOURCE = 'paypal-flow';
|
||||
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
||||
const PAYPAL_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/paypal-flow.js'];
|
||||
const PAYPAL_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'flows/openai/content/paypal-flow.js'];
|
||||
const PAYPAL_LOGIN_TRANSITION_TIMEOUT_MS = 30000;
|
||||
const PAYPAL_LOGIN_TRANSITION_POLL_MS = 500;
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
root.MultiPageBackgroundSub2ApiSessionImport = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundSub2ApiSessionImportModule() {
|
||||
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'content/plus-checkout.js'];
|
||||
const PLUS_CHECKOUT_INJECT_FILES = ['content/utils.js', 'content/operation-delay.js', 'flows/openai/content/plus-checkout.js'];
|
||||
|
||||
function createSub2ApiSessionImportExecutor(deps = {}) {
|
||||
const {
|
||||
+10
-10
@@ -17,7 +17,7 @@
|
||||
resolveSignupMethod = () => 'email',
|
||||
resolveSignupEmailForFlow,
|
||||
sendToContentScriptResilient,
|
||||
SIGNUP_PAGE_INJECT_FILES,
|
||||
OPENAI_AUTH_INJECT_FILES,
|
||||
waitForTabStableComplete = null,
|
||||
} = deps;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
function isRetryableStep2TransportErrorMessage(errorLike) {
|
||||
const message = getErrorMessage(errorLike);
|
||||
return /Content script on signup-page did not respond in \d+s|内容脚本\s+\d+(?:\.\d+)?\s*秒内未响应|Receiving end does not exist|message channel closed|A listener indicated an asynchronous response|port closed before a response was received|did not respond in \d+s/i.test(message);
|
||||
return /Content script on [\w-]+ did not respond in \d+s|内容脚本\s+\d+(?:\.\d+)?\s*秒内未响应|Receiving end does not exist|message channel closed|A listener indicated an asynchronous response|port closed before a response was received|did not respond in \d+s/i.test(message);
|
||||
}
|
||||
|
||||
function isLikelyLoggedInChatgptHomeUrl(rawUrl) {
|
||||
@@ -78,7 +78,7 @@
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'ENSURE_SIGNUP_ENTRY_READY',
|
||||
step: 2,
|
||||
source: 'background',
|
||||
@@ -151,7 +151,7 @@
|
||||
} = options;
|
||||
|
||||
try {
|
||||
return await sendToContentScriptResilient('signup-page', {
|
||||
return await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'EXECUTE_NODE',
|
||||
nodeId: 'submit-signup-email',
|
||||
step: 2,
|
||||
@@ -198,7 +198,7 @@
|
||||
throw new Error('步骤 2:未找到可用的注册页标签,无法切换到手机号注册入口。');
|
||||
}
|
||||
|
||||
const result = await sendToContentScriptResilient('signup-page', {
|
||||
const result = await sendToContentScriptResilient('openai-auth', {
|
||||
type: 'ENSURE_SIGNUP_PHONE_ENTRY_READY',
|
||||
step: 2,
|
||||
source: 'background',
|
||||
@@ -232,8 +232,8 @@
|
||||
}
|
||||
|
||||
async function ensureSignupTabForStep2() {
|
||||
let signupTabId = await getTabId('signup-page');
|
||||
if (!signupTabId || !(await isTabAlive('signup-page'))) {
|
||||
let signupTabId = await getTabId('openai-auth');
|
||||
if (!signupTabId || !(await isTabAlive('openai-auth'))) {
|
||||
await addLog('步骤 2:未发现可用的注册页标签,正在重新打开 ChatGPT 官网...', 'warn');
|
||||
signupTabId = (await ensureSignupEntryPageReady(2)).tabId;
|
||||
} else {
|
||||
@@ -243,9 +243,9 @@
|
||||
signupTabId,
|
||||
'步骤 2:已切换到注册页标签,正在等待页面加载完成并额外稳定 3 秒...'
|
||||
);
|
||||
await ensureContentScriptReadyOnTab('signup-page', signupTabId, {
|
||||
inject: SIGNUP_PAGE_INJECT_FILES,
|
||||
injectSource: 'signup-page',
|
||||
await ensureContentScriptReadyOnTab('openai-auth', signupTabId, {
|
||||
inject: OPENAI_AUTH_INJECT_FILES,
|
||||
injectSource: 'openai-auth',
|
||||
timeoutMs: 45000,
|
||||
retryDelayMs: 900,
|
||||
logMessage: '步骤 2:注册入口页内容脚本未就绪,正在等待页面恢复...',
|
||||
@@ -1,4 +1,4 @@
|
||||
// content/gopay-flow.js — GoPay authorization helper.
|
||||
// flows/openai/content/gopay-flow.js — GoPay authorization helper.
|
||||
|
||||
console.log('[MultiPage:gopay-flow] Content script loaded on', location.href);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// content/signup-page.js — Content script for ChatGPT signup entry + OpenAI auth pages
|
||||
// flows/openai/content/openai-auth.js — Content script for ChatGPT signup entry + OpenAI auth pages
|
||||
// Injected on: auth0.openai.com, auth.openai.com, accounts.openai.com
|
||||
// Dynamically injected on: chatgpt.com
|
||||
|
||||
console.log('[MultiPage:signup-page] Content script loaded on', location.href);
|
||||
console.log('[MultiPage:openai-auth] Content script loaded on', location.href);
|
||||
|
||||
const SIGNUP_PAGE_LISTENER_SENTINEL = 'data-multipage-signup-page-listener';
|
||||
const OPENAI_AUTH_LISTENER_SENTINEL = 'data-multipage-openai-auth-listener';
|
||||
|
||||
function getOperationDelayRunner() {
|
||||
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||
@@ -14,8 +14,8 @@ function getOperationDelayRunner() {
|
||||
: async (_metadata, operation) => operation();
|
||||
}
|
||||
|
||||
if (document.documentElement.getAttribute(SIGNUP_PAGE_LISTENER_SENTINEL) !== '1') {
|
||||
document.documentElement.setAttribute(SIGNUP_PAGE_LISTENER_SENTINEL, '1');
|
||||
if (document.documentElement.getAttribute(OPENAI_AUTH_LISTENER_SENTINEL) !== '1') {
|
||||
document.documentElement.setAttribute(OPENAI_AUTH_LISTENER_SENTINEL, '1');
|
||||
|
||||
// Listen for commands from Background
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
@@ -70,10 +70,10 @@ if (document.documentElement.getAttribute(SIGNUP_PAGE_LISTENER_SENTINEL) !== '1'
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('[MultiPage:signup-page] 消息监听已存在,跳过重复注册');
|
||||
console.log('[MultiPage:openai-auth] 消息监听已存在,跳过重复注册');
|
||||
}
|
||||
|
||||
const SIGNUP_PAGE_NODE_HANDLERS = Object.freeze({
|
||||
const OPENAI_AUTH_NODE_HANDLERS = Object.freeze({
|
||||
'submit-signup-email': (payload) => step2_clickRegister(payload),
|
||||
'fill-password': (payload) => step3_fillEmailPassword(payload),
|
||||
'fill-profile': (payload) => step5_fillNameBirthday(payload),
|
||||
@@ -120,9 +120,9 @@ async function handleCommand(message) {
|
||||
switch (message.type) {
|
||||
case 'EXECUTE_NODE': {
|
||||
const nodeId = String(message.nodeId || message.payload?.nodeId || '').trim();
|
||||
const handler = SIGNUP_PAGE_NODE_HANDLERS[nodeId];
|
||||
const handler = OPENAI_AUTH_NODE_HANDLERS[nodeId];
|
||||
if (!handler) {
|
||||
throw new Error(`signup-page.js 不处理节点 ${nodeId}`);
|
||||
throw new Error(`openai-auth.js 不处理节点 ${nodeId}`);
|
||||
}
|
||||
return await handler(message.payload || {});
|
||||
}
|
||||
@@ -1085,7 +1085,7 @@ function logSignupPasswordDiagnostics(context, level = 'warn') {
|
||||
try {
|
||||
log(`${context}:密码页诊断快照:${JSON.stringify(getSignupPasswordDiagnostics())}`, level);
|
||||
} catch (error) {
|
||||
console.warn('[MultiPage:signup-page] failed to build signup password diagnostics:', error?.message || error);
|
||||
console.warn('[MultiPage:openai-auth] failed to build signup password diagnostics:', error?.message || error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1310,7 +1310,7 @@ async function fillSignupEmailAndContinue(email, step) {
|
||||
});
|
||||
} catch (error) {
|
||||
if (!isStopError(error)) {
|
||||
console.error('[MultiPage:signup-page] deferred signup email submit failed:', error?.message || error);
|
||||
console.error('[MultiPage:openai-auth] deferred signup email submit failed:', error?.message || error);
|
||||
}
|
||||
}
|
||||
}, 120);
|
||||
@@ -2580,7 +2580,7 @@ async function submitSignupPhoneNumberAndContinue(payload = {}) {
|
||||
});
|
||||
} catch (error) {
|
||||
if (!isStopError(error)) {
|
||||
console.error('[MultiPage:signup-page] deferred signup phone submit failed:', error?.message || error);
|
||||
console.error('[MultiPage:openai-auth] deferred signup phone submit failed:', error?.message || error);
|
||||
}
|
||||
}
|
||||
}, 120);
|
||||
@@ -2720,7 +2720,7 @@ async function step3_fillEmailPassword(payload) {
|
||||
log('步骤 3:表单已提交');
|
||||
} catch (error) {
|
||||
if (!isStopError(error)) {
|
||||
console.error('[MultiPage:signup-page] deferred step 3 submit failed:', error?.message || error);
|
||||
console.error('[MultiPage:openai-auth] deferred step 3 submit failed:', error?.message || error);
|
||||
}
|
||||
}
|
||||
}, 120);
|
||||
@@ -1,4 +1,4 @@
|
||||
// content/paypal-flow.js — PayPal login and approval helper.
|
||||
// flows/openai/content/paypal-flow.js — PayPal login and approval helper.
|
||||
|
||||
console.log('[MultiPage:paypal-flow] Content script loaded on', location.href);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// content/plus-checkout.js — ChatGPT Plus checkout helper.
|
||||
// flows/openai/content/plus-checkout.js — ChatGPT Plus checkout helper.
|
||||
|
||||
(function attachPlusCheckoutContentScript() {
|
||||
console.log('[MultiPage:plus-checkout] Content script loaded on', location.href);
|
||||
@@ -1,4 +1,4 @@
|
||||
// content/sub2api-panel.js — 页内脚本:SUB2API 后台(OAuth 生成与回调提交)
|
||||
// flows/openai/content/sub2api-panel.js — 页内脚本:SUB2API 后台(OAuth 生成与回调提交)
|
||||
|
||||
console.log('[MultiPage:sub2api-panel] Content script loaded on', location.href);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// content/vps-panel.js — Content script for CPA panel (OAuth URL request / platform verification node)
|
||||
// flows/openai/content/vps-panel.js — Content script for CPA panel (OAuth URL request / platform verification node)
|
||||
// Injected on: CPA panel (user-configured URL)
|
||||
//
|
||||
// Actual DOM structure (after login click):
|
||||
@@ -1,4 +1,4 @@
|
||||
// content/whatsapp-flow.js — WhatsApp Web code reader for GoPay.
|
||||
// flows/openai/content/whatsapp-flow.js — WhatsApp Web code reader for GoPay.
|
||||
|
||||
console.log('[MultiPage:whatsapp-flow] Content script loaded on', location.href);
|
||||
|
||||
@@ -0,0 +1,425 @@
|
||||
(function attachMultiPageOpenAiFlowDefinition(root, factory) {
|
||||
root.MultiPageOpenAiFlowDefinition = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createMultiPageOpenAiFlowDefinition() {
|
||||
function freezeDeep(entry) {
|
||||
if (!entry || typeof entry !== 'object' || Object.isFrozen(entry)) {
|
||||
return entry;
|
||||
}
|
||||
Object.getOwnPropertyNames(entry).forEach((key) => {
|
||||
freezeDeep(entry[key]);
|
||||
});
|
||||
return Object.freeze(entry);
|
||||
}
|
||||
|
||||
const VALUE = freezeDeep({
|
||||
"id": "openai",
|
||||
"label": "Codex / OpenAI",
|
||||
"services": [
|
||||
"account",
|
||||
"email",
|
||||
"proxy"
|
||||
],
|
||||
"capabilities": {
|
||||
"supportsEmailSignup": true,
|
||||
"supportsPhoneSignup": true,
|
||||
"supportsPhoneVerificationSettings": true,
|
||||
"supportsPlusMode": true,
|
||||
"supportsContributionMode": true,
|
||||
"supportsAccountContribution": true,
|
||||
"supportsOpenAiOAuthContribution": true,
|
||||
"contributionAdapterIds": [
|
||||
"openai-oauth",
|
||||
"openai-codex-file",
|
||||
"openai-sub2api-file"
|
||||
],
|
||||
"supportedTargetIds": [
|
||||
"cpa",
|
||||
"sub2api",
|
||||
"codex2api"
|
||||
],
|
||||
"supportsLuckmail": true,
|
||||
"supportsOauthTimeoutBudget": true,
|
||||
"canSwitchFlow": true,
|
||||
"stepDefinitionMode": "openai-dynamic",
|
||||
"targetSelectorLabel": "来源"
|
||||
},
|
||||
"baseGroups": [
|
||||
"openai-plus",
|
||||
"openai-phone",
|
||||
"openai-oauth",
|
||||
"openai-step6"
|
||||
],
|
||||
"targets": {
|
||||
"cpa": {
|
||||
"id": "cpa",
|
||||
"label": "CPA 面板",
|
||||
"groups": [
|
||||
"openai-target-cpa"
|
||||
]
|
||||
},
|
||||
"sub2api": {
|
||||
"id": "sub2api",
|
||||
"label": "SUB2API",
|
||||
"groups": [
|
||||
"openai-target-sub2api"
|
||||
]
|
||||
},
|
||||
"codex2api": {
|
||||
"id": "codex2api",
|
||||
"label": "Codex2API",
|
||||
"groups": [
|
||||
"openai-target-codex2api"
|
||||
]
|
||||
}
|
||||
},
|
||||
"runtimeSources": {
|
||||
"openai-auth": {
|
||||
"flowId": "openai",
|
||||
"kind": "flow-page",
|
||||
"label": "认证页",
|
||||
"readyPolicy": "allow-child-frame",
|
||||
"family": "openai-auth-family",
|
||||
"driverId": "flows/openai/content/openai-auth",
|
||||
"cleanupScopes": [
|
||||
"oauth-localhost-callback"
|
||||
],
|
||||
"detectionMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"auth0.openai.com",
|
||||
"auth.openai.com",
|
||||
"accounts.openai.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"auth0.openai.com",
|
||||
"auth.openai.com",
|
||||
"accounts.openai.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"hostnames": [
|
||||
"chatgpt.com",
|
||||
"www.chatgpt.com",
|
||||
"chat.openai.com"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"chatgpt": {
|
||||
"flowId": "openai",
|
||||
"kind": "flow-entry",
|
||||
"label": "ChatGPT 首页",
|
||||
"readyPolicy": "allow-child-frame",
|
||||
"family": "chatgpt-entry-family",
|
||||
"driverId": null,
|
||||
"cleanupScopes": [],
|
||||
"detectionMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"chatgpt.com",
|
||||
"www.chatgpt.com",
|
||||
"chat.openai.com"
|
||||
]
|
||||
}
|
||||
],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"chatgpt.com",
|
||||
"www.chatgpt.com",
|
||||
"chat.openai.com"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"vps-panel": {
|
||||
"flowId": "openai",
|
||||
"kind": "panel-page",
|
||||
"label": "CPA 面板",
|
||||
"readyPolicy": "allow-child-frame",
|
||||
"family": "vps-panel-family",
|
||||
"driverId": "flows/openai/content/vps-panel",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"originEqualsReference": true,
|
||||
"pathEqualsReference": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"platform-panel": {
|
||||
"flowId": "openai",
|
||||
"kind": "virtual-page",
|
||||
"label": "平台回调面板",
|
||||
"readyPolicy": "disabled",
|
||||
"family": "platform-panel-family",
|
||||
"driverId": "content/platform-panel",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": []
|
||||
},
|
||||
"sub2api-panel": {
|
||||
"flowId": "openai",
|
||||
"kind": "panel-page",
|
||||
"label": "SUB2API 后台",
|
||||
"readyPolicy": "allow-child-frame",
|
||||
"family": "sub2api-panel-family",
|
||||
"driverId": "flows/openai/content/sub2api-panel",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"originEqualsReference": true,
|
||||
"pathPrefixes": [
|
||||
"/admin/accounts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"originEqualsReference": true,
|
||||
"pathPrefixes": [
|
||||
"/login"
|
||||
]
|
||||
},
|
||||
{
|
||||
"originEqualsReference": true,
|
||||
"pathEqualsOneOf": [
|
||||
"/"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"codex2api-panel": {
|
||||
"flowId": "openai",
|
||||
"kind": "panel-page",
|
||||
"label": "Codex2API 后台",
|
||||
"readyPolicy": "allow-child-frame",
|
||||
"family": "codex2api-panel-family",
|
||||
"driverId": "flows/openai/content/sub2api-panel",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"originEqualsReference": true,
|
||||
"pathPrefixes": [
|
||||
"/admin/accounts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"originEqualsReference": true,
|
||||
"pathEqualsOneOf": [
|
||||
"/admin",
|
||||
"/"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"plus-checkout": {
|
||||
"flowId": "openai",
|
||||
"kind": "flow-page",
|
||||
"label": "Plus Checkout",
|
||||
"readyPolicy": "top-frame-only",
|
||||
"family": "plus-checkout-family",
|
||||
"driverId": "flows/openai/content/plus-checkout",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"hostnames": [
|
||||
"chatgpt.com"
|
||||
],
|
||||
"pathPrefixes": [
|
||||
"/checkout/"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"paypal-flow": {
|
||||
"flowId": "openai",
|
||||
"kind": "flow-page",
|
||||
"label": "PayPal 授权页",
|
||||
"readyPolicy": "allow-child-frame",
|
||||
"family": "paypal-flow-family",
|
||||
"driverId": "flows/openai/content/paypal-flow",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"hostnameEndsWith": [
|
||||
"paypal.com"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gopay-flow": {
|
||||
"flowId": "openai",
|
||||
"kind": "flow-page",
|
||||
"label": "GoPay 授权页",
|
||||
"readyPolicy": "allow-child-frame",
|
||||
"family": "gopay-flow-family",
|
||||
"driverId": "flows/openai/content/gopay-flow",
|
||||
"cleanupScopes": [],
|
||||
"familyMatchers": [
|
||||
{
|
||||
"hostnameRegex": "gopay|gojek",
|
||||
"hostnameRegexFlags": "i"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"driverDefinitions": {
|
||||
"flows/openai/content/openai-auth": {
|
||||
"sourceId": "openai-auth",
|
||||
"commands": [
|
||||
"submit-signup-email",
|
||||
"fill-password",
|
||||
"fill-profile",
|
||||
"oauth-login",
|
||||
"submit-verification-code",
|
||||
"post-login-phone-verification",
|
||||
"bind-email",
|
||||
"fetch-bind-email-code",
|
||||
"confirm-oauth",
|
||||
"detect-auth-state"
|
||||
]
|
||||
},
|
||||
"flows/openai/content/sub2api-panel": {
|
||||
"sourceId": "sub2api-panel",
|
||||
"commands": [
|
||||
"open-panel",
|
||||
"fetch-oauth-url",
|
||||
"platform-verify"
|
||||
]
|
||||
},
|
||||
"flows/openai/content/vps-panel": {
|
||||
"sourceId": "vps-panel",
|
||||
"commands": [
|
||||
"open-panel",
|
||||
"fetch-oauth-url",
|
||||
"platform-verify"
|
||||
]
|
||||
},
|
||||
"content/platform-panel": {
|
||||
"sourceId": "platform-panel",
|
||||
"commands": [
|
||||
"platform-verify",
|
||||
"fetch-oauth-url"
|
||||
]
|
||||
},
|
||||
"flows/openai/content/plus-checkout": {
|
||||
"sourceId": "plus-checkout",
|
||||
"commands": [
|
||||
"plus-checkout-create",
|
||||
"paypal-hosted-openai-checkout",
|
||||
"plus-checkout-billing",
|
||||
"plus-checkout-return"
|
||||
]
|
||||
},
|
||||
"flows/openai/content/paypal-flow": {
|
||||
"sourceId": "paypal-flow",
|
||||
"commands": [
|
||||
"paypal-approve",
|
||||
"paypal-hosted-email",
|
||||
"paypal-hosted-card",
|
||||
"paypal-hosted-create-account",
|
||||
"paypal-hosted-review"
|
||||
]
|
||||
},
|
||||
"flows/openai/content/gopay-flow": {
|
||||
"sourceId": "gopay-flow",
|
||||
"commands": [
|
||||
"gopay-subscription-confirm"
|
||||
]
|
||||
}
|
||||
},
|
||||
"defaultTargetId": "cpa",
|
||||
"settingsGroups": {
|
||||
"openai-target-cpa": {
|
||||
"id": "openai-target-cpa",
|
||||
"label": "CPA 来源",
|
||||
"rowIds": [
|
||||
"row-vps-url",
|
||||
"row-vps-password",
|
||||
"row-local-cpa-step9-mode"
|
||||
]
|
||||
},
|
||||
"openai-target-sub2api": {
|
||||
"id": "openai-target-sub2api",
|
||||
"label": "SUB2API 来源",
|
||||
"rowIds": [
|
||||
"row-sub2api-url",
|
||||
"row-sub2api-email",
|
||||
"row-sub2api-password",
|
||||
"row-sub2api-group",
|
||||
"row-sub2api-account-priority",
|
||||
"row-sub2api-default-proxy"
|
||||
]
|
||||
},
|
||||
"openai-target-codex2api": {
|
||||
"id": "openai-target-codex2api",
|
||||
"label": "Codex2API 来源",
|
||||
"rowIds": [
|
||||
"row-codex2api-url",
|
||||
"row-codex2api-admin-key"
|
||||
]
|
||||
},
|
||||
"openai-plus": {
|
||||
"id": "openai-plus",
|
||||
"label": "Plus",
|
||||
"rowIds": [
|
||||
"row-plus-mode",
|
||||
"row-plus-account-access-strategy",
|
||||
"row-plus-payment-method"
|
||||
]
|
||||
},
|
||||
"openai-phone": {
|
||||
"id": "openai-phone",
|
||||
"label": "接码设置",
|
||||
"sectionIds": [
|
||||
"phone-verification-section"
|
||||
],
|
||||
"rowIds": []
|
||||
},
|
||||
"openai-oauth": {
|
||||
"id": "openai-oauth",
|
||||
"label": "OAuth",
|
||||
"rowIds": [
|
||||
"row-oauth-flow-timeout",
|
||||
"row-oauth-display"
|
||||
]
|
||||
},
|
||||
"openai-step6": {
|
||||
"id": "openai-step6",
|
||||
"label": "第六步",
|
||||
"rowIds": [
|
||||
"row-step6-cookie-settings"
|
||||
]
|
||||
}
|
||||
},
|
||||
"targetCapabilities": {
|
||||
"cpa": {
|
||||
"supportsPhoneSignup": true,
|
||||
"requiresPhoneSignupWarning": true,
|
||||
"supportedPlusAccountAccessStrategies": [
|
||||
"oauth",
|
||||
"cpa_codex_session"
|
||||
]
|
||||
},
|
||||
"sub2api": {
|
||||
"supportsPhoneSignup": true,
|
||||
"requiresPhoneSignupWarning": false,
|
||||
"supportedPlusAccountAccessStrategies": [
|
||||
"oauth",
|
||||
"sub2api_codex_session"
|
||||
]
|
||||
},
|
||||
"codex2api": {
|
||||
"supportsPhoneSignup": true,
|
||||
"requiresPhoneSignupWarning": false,
|
||||
"supportedPlusAccountAccessStrategies": [
|
||||
"oauth"
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return VALUE;
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
(function attachLegacyAccountRecordsImporter(root, factory) {
|
||||
root.MultiPageLegacyAccountRecordsImporter = factory(root);
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createLegacyAccountRecordsImporterModule(root) {
|
||||
function createAccountRecordsImporter(deps = {}) {
|
||||
const createAccountRunHistoryHelpers = deps.createAccountRunHistoryHelpers
|
||||
|| root.MultiPageBackgroundAccountRunHistory?.createAccountRunHistoryHelpers;
|
||||
|
||||
function importAccountRecords(records = []) {
|
||||
if (!Array.isArray(records)) {
|
||||
throw new Error('账号记录导入内容必须是数组。');
|
||||
}
|
||||
if (typeof createAccountRunHistoryHelpers !== 'function') {
|
||||
return records
|
||||
.filter((record) => Boolean(record) && typeof record === 'object' && !Array.isArray(record))
|
||||
.map((record) => ({ ...record }));
|
||||
}
|
||||
|
||||
const helpers = createAccountRunHistoryHelpers({
|
||||
chrome: deps.chrome || {
|
||||
storage: {
|
||||
local: {
|
||||
get: async () => ({}),
|
||||
set: async () => {},
|
||||
},
|
||||
},
|
||||
},
|
||||
getState: deps.getState || (async () => ({})),
|
||||
addLog: deps.addLog || (async () => {}),
|
||||
getNodeIdByStepForState: deps.getNodeIdByStepForState || (() => ''),
|
||||
normalizeAccountRunHistoryHelperBaseUrl: deps.normalizeAccountRunHistoryHelperBaseUrl
|
||||
|| ((value) => String(value || '').trim()),
|
||||
});
|
||||
if (typeof helpers?.normalizeAccountRunHistory !== 'function') {
|
||||
return [];
|
||||
}
|
||||
return helpers.normalizeAccountRunHistory(records);
|
||||
}
|
||||
|
||||
return {
|
||||
importAccountRecords,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createAccountRecordsImporter,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,142 @@
|
||||
(function attachLegacySettingsImporter(root, factory) {
|
||||
root.MultiPageLegacySettingsImporter = factory(root);
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createLegacySettingsImporterModule(root) {
|
||||
const LEGACY_TOP_LEVEL_KEYS = Object.freeze([
|
||||
'panelMode',
|
||||
'openaiIntegrationTargetId',
|
||||
'kiroTargetId',
|
||||
'stepExecutionRangeByFlow',
|
||||
'kiroRuntime',
|
||||
]);
|
||||
|
||||
function isPlainObject(value) {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function cloneValue(value) {
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((entry) => cloneValue(entry));
|
||||
}
|
||||
if (isPlainObject(value)) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).map(([key, entryValue]) => [key, cloneValue(entryValue)])
|
||||
);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function collectLegacyFieldHits(input = {}) {
|
||||
if (!isPlainObject(input)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const hits = [];
|
||||
LEGACY_TOP_LEVEL_KEYS.forEach((key) => {
|
||||
if (Object.prototype.hasOwnProperty.call(input, key)) {
|
||||
hits.push(key);
|
||||
}
|
||||
});
|
||||
|
||||
const settingsState = isPlainObject(input.settingsState) ? input.settingsState : {};
|
||||
const openaiSettings = isPlainObject(settingsState?.flows?.openai) ? settingsState.flows.openai : {};
|
||||
const kiroSettings = isPlainObject(settingsState?.flows?.kiro) ? settingsState.flows.kiro : {};
|
||||
if (Object.prototype.hasOwnProperty.call(openaiSettings, 'integrationTargetId')) {
|
||||
hits.push('settingsState.flows.openai.integrationTargetId');
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(openaiSettings, 'integrationTargets')) {
|
||||
hits.push('settingsState.flows.openai.integrationTargets');
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(kiroSettings, 'targetId')) {
|
||||
hits.push('settingsState.flows.kiro.targetId');
|
||||
}
|
||||
|
||||
return Array.from(new Set(hits));
|
||||
}
|
||||
|
||||
function resolveSettingsSchemaApi(deps = {}) {
|
||||
if (deps.settingsSchemaApi?.normalizeSettingsState && deps.settingsSchemaApi?.buildSettingsView) {
|
||||
return deps.settingsSchemaApi;
|
||||
}
|
||||
const settingsSchemaModule = deps.settingsSchemaModule || root.MultiPageSettingsSchema || null;
|
||||
if (typeof settingsSchemaModule?.createSettingsSchema !== 'function') {
|
||||
return null;
|
||||
}
|
||||
return settingsSchemaModule.createSettingsSchema({
|
||||
flowRegistry: deps.flowRegistry || root.MultiPageFlowRegistry || null,
|
||||
defaultFlowId: deps.defaultFlowId,
|
||||
});
|
||||
}
|
||||
|
||||
function buildImportInput(input = {}) {
|
||||
const next = isPlainObject(input) ? cloneValue(input) : {};
|
||||
const settingsState = isPlainObject(next.settingsState) ? next.settingsState : {};
|
||||
const flows = isPlainObject(settingsState.flows) ? settingsState.flows : {};
|
||||
const openaiState = isPlainObject(flows.openai) ? flows.openai : {};
|
||||
const kiroState = isPlainObject(flows.kiro) ? flows.kiro : {};
|
||||
const legacyOpenAiTargetId = String(
|
||||
input?.openaiIntegrationTargetId
|
||||
?? input?.panelMode
|
||||
?? ''
|
||||
).trim();
|
||||
const legacyKiroTargetId = String(input?.kiroTargetId ?? '').trim();
|
||||
const openaiHasCanonicalTarget = Object.prototype.hasOwnProperty.call(openaiState, 'selectedTargetId')
|
||||
|| Object.prototype.hasOwnProperty.call(openaiState, 'integrationTargetId');
|
||||
const kiroHasCanonicalTarget = Object.prototype.hasOwnProperty.call(kiroState, 'selectedTargetId')
|
||||
|| Object.prototype.hasOwnProperty.call(kiroState, 'targetId');
|
||||
|
||||
if (!openaiHasCanonicalTarget && legacyOpenAiTargetId) {
|
||||
next.settingsState = settingsState;
|
||||
next.settingsState.flows = flows;
|
||||
next.settingsState.flows.openai = {
|
||||
...openaiState,
|
||||
selectedTargetId: legacyOpenAiTargetId,
|
||||
};
|
||||
}
|
||||
|
||||
if (!kiroHasCanonicalTarget && legacyKiroTargetId) {
|
||||
next.settingsState = next.settingsState || settingsState;
|
||||
next.settingsState.flows = next.settingsState.flows || flows;
|
||||
next.settingsState.flows.kiro = {
|
||||
...kiroState,
|
||||
selectedTargetId: legacyKiroTargetId,
|
||||
};
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
function createSettingsImporter(deps = {}) {
|
||||
const settingsSchemaApi = resolveSettingsSchemaApi(deps);
|
||||
|
||||
function importSettings(input = {}) {
|
||||
if (!isPlainObject(input)) {
|
||||
throw new Error('配置文件中的 settings 内容无效。');
|
||||
}
|
||||
if (!settingsSchemaApi?.normalizeSettingsState) {
|
||||
throw new Error('设置导入器未完成初始化。');
|
||||
}
|
||||
|
||||
const importInput = buildImportInput(input);
|
||||
const normalizedState = settingsSchemaApi.normalizeSettingsState(importInput, {
|
||||
activeFlowId: importInput.activeFlowId || importInput.flowId || deps.defaultFlowId,
|
||||
});
|
||||
|
||||
return {
|
||||
settingsSchemaVersion: Number(normalizedState.schemaVersion) || 0,
|
||||
settingsState: cloneValue(normalizedState),
|
||||
legacyFieldHits: collectLegacyFieldHits(input),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
collectLegacyFieldHits,
|
||||
importSettings,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
LEGACY_TOP_LEVEL_KEYS,
|
||||
collectLegacyFieldHits,
|
||||
createSettingsImporter,
|
||||
};
|
||||
});
|
||||
+29
-9
@@ -49,13 +49,17 @@
|
||||
],
|
||||
"js": [
|
||||
"content/activation-utils.js",
|
||||
"shared/source-registry.js",
|
||||
"flows/openai/index.js",
|
||||
"flows/kiro/index.js",
|
||||
"flows/index.js",
|
||||
"core/flow-kernel/flow-registry.js",
|
||||
"core/flow-kernel/source-registry.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"
|
||||
"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"
|
||||
],
|
||||
"run_at": "document_idle"
|
||||
},
|
||||
@@ -66,7 +70,11 @@
|
||||
],
|
||||
"js": [
|
||||
"content/activation-utils.js",
|
||||
"shared/source-registry.js",
|
||||
"flows/openai/index.js",
|
||||
"flows/kiro/index.js",
|
||||
"flows/index.js",
|
||||
"core/flow-kernel/flow-registry.js",
|
||||
"core/flow-kernel/source-registry.js",
|
||||
"content/utils.js",
|
||||
"content/qq-mail.js"
|
||||
],
|
||||
@@ -83,7 +91,11 @@
|
||||
],
|
||||
"js": [
|
||||
"content/activation-utils.js",
|
||||
"shared/source-registry.js",
|
||||
"flows/openai/index.js",
|
||||
"flows/kiro/index.js",
|
||||
"flows/index.js",
|
||||
"core/flow-kernel/flow-registry.js",
|
||||
"core/flow-kernel/source-registry.js",
|
||||
"content/utils.js",
|
||||
"content/mail-163.js"
|
||||
],
|
||||
@@ -97,7 +109,11 @@
|
||||
],
|
||||
"js": [
|
||||
"content/activation-utils.js",
|
||||
"shared/source-registry.js",
|
||||
"flows/openai/index.js",
|
||||
"flows/kiro/index.js",
|
||||
"flows/index.js",
|
||||
"core/flow-kernel/flow-registry.js",
|
||||
"core/flow-kernel/source-registry.js",
|
||||
"content/utils.js",
|
||||
"content/icloud-mail.js"
|
||||
],
|
||||
@@ -110,7 +126,11 @@
|
||||
],
|
||||
"js": [
|
||||
"content/activation-utils.js",
|
||||
"shared/source-registry.js",
|
||||
"flows/openai/index.js",
|
||||
"flows/kiro/index.js",
|
||||
"flows/index.js",
|
||||
"core/flow-kernel/flow-registry.js",
|
||||
"core/flow-kernel/source-registry.js",
|
||||
"content/utils.js",
|
||||
"content/operation-delay.js",
|
||||
"content/duck-mail.js"
|
||||
|
||||
@@ -21,21 +21,21 @@
|
||||
主仓库 `codex注册扩展` 已重点阅读:
|
||||
|
||||
- `data/step-definitions.js`
|
||||
- `shared/flow-capabilities.js`
|
||||
- `shared/flow-registry.js`
|
||||
- `shared/settings-schema.js`
|
||||
- `core/flow-kernel/flow-capabilities.js`
|
||||
- `core/flow-kernel/flow-registry.js`
|
||||
- `core/flow-kernel/settings-schema.js`
|
||||
- `sidepanel/sidepanel.html`
|
||||
- `sidepanel/sidepanel.js`
|
||||
- `background.js`
|
||||
- `background/runtime-state.js`
|
||||
- `core/flow-kernel/runtime-state.js`
|
||||
- `background/message-router.js`
|
||||
- `background/panel-bridge.js`
|
||||
- `background/sub2api-api.js`
|
||||
- `background/steps/platform-verify.js`
|
||||
- `background/steps/create-plus-checkout.js`
|
||||
- `background/steps/fill-plus-checkout.js`
|
||||
- `background/steps/plus-return-confirm.js`
|
||||
- `content/plus-checkout.js`
|
||||
- `flows/openai/background/steps/platform-verify.js`
|
||||
- `flows/openai/background/steps/create-plus-checkout.js`
|
||||
- `flows/openai/background/steps/fill-plus-checkout.js`
|
||||
- `flows/openai/background/steps/plus-return-confirm.js`
|
||||
- `flows/openai/content/plus-checkout.js`
|
||||
- `tests/step-definitions-module.test.js`
|
||||
- `tests/sidepanel-plus-payment-method.test.js`
|
||||
- `tests/flow-capabilities-module.test.js`
|
||||
@@ -125,7 +125,7 @@
|
||||
1. 通过 `background/panel-bridge.js` 请求 `background/sub2api-api.js` 生成 OAuth URL
|
||||
2. 保存 `oauthUrl / sub2apiSessionId / sub2apiOAuthState`
|
||||
3. 页面完成 OAuth 回调,拿到 `localhostUrl`
|
||||
4. `background/steps/platform-verify.js` 调 `submitOpenAiCallback`
|
||||
4. `flows/openai/background/steps/platform-verify.js` 调 `submitOpenAiCallback`
|
||||
5. SUB2API 用 `exchange-code` 交换 OAuth code,再创建账号
|
||||
|
||||
这条链路是“完整 OAuth 账号创建”,不是导入现有 ChatGPT Web session。
|
||||
@@ -140,8 +140,8 @@
|
||||
|
||||
现成能力位置:
|
||||
|
||||
- `content/plus-checkout.js`
|
||||
- `background/steps/create-plus-checkout.js`
|
||||
- `flows/openai/content/plus-checkout.js`
|
||||
- `flows/openai/background/steps/create-plus-checkout.js`
|
||||
|
||||
这意味着新功能不需要再发明“如何拿 session”,只需要把这份能力接到 Plus 尾链上。
|
||||
|
||||
@@ -258,7 +258,7 @@
|
||||
- `select-plus-account-access-strategy`
|
||||
- `plus-account-access-strategy-caption`
|
||||
|
||||
`shared/flow-registry.js` 的 `openai-plus` 设置组应扩展为同时包含:
|
||||
`core/flow-kernel/flow-registry.js` 的 `openai-plus` 设置组应扩展为同时包含:
|
||||
|
||||
- `row-plus-mode`
|
||||
- `row-plus-payment-method`
|
||||
@@ -364,13 +364,13 @@ Session 导入策略生效时,替换锚点如下:
|
||||
|
||||
建议新增后台执行器文件:
|
||||
|
||||
- `background/steps/sub2api-session-import.js`
|
||||
- `flows/openai/background/steps/sub2api-session-import.js`
|
||||
|
||||
执行器职责:
|
||||
|
||||
1. 定位当前 Plus 会话页对应 tab
|
||||
2. 确认当前 tab 已回到 ChatGPT / OpenAI 域名页面,且可访问 `/api/auth/session`
|
||||
3. 通过现有 `content/plus-checkout.js` 能力读取:
|
||||
3. 通过现有 `flows/openai/content/plus-checkout.js` 能力读取:
|
||||
- `session`
|
||||
- `accessToken`
|
||||
4. 用现有 `background/sub2api-api.js` 登录 SUB2API
|
||||
@@ -477,13 +477,13 @@ Session 导入策略生效时,替换锚点如下:
|
||||
|
||||
而不是去复用旧的:
|
||||
|
||||
- `content/sub2api-panel.js`
|
||||
- `flows/openai/content/sub2api-panel.js`
|
||||
|
||||
原因:
|
||||
|
||||
1. 当前主链路已迁移到 `background/sub2api-api.js`
|
||||
2. session 导入需要登录、查分组、查代理、发导入请求,这些都属于后台 API 编排
|
||||
3. 继续往 `content/sub2api-panel.js` 塞逻辑会造成双实现
|
||||
3. 继续往 `flows/openai/content/sub2api-panel.js` 塞逻辑会造成双实现
|
||||
|
||||
建议新增 API 方法:
|
||||
|
||||
@@ -503,7 +503,7 @@ Session 导入策略生效时,替换锚点如下:
|
||||
|
||||
- `background/panel-bridge.js` 继续只负责“跨 target 的 OAuth URL 申请桥接”
|
||||
- session 导入不要硬塞进 `requestOAuthUrlFromPanel`
|
||||
- `background/steps/platform-verify.js` 继续只处理 callback 型平台验证
|
||||
- `flows/openai/background/steps/platform-verify.js` 继续只处理 callback 型平台验证
|
||||
- `sub2api-session-import` 走独立后台执行器,不混进 `platform-verify`
|
||||
|
||||
## 5.7 后台总控与运行态设计
|
||||
@@ -599,7 +599,7 @@ Session 导入策略生效时,替换锚点如下:
|
||||
|
||||
### 5.8.1 settings-schema
|
||||
|
||||
`shared/settings-schema.js` 需要在:
|
||||
`core/flow-kernel/settings-schema.js` 需要在:
|
||||
|
||||
- `flows.openai.plus`
|
||||
|
||||
@@ -647,7 +647,7 @@ Session 导入策略生效时,替换锚点如下:
|
||||
|
||||
### 5.9.1 不要把策略可用性写死在 UI
|
||||
|
||||
应扩展 `shared/flow-capabilities.js`,让它输出:
|
||||
应扩展 `core/flow-kernel/flow-capabilities.js`,让它输出:
|
||||
|
||||
- `requestedPlusAccountAccessStrategy`
|
||||
- `effectivePlusAccountAccessStrategy`
|
||||
@@ -821,9 +821,9 @@ session strategy 下这些逻辑全部不适用。
|
||||
|
||||
### 涉及文件
|
||||
|
||||
- `shared/settings-schema.js`
|
||||
- `shared/flow-capabilities.js`
|
||||
- `shared/flow-registry.js`
|
||||
- `core/flow-kernel/settings-schema.js`
|
||||
- `core/flow-kernel/flow-capabilities.js`
|
||||
- `core/flow-kernel/flow-registry.js`
|
||||
- `sidepanel/sidepanel.html`
|
||||
- `sidepanel/sidepanel.js`
|
||||
- `background.js`
|
||||
@@ -889,10 +889,10 @@ session strategy 下这些逻辑全部不适用。
|
||||
### 涉及文件
|
||||
|
||||
- `background/sub2api-api.js`
|
||||
- `background/steps/sub2api-session-import.js`
|
||||
- `background/steps/registry.js` 或后台节点注册处
|
||||
- `content/plus-checkout.js`
|
||||
- `background/steps/create-plus-checkout.js`
|
||||
- `flows/openai/background/steps/sub2api-session-import.js`
|
||||
- `core/flow-kernel/step-registry.js` 或后台节点注册处
|
||||
- `flows/openai/content/plus-checkout.js`
|
||||
- `flows/openai/background/steps/create-plus-checkout.js`
|
||||
|
||||
### 完成标准
|
||||
|
||||
@@ -920,9 +920,9 @@ session strategy 下这些逻辑全部不适用。
|
||||
### 涉及文件
|
||||
|
||||
- `background.js`
|
||||
- `background/runtime-state.js`
|
||||
- `core/flow-kernel/runtime-state.js`
|
||||
- `background/message-router.js`
|
||||
- `background/steps/platform-verify.js`
|
||||
- `flows/openai/background/steps/platform-verify.js`
|
||||
- `background/panel-bridge.js`
|
||||
- 自动运行 / auth-chain 相关测试
|
||||
|
||||
|
||||
@@ -1,582 +0,0 @@
|
||||
(function attachMultiPageFlowRegistry(root, factory) {
|
||||
root.MultiPageFlowRegistry = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createFlowRegistryModule() {
|
||||
const DEFAULT_FLOW_ID = 'openai';
|
||||
const DEFAULT_OPENAI_TARGET_ID = 'cpa';
|
||||
const DEFAULT_KIRO_TARGET_ID = 'kiro-rs';
|
||||
const DEFAULT_KIRO_PUBLICATION_TARGET_ID = 'kiro-rs';
|
||||
const DEFAULT_KIRO_RS_URL = '';
|
||||
const OPENAI_TARGET_IDS = Object.freeze(['cpa', 'sub2api', 'codex2api']);
|
||||
const SHARED_SERVICE_IDS = Object.freeze(['account', 'email', 'proxy']);
|
||||
|
||||
const DEFAULT_FLOW_CAPABILITIES = Object.freeze({
|
||||
supportsEmailSignup: true,
|
||||
supportsPhoneSignup: false,
|
||||
supportsPhoneVerificationSettings: false,
|
||||
supportsPlusMode: false,
|
||||
supportsContributionMode: false,
|
||||
supportsAccountContribution: false,
|
||||
supportsOpenAiOAuthContribution: false,
|
||||
contributionAdapterIds: [],
|
||||
supportedTargetIds: [],
|
||||
supportsLuckmail: false,
|
||||
supportsOauthTimeoutBudget: false,
|
||||
canSwitchFlow: true,
|
||||
stepDefinitionMode: 'default',
|
||||
targetSelectorLabel: '来源',
|
||||
});
|
||||
|
||||
function freezeDeep(value) {
|
||||
if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
|
||||
return value;
|
||||
}
|
||||
Object.getOwnPropertyNames(value).forEach((key) => {
|
||||
freezeDeep(value[key]);
|
||||
});
|
||||
return Object.freeze(value);
|
||||
}
|
||||
|
||||
const FLOW_DEFINITIONS = freezeDeep({
|
||||
openai: {
|
||||
id: 'openai',
|
||||
label: 'Codex / OpenAI',
|
||||
services: ['account', 'email', 'proxy'],
|
||||
capabilities: {
|
||||
...DEFAULT_FLOW_CAPABILITIES,
|
||||
supportsPhoneSignup: true,
|
||||
supportsPhoneVerificationSettings: true,
|
||||
supportsPlusMode: true,
|
||||
supportsContributionMode: true,
|
||||
supportsAccountContribution: true,
|
||||
supportsOpenAiOAuthContribution: true,
|
||||
contributionAdapterIds: ['openai-oauth', 'openai-codex-file', 'openai-sub2api-file'],
|
||||
supportedTargetIds: [...OPENAI_TARGET_IDS],
|
||||
supportsLuckmail: true,
|
||||
supportsOauthTimeoutBudget: true,
|
||||
stepDefinitionMode: 'openai-dynamic',
|
||||
},
|
||||
baseGroups: [
|
||||
'openai-plus',
|
||||
'openai-phone',
|
||||
'openai-oauth',
|
||||
'openai-step6',
|
||||
],
|
||||
targets: {
|
||||
cpa: {
|
||||
id: 'cpa',
|
||||
label: 'CPA 面板',
|
||||
groups: ['openai-target-cpa'],
|
||||
},
|
||||
sub2api: {
|
||||
id: 'sub2api',
|
||||
label: 'SUB2API',
|
||||
groups: ['openai-target-sub2api'],
|
||||
},
|
||||
codex2api: {
|
||||
id: 'codex2api',
|
||||
label: 'Codex2API',
|
||||
groups: ['openai-target-codex2api'],
|
||||
},
|
||||
},
|
||||
runtimeSources: {
|
||||
'openai-auth': {
|
||||
flowId: 'openai',
|
||||
kind: 'flow-page',
|
||||
label: '认证页',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'openai-auth-family',
|
||||
driverId: 'content/signup-page',
|
||||
cleanupScopes: ['oauth-localhost-callback'],
|
||||
},
|
||||
chatgpt: {
|
||||
flowId: 'openai',
|
||||
kind: 'flow-entry',
|
||||
label: 'ChatGPT 首页',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'chatgpt-entry-family',
|
||||
driverId: null,
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'vps-panel': {
|
||||
flowId: 'openai',
|
||||
kind: 'panel-page',
|
||||
label: 'CPA 面板',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'vps-panel-family',
|
||||
driverId: 'content/vps-panel',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'platform-panel': {
|
||||
flowId: 'openai',
|
||||
kind: 'virtual-page',
|
||||
label: '平台回调面板',
|
||||
readyPolicy: 'disabled',
|
||||
family: 'platform-panel-family',
|
||||
driverId: 'content/platform-panel',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'sub2api-panel': {
|
||||
flowId: 'openai',
|
||||
kind: 'panel-page',
|
||||
label: 'SUB2API 后台',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'sub2api-panel-family',
|
||||
driverId: 'content/sub2api-panel',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'codex2api-panel': {
|
||||
flowId: 'openai',
|
||||
kind: 'panel-page',
|
||||
label: 'Codex2API 后台',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'codex2api-panel-family',
|
||||
driverId: 'content/sub2api-panel',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'plus-checkout': {
|
||||
flowId: 'openai',
|
||||
kind: 'flow-page',
|
||||
label: 'Plus Checkout',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'plus-checkout-family',
|
||||
driverId: 'content/plus-checkout',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'paypal-flow': {
|
||||
flowId: 'openai',
|
||||
kind: 'flow-page',
|
||||
label: 'PayPal 授权页',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'paypal-flow-family',
|
||||
driverId: 'content/paypal-flow',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'gopay-flow': {
|
||||
flowId: 'openai',
|
||||
kind: 'flow-page',
|
||||
label: 'GoPay 授权页',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'gopay-flow-family',
|
||||
driverId: 'content/gopay-flow',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
},
|
||||
driverDefinitions: {
|
||||
'content/signup-page': {
|
||||
sourceId: 'openai-auth',
|
||||
commands: [
|
||||
'submit-signup-email',
|
||||
'fill-password',
|
||||
'fill-profile',
|
||||
'oauth-login',
|
||||
'submit-verification-code',
|
||||
'post-login-phone-verification',
|
||||
'bind-email',
|
||||
'fetch-bind-email-code',
|
||||
'confirm-oauth',
|
||||
'detect-auth-state',
|
||||
],
|
||||
},
|
||||
'content/sub2api-panel': {
|
||||
sourceId: 'sub2api-panel',
|
||||
commands: ['open-panel', 'fetch-oauth-url', 'platform-verify'],
|
||||
},
|
||||
'content/vps-panel': {
|
||||
sourceId: 'vps-panel',
|
||||
commands: ['open-panel', 'fetch-oauth-url', 'platform-verify'],
|
||||
},
|
||||
'content/platform-panel': {
|
||||
sourceId: 'platform-panel',
|
||||
commands: ['platform-verify', 'fetch-oauth-url'],
|
||||
},
|
||||
'content/plus-checkout': {
|
||||
sourceId: 'plus-checkout',
|
||||
commands: [
|
||||
'plus-checkout-create',
|
||||
'paypal-hosted-openai-checkout',
|
||||
'plus-checkout-billing',
|
||||
'plus-checkout-return',
|
||||
],
|
||||
},
|
||||
'content/paypal-flow': {
|
||||
sourceId: 'paypal-flow',
|
||||
commands: [
|
||||
'paypal-approve',
|
||||
'paypal-hosted-email',
|
||||
'paypal-hosted-card',
|
||||
'paypal-hosted-create-account',
|
||||
'paypal-hosted-review',
|
||||
],
|
||||
},
|
||||
'content/gopay-flow': {
|
||||
sourceId: 'gopay-flow',
|
||||
commands: ['gopay-subscription-confirm'],
|
||||
},
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
id: 'kiro',
|
||||
label: 'Kiro',
|
||||
services: ['account', 'email', 'proxy'],
|
||||
capabilities: {
|
||||
...DEFAULT_FLOW_CAPABILITIES,
|
||||
supportsAccountContribution: true,
|
||||
contributionAdapterIds: ['kiro-builder-id'],
|
||||
supportedTargetIds: [DEFAULT_KIRO_TARGET_ID],
|
||||
stepDefinitionMode: 'kiro',
|
||||
},
|
||||
baseGroups: [
|
||||
'kiro-runtime-status',
|
||||
],
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
id: 'kiro-rs',
|
||||
label: 'kiro.rs',
|
||||
groups: ['kiro-target-kiro-rs'],
|
||||
},
|
||||
},
|
||||
publicationTargets: {
|
||||
'kiro-rs': {
|
||||
id: 'kiro-rs',
|
||||
label: 'kiro.rs',
|
||||
},
|
||||
},
|
||||
runtimeSources: {
|
||||
'kiro-register-page': {
|
||||
flowId: 'kiro',
|
||||
kind: 'flow-page',
|
||||
label: 'Kiro 注册页',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'kiro-register-page-family',
|
||||
driverId: 'content/kiro/register-page',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'kiro-desktop-authorize': {
|
||||
flowId: 'kiro',
|
||||
kind: 'flow-page',
|
||||
label: 'Kiro 桌面授权页',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'kiro-desktop-authorize-family',
|
||||
driverId: 'content/kiro/desktop-authorize-page',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'kiro-rs-admin': {
|
||||
flowId: 'kiro',
|
||||
kind: 'virtual-page',
|
||||
label: 'kiro.rs Admin',
|
||||
readyPolicy: 'disabled',
|
||||
family: 'kiro-rs-admin-family',
|
||||
driverId: null,
|
||||
cleanupScopes: [],
|
||||
},
|
||||
},
|
||||
driverDefinitions: {
|
||||
'content/kiro/register-page': {
|
||||
sourceId: 'kiro-register-page',
|
||||
commands: [
|
||||
'kiro-open-register-page',
|
||||
'kiro-submit-email',
|
||||
'kiro-submit-name',
|
||||
'kiro-submit-verification-code',
|
||||
'kiro-submit-password',
|
||||
'kiro-complete-register-consent',
|
||||
],
|
||||
},
|
||||
'content/kiro/desktop-authorize-page': {
|
||||
sourceId: 'kiro-desktop-authorize',
|
||||
commands: [
|
||||
'kiro-complete-desktop-authorize',
|
||||
],
|
||||
},
|
||||
'background/kiro-register': {
|
||||
sourceId: 'kiro-register-page',
|
||||
commands: [
|
||||
'kiro-open-register-page',
|
||||
'kiro-submit-email',
|
||||
'kiro-submit-name',
|
||||
'kiro-submit-verification-code',
|
||||
'kiro-submit-password',
|
||||
'kiro-complete-register-consent',
|
||||
],
|
||||
},
|
||||
'background/kiro-desktop-authorize': {
|
||||
sourceId: 'kiro-desktop-authorize',
|
||||
commands: [
|
||||
'kiro-start-desktop-authorize',
|
||||
'kiro-complete-desktop-authorize',
|
||||
],
|
||||
},
|
||||
'background/kiro-publisher-kiro-rs': {
|
||||
sourceId: 'kiro-rs-admin',
|
||||
commands: [
|
||||
'kiro-upload-credential',
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const SETTINGS_GROUP_DEFINITIONS = freezeDeep({
|
||||
'service-account': {
|
||||
id: 'service-account',
|
||||
label: '账户',
|
||||
rowIds: ['row-custom-password'],
|
||||
},
|
||||
'service-email': {
|
||||
id: 'service-email',
|
||||
label: '邮箱服务',
|
||||
},
|
||||
'service-proxy': {
|
||||
id: 'service-proxy',
|
||||
label: 'IP 代理',
|
||||
sectionIds: ['ip-proxy-section'],
|
||||
},
|
||||
'openai-target-cpa': {
|
||||
id: 'openai-target-cpa',
|
||||
label: 'CPA 来源',
|
||||
rowIds: ['row-vps-url', 'row-vps-password', 'row-local-cpa-step9-mode'],
|
||||
},
|
||||
'openai-target-sub2api': {
|
||||
id: 'openai-target-sub2api',
|
||||
label: 'SUB2API 来源',
|
||||
rowIds: [
|
||||
'row-sub2api-url',
|
||||
'row-sub2api-email',
|
||||
'row-sub2api-password',
|
||||
'row-sub2api-group',
|
||||
'row-sub2api-account-priority',
|
||||
'row-sub2api-default-proxy',
|
||||
],
|
||||
},
|
||||
'openai-target-codex2api': {
|
||||
id: 'openai-target-codex2api',
|
||||
label: 'Codex2API 来源',
|
||||
rowIds: ['row-codex2api-url', 'row-codex2api-admin-key'],
|
||||
},
|
||||
'openai-plus': {
|
||||
id: 'openai-plus',
|
||||
label: 'Plus',
|
||||
rowIds: ['row-plus-mode', 'row-plus-account-access-strategy', 'row-plus-payment-method'],
|
||||
},
|
||||
'openai-phone': {
|
||||
id: 'openai-phone',
|
||||
label: '接码设置',
|
||||
sectionIds: ['phone-verification-section'],
|
||||
rowIds: [],
|
||||
},
|
||||
'openai-oauth': {
|
||||
id: 'openai-oauth',
|
||||
label: 'OAuth',
|
||||
rowIds: ['row-oauth-flow-timeout', 'row-oauth-display'],
|
||||
},
|
||||
'openai-step6': {
|
||||
id: 'openai-step6',
|
||||
label: '第六步',
|
||||
rowIds: ['row-step6-cookie-settings'],
|
||||
},
|
||||
'kiro-target-kiro-rs': {
|
||||
id: 'kiro-target-kiro-rs',
|
||||
label: 'kiro.rs 配置',
|
||||
rowIds: ['row-kiro-rs-url', 'row-kiro-rs-key', 'row-kiro-rs-test-status'],
|
||||
},
|
||||
'kiro-runtime-status': {
|
||||
id: 'kiro-runtime-status',
|
||||
label: 'Kiro 运行态',
|
||||
rowIds: ['row-kiro-web-status', 'row-kiro-login-url', 'row-kiro-upload-status'],
|
||||
},
|
||||
});
|
||||
|
||||
function normalizeFlowId(value = '', fallback = DEFAULT_FLOW_ID) {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized && Object.prototype.hasOwnProperty.call(FLOW_DEFINITIONS, normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
const fallbackValue = String(fallback || '').trim().toLowerCase();
|
||||
return Object.prototype.hasOwnProperty.call(FLOW_DEFINITIONS, fallbackValue)
|
||||
? fallbackValue
|
||||
: DEFAULT_FLOW_ID;
|
||||
}
|
||||
|
||||
function getRegisteredFlowIds() {
|
||||
return Object.keys(FLOW_DEFINITIONS);
|
||||
}
|
||||
|
||||
function getFlowDefinition(flowId) {
|
||||
return FLOW_DEFINITIONS[normalizeFlowId(flowId)] || FLOW_DEFINITIONS[DEFAULT_FLOW_ID];
|
||||
}
|
||||
|
||||
function getFlowLabel(flowId) {
|
||||
return getFlowDefinition(flowId)?.label || normalizeFlowId(flowId);
|
||||
}
|
||||
|
||||
function getDefaultTargetId(flowId) {
|
||||
return normalizeFlowId(flowId) === 'kiro'
|
||||
? DEFAULT_KIRO_TARGET_ID
|
||||
: DEFAULT_OPENAI_TARGET_ID;
|
||||
}
|
||||
|
||||
function normalizeOpenAiTargetId(value = '', fallback = DEFAULT_OPENAI_TARGET_ID) {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (OPENAI_TARGET_IDS.includes(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
const fallbackValue = String(fallback || '').trim().toLowerCase();
|
||||
return OPENAI_TARGET_IDS.includes(fallbackValue)
|
||||
? fallbackValue
|
||||
: DEFAULT_OPENAI_TARGET_ID;
|
||||
}
|
||||
|
||||
function normalizeKiroTargetId(value = '', fallback = DEFAULT_KIRO_TARGET_ID) {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === DEFAULT_KIRO_TARGET_ID) {
|
||||
return normalized;
|
||||
}
|
||||
const fallbackValue = String(fallback || '').trim().toLowerCase();
|
||||
return fallbackValue === DEFAULT_KIRO_TARGET_ID
|
||||
? fallbackValue
|
||||
: DEFAULT_KIRO_TARGET_ID;
|
||||
}
|
||||
|
||||
function normalizeTargetId(flowId, targetId = '', fallback = undefined) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
if (normalizedFlowId === 'kiro') {
|
||||
return normalizeKiroTargetId(
|
||||
targetId,
|
||||
fallback || DEFAULT_KIRO_TARGET_ID
|
||||
);
|
||||
}
|
||||
return normalizeOpenAiTargetId(
|
||||
targetId,
|
||||
fallback || DEFAULT_OPENAI_TARGET_ID
|
||||
);
|
||||
}
|
||||
|
||||
function getTargetDefinitions(flowId) {
|
||||
return getFlowDefinition(flowId)?.targets || {};
|
||||
}
|
||||
|
||||
function getTargetDefinition(flowId, targetId) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const normalizedTargetId = normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
targetId,
|
||||
getDefaultTargetId(normalizedFlowId)
|
||||
);
|
||||
return getTargetDefinitions(normalizedFlowId)[normalizedTargetId] || null;
|
||||
}
|
||||
|
||||
function getTargetOptions(flowId) {
|
||||
return Object.values(getTargetDefinitions(flowId));
|
||||
}
|
||||
|
||||
function getTargetLabel(flowId, targetId) {
|
||||
return getTargetDefinition(flowId, targetId)?.label
|
||||
|| normalizeTargetId(flowId, targetId);
|
||||
}
|
||||
|
||||
function getPublicationTargetDefinitions(flowId) {
|
||||
return getFlowDefinition(flowId)?.publicationTargets || {};
|
||||
}
|
||||
|
||||
function getPublicationTargetDefinition(flowId, publicationTargetId) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const normalizedPublicationTargetId = String(
|
||||
publicationTargetId || (
|
||||
normalizedFlowId === 'kiro'
|
||||
? DEFAULT_KIRO_PUBLICATION_TARGET_ID
|
||||
: ''
|
||||
)
|
||||
).trim().toLowerCase();
|
||||
return getPublicationTargetDefinitions(normalizedFlowId)[normalizedPublicationTargetId] || null;
|
||||
}
|
||||
|
||||
function getFlowCapabilities(flowId) {
|
||||
return {
|
||||
...DEFAULT_FLOW_CAPABILITIES,
|
||||
...(getFlowDefinition(flowId)?.capabilities || {}),
|
||||
};
|
||||
}
|
||||
|
||||
function getVisibleGroupIds(flowId, targetId, options = {}) {
|
||||
const normalizedFlowId = normalizeFlowId(flowId);
|
||||
const flowDefinition = getFlowDefinition(normalizedFlowId);
|
||||
const normalizedTargetId = normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
targetId,
|
||||
getDefaultTargetId(normalizedFlowId)
|
||||
);
|
||||
const targetDefinition = getTargetDefinition(
|
||||
normalizedFlowId,
|
||||
normalizedTargetId
|
||||
);
|
||||
const includeSharedServices = options?.includeSharedServices !== false;
|
||||
const serviceGroups = includeSharedServices
|
||||
? (Array.isArray(flowDefinition?.services)
|
||||
? flowDefinition.services.map((serviceId) => `service-${serviceId}`)
|
||||
: [])
|
||||
: [];
|
||||
return Array.from(new Set([
|
||||
...(Array.isArray(flowDefinition?.baseGroups) ? flowDefinition.baseGroups : []),
|
||||
...(Array.isArray(targetDefinition?.groups) ? targetDefinition.groups : []),
|
||||
...serviceGroups,
|
||||
]));
|
||||
}
|
||||
|
||||
function getSettingsGroupDefinition(groupId) {
|
||||
const normalizedGroupId = String(groupId || '').trim();
|
||||
return SETTINGS_GROUP_DEFINITIONS[normalizedGroupId] || null;
|
||||
}
|
||||
|
||||
function getSettingsGroupDefinitions() {
|
||||
return SETTINGS_GROUP_DEFINITIONS;
|
||||
}
|
||||
|
||||
function getRuntimeSourceDefinitions() {
|
||||
const next = {};
|
||||
Object.values(FLOW_DEFINITIONS).forEach((flowDefinition) => {
|
||||
Object.assign(next, flowDefinition.runtimeSources || {});
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
function getDriverDefinitions() {
|
||||
const next = {};
|
||||
Object.values(FLOW_DEFINITIONS).forEach((flowDefinition) => {
|
||||
Object.assign(next, flowDefinition.driverDefinitions || {});
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
return {
|
||||
DEFAULT_FLOW_CAPABILITIES,
|
||||
DEFAULT_FLOW_ID,
|
||||
DEFAULT_KIRO_TARGET_ID,
|
||||
DEFAULT_KIRO_PUBLICATION_TARGET_ID,
|
||||
DEFAULT_KIRO_RS_URL,
|
||||
DEFAULT_OPENAI_TARGET_ID,
|
||||
FLOW_DEFINITIONS,
|
||||
OPENAI_TARGET_IDS,
|
||||
SETTINGS_GROUP_DEFINITIONS,
|
||||
SHARED_SERVICE_IDS,
|
||||
getDriverDefinitions,
|
||||
getDefaultTargetId,
|
||||
getFlowCapabilities,
|
||||
getFlowDefinition,
|
||||
getFlowLabel,
|
||||
getPublicationTargetDefinition,
|
||||
getPublicationTargetDefinitions,
|
||||
getRegisteredFlowIds,
|
||||
getRuntimeSourceDefinitions,
|
||||
getSettingsGroupDefinition,
|
||||
getSettingsGroupDefinitions,
|
||||
getTargetDefinition,
|
||||
getTargetDefinitions,
|
||||
getTargetLabel,
|
||||
getTargetOptions,
|
||||
getVisibleGroupIds,
|
||||
normalizeFlowId,
|
||||
normalizeKiroTargetId,
|
||||
normalizeOpenAiTargetId,
|
||||
normalizeTargetId,
|
||||
};
|
||||
});
|
||||
@@ -1,406 +0,0 @@
|
||||
(function attachMultiPageSourceRegistry(root, factory) {
|
||||
root.MultiPageSourceRegistry = factory();
|
||||
})(typeof self !== 'undefined' ? self : globalThis, function createSourceRegistryModule() {
|
||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||
const flowRegistryApi = rootScope.MultiPageFlowRegistry || {};
|
||||
|
||||
const SOURCE_ALIASES = Object.freeze({
|
||||
'signup-page': 'openai-auth',
|
||||
});
|
||||
|
||||
const SHARED_SOURCE_DEFINITIONS = Object.freeze({
|
||||
'qq-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'QQ 邮箱',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'qq-mail-family',
|
||||
driverId: 'content/qq-mail',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'mail-163': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: '163 邮箱',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'mail-163-family',
|
||||
driverId: 'content/mail-163',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'gmail-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'Gmail 邮箱',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'gmail-mail-family',
|
||||
driverId: 'content/gmail-mail',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'icloud-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'iCloud 邮箱',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'icloud-mail-family',
|
||||
driverId: 'content/icloud-mail',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'inbucket-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'Inbucket 邮箱',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'inbucket-mail-family',
|
||||
driverId: 'content/inbucket-mail',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'mail-2925': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: '2925 邮箱',
|
||||
readyPolicy: 'top-frame-only',
|
||||
family: 'mail-2925-family',
|
||||
driverId: 'content/mail-2925',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'duck-mail': {
|
||||
flowId: null,
|
||||
kind: 'mail-provider',
|
||||
label: 'Duck 邮箱',
|
||||
readyPolicy: 'allow-child-frame',
|
||||
family: 'duck-mail-family',
|
||||
driverId: 'content/duck-mail',
|
||||
cleanupScopes: [],
|
||||
},
|
||||
'unknown-source': {
|
||||
flowId: null,
|
||||
kind: 'unknown',
|
||||
label: '未知来源',
|
||||
readyPolicy: 'disabled',
|
||||
family: 'unknown-family',
|
||||
driverId: null,
|
||||
cleanupScopes: [],
|
||||
},
|
||||
});
|
||||
|
||||
const SHARED_DRIVER_DEFINITIONS = Object.freeze({
|
||||
'content/qq-mail': {
|
||||
sourceId: 'qq-mail',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/mail-163': {
|
||||
sourceId: 'mail-163',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/gmail-mail': {
|
||||
sourceId: 'gmail-mail',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/icloud-mail': {
|
||||
sourceId: 'icloud-mail',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/mail-2925': {
|
||||
sourceId: 'mail-2925',
|
||||
commands: ['POLL_EMAIL'],
|
||||
},
|
||||
'content/duck-mail': {
|
||||
sourceId: 'duck-mail',
|
||||
commands: ['FETCH_ALIAS_EMAIL'],
|
||||
},
|
||||
});
|
||||
|
||||
const CLEANUP_SCOPE_OWNERS = Object.freeze({
|
||||
'oauth-localhost-callback': 'openai-auth',
|
||||
});
|
||||
|
||||
const AUTH_PAGE_HOSTS = new Set(['auth0.openai.com', 'auth.openai.com', 'accounts.openai.com']);
|
||||
const ENTRY_PAGE_HOSTS = new Set(['chatgpt.com', 'www.chatgpt.com', 'chat.openai.com']);
|
||||
const CHILD_FRAME_BLOCKED_SOURCES = new Set([
|
||||
'qq-mail',
|
||||
'mail-163',
|
||||
'gmail-mail',
|
||||
'mail-2925',
|
||||
'inbucket-mail',
|
||||
'plus-checkout',
|
||||
'kiro-register-page',
|
||||
'kiro-desktop-authorize',
|
||||
]);
|
||||
|
||||
function normalizeHostname(hostname = '') {
|
||||
return String(hostname || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function matchesNamedHostFamily(hostname = '', family = '') {
|
||||
const normalizedHost = normalizeHostname(hostname);
|
||||
const normalizedFamily = normalizeHostname(family);
|
||||
if (!normalizedHost || !normalizedFamily) {
|
||||
return false;
|
||||
}
|
||||
return normalizedHost === normalizedFamily
|
||||
|| normalizedHost.endsWith(`.${normalizedFamily}`)
|
||||
|| normalizedHost.startsWith(`${normalizedFamily}.`)
|
||||
|| normalizedHost.includes(`.${normalizedFamily}.`);
|
||||
}
|
||||
|
||||
function isKiroWebHost(hostname = '') {
|
||||
const normalized = normalizeHostname(hostname);
|
||||
return normalized === 'app.kiro.dev'
|
||||
|| normalized === 'kiro.dev';
|
||||
}
|
||||
|
||||
function isKiroAwsAuthHost(hostname = '') {
|
||||
const normalized = normalizeHostname(hostname);
|
||||
return normalized === 'view.awsapps.com'
|
||||
|| normalized === 'login.awsapps.com'
|
||||
|| matchesNamedHostFamily(normalized, 'signin.aws')
|
||||
|| matchesNamedHostFamily(normalized, 'profile.aws')
|
||||
|| normalized === 'amazonaws.com'
|
||||
|| normalized.endsWith('.amazonaws.com');
|
||||
}
|
||||
|
||||
function isKiroRegisterHost(hostname = '') {
|
||||
return isKiroWebHost(hostname) || isKiroAwsAuthHost(hostname);
|
||||
}
|
||||
|
||||
function getRuntimeSourceDefinitions() {
|
||||
return {
|
||||
...(typeof flowRegistryApi.getRuntimeSourceDefinitions === 'function'
|
||||
? flowRegistryApi.getRuntimeSourceDefinitions()
|
||||
: {}),
|
||||
...SHARED_SOURCE_DEFINITIONS,
|
||||
};
|
||||
}
|
||||
|
||||
function getDriverDefinitions() {
|
||||
return {
|
||||
...(typeof flowRegistryApi.getDriverDefinitions === 'function'
|
||||
? flowRegistryApi.getDriverDefinitions()
|
||||
: {}),
|
||||
...SHARED_DRIVER_DEFINITIONS,
|
||||
};
|
||||
}
|
||||
|
||||
function createSourceRegistry() {
|
||||
const SOURCE_DEFINITIONS = getRuntimeSourceDefinitions();
|
||||
const DRIVER_DEFINITIONS = getDriverDefinitions();
|
||||
|
||||
function parseUrlSafely(rawUrl) {
|
||||
if (!rawUrl) return null;
|
||||
try {
|
||||
return new URL(rawUrl);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeSourceId(source) {
|
||||
return String(source || '').trim();
|
||||
}
|
||||
|
||||
function resolveCanonicalSource(source) {
|
||||
const normalized = normalizeSourceId(source);
|
||||
if (!normalized) return '';
|
||||
return SOURCE_ALIASES[normalized] || normalized;
|
||||
}
|
||||
|
||||
function getAliasKeysForCanonicalSource(source) {
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
return Object.keys(SOURCE_ALIASES).filter((alias) => SOURCE_ALIASES[alias] === canonical);
|
||||
}
|
||||
|
||||
function getSourceKeys(source) {
|
||||
const normalized = normalizeSourceId(source);
|
||||
const canonical = resolveCanonicalSource(normalized);
|
||||
return Array.from(new Set([
|
||||
canonical,
|
||||
...getAliasKeysForCanonicalSource(canonical),
|
||||
normalized,
|
||||
].filter(Boolean)));
|
||||
}
|
||||
|
||||
function getSourceMeta(source) {
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
const definition = SOURCE_DEFINITIONS[canonical];
|
||||
if (!definition) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: canonical,
|
||||
aliases: getAliasKeysForCanonicalSource(canonical),
|
||||
...definition,
|
||||
};
|
||||
}
|
||||
|
||||
function getSourceLabel(source) {
|
||||
return getSourceMeta(source)?.label || normalizeSourceId(source) || '未知来源';
|
||||
}
|
||||
|
||||
function getDriverIdForSource(source) {
|
||||
return getSourceMeta(source)?.driverId || null;
|
||||
}
|
||||
|
||||
function getDriverMeta(sourceOrDriverId) {
|
||||
const directDriverId = normalizeSourceId(sourceOrDriverId);
|
||||
const driverId = Object.prototype.hasOwnProperty.call(DRIVER_DEFINITIONS, directDriverId)
|
||||
? directDriverId
|
||||
: getDriverIdForSource(sourceOrDriverId);
|
||||
if (!driverId || !Object.prototype.hasOwnProperty.call(DRIVER_DEFINITIONS, driverId)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
id: driverId,
|
||||
...DRIVER_DEFINITIONS[driverId],
|
||||
};
|
||||
}
|
||||
|
||||
function driverAcceptsCommand(sourceOrDriverId, command) {
|
||||
const normalizedCommand = normalizeSourceId(command);
|
||||
if (!normalizedCommand) {
|
||||
return false;
|
||||
}
|
||||
const driver = getDriverMeta(sourceOrDriverId);
|
||||
return Array.isArray(driver?.commands) && driver.commands.includes(normalizedCommand);
|
||||
}
|
||||
|
||||
function isSignupPageHost(hostname = '') {
|
||||
return AUTH_PAGE_HOSTS.has(normalizeHostname(hostname));
|
||||
}
|
||||
|
||||
function isSignupEntryHost(hostname = '') {
|
||||
return ENTRY_PAGE_HOSTS.has(normalizeHostname(hostname));
|
||||
}
|
||||
|
||||
function is163MailHost(hostname = '') {
|
||||
const normalized = normalizeHostname(hostname);
|
||||
return normalized === 'mail.163.com'
|
||||
|| normalized.endsWith('.mail.163.com')
|
||||
|| normalized === 'mail.126.com'
|
||||
|| normalized.endsWith('.mail.126.com')
|
||||
|| normalized === 'webmail.vip.163.com';
|
||||
}
|
||||
|
||||
function matchesSourceUrlFamily(source, candidateUrl, referenceUrl) {
|
||||
const candidate = parseUrlSafely(candidateUrl);
|
||||
if (!candidate) return false;
|
||||
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
const reference = parseUrlSafely(referenceUrl);
|
||||
|
||||
switch (canonical) {
|
||||
case 'openai-auth':
|
||||
return isSignupPageHost(candidate.hostname) || isSignupEntryHost(candidate.hostname);
|
||||
case 'chatgpt':
|
||||
return isSignupEntryHost(candidate.hostname);
|
||||
case 'duck-mail':
|
||||
return candidate.hostname === 'duckduckgo.com' && candidate.pathname.startsWith('/email/');
|
||||
case 'qq-mail':
|
||||
return candidate.hostname === 'mail.qq.com' || candidate.hostname === 'wx.mail.qq.com';
|
||||
case 'mail-163':
|
||||
return is163MailHost(candidate.hostname);
|
||||
case 'gmail-mail':
|
||||
return candidate.hostname === 'mail.google.com';
|
||||
case 'icloud-mail':
|
||||
return candidate.hostname === 'www.icloud.com'
|
||||
|| candidate.hostname === 'www.icloud.com.cn';
|
||||
case 'inbucket-mail':
|
||||
return Boolean(reference)
|
||||
&& candidate.origin === reference.origin
|
||||
&& candidate.pathname.startsWith('/m/');
|
||||
case 'mail-2925':
|
||||
return candidate.hostname === '2925.com' || candidate.hostname === 'www.2925.com';
|
||||
case 'vps-panel':
|
||||
return Boolean(reference)
|
||||
&& candidate.origin === reference.origin
|
||||
&& candidate.pathname === reference.pathname;
|
||||
case 'sub2api-panel':
|
||||
return Boolean(reference)
|
||||
&& candidate.origin === reference.origin
|
||||
&& (
|
||||
candidate.pathname.startsWith('/admin/accounts')
|
||||
|| candidate.pathname.startsWith('/login')
|
||||
|| candidate.pathname === '/'
|
||||
);
|
||||
case 'codex2api-panel':
|
||||
return Boolean(reference)
|
||||
&& candidate.origin === reference.origin
|
||||
&& (
|
||||
candidate.pathname.startsWith('/admin/accounts')
|
||||
|| candidate.pathname === '/admin'
|
||||
|| candidate.pathname === '/'
|
||||
);
|
||||
case 'plus-checkout':
|
||||
return candidate.hostname === 'chatgpt.com'
|
||||
&& candidate.pathname.startsWith('/checkout/');
|
||||
case 'paypal-flow':
|
||||
return candidate.hostname.endsWith('paypal.com');
|
||||
case 'gopay-flow':
|
||||
return /gopay|gojek/i.test(candidate.hostname);
|
||||
case 'kiro-register-page':
|
||||
return isKiroRegisterHost(candidate.hostname);
|
||||
case 'kiro-desktop-authorize':
|
||||
return isKiroAwsAuthHost(candidate.hostname);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function detectSourceFromLocation({
|
||||
injectedSource,
|
||||
url = '',
|
||||
hostname = '',
|
||||
} = {}) {
|
||||
if (injectedSource) return resolveCanonicalSource(injectedSource);
|
||||
|
||||
const normalizedHostname = String(hostname || '').toLowerCase();
|
||||
const normalizedUrl = String(url || '');
|
||||
|
||||
if (isSignupPageHost(normalizedHostname)) return 'openai-auth';
|
||||
if (normalizedHostname === 'mail.qq.com' || normalizedHostname === 'wx.mail.qq.com') return 'qq-mail';
|
||||
if (is163MailHost(normalizedHostname)) return 'mail-163';
|
||||
if (normalizedHostname === 'mail.google.com') return 'gmail-mail';
|
||||
if (normalizedHostname === 'www.icloud.com' || normalizedHostname === 'www.icloud.com.cn') return 'icloud-mail';
|
||||
if (normalizedUrl.includes('duckduckgo.com/email/settings/autofill')) return 'duck-mail';
|
||||
if (normalizedUrl.includes('2925.com')) return 'mail-2925';
|
||||
if (isKiroRegisterHost(normalizedHostname)) return 'kiro-register-page';
|
||||
if (isSignupEntryHost(normalizedHostname)) return 'chatgpt';
|
||||
return 'unknown-source';
|
||||
}
|
||||
|
||||
function shouldReportReadyForFrame(source, isChildFrame) {
|
||||
const canonical = resolveCanonicalSource(source);
|
||||
const readyPolicy = getSourceMeta(canonical)?.readyPolicy || 'allow-child-frame';
|
||||
if (readyPolicy === 'disabled') return false;
|
||||
if (!isChildFrame) return true;
|
||||
if (readyPolicy === 'top-frame-only') return false;
|
||||
if (CHILD_FRAME_BLOCKED_SOURCES.has(canonical)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function getCleanupOwnerSource(cleanupScope) {
|
||||
return resolveCanonicalSource(CLEANUP_SCOPE_OWNERS[String(cleanupScope || '').trim()] || '');
|
||||
}
|
||||
|
||||
return {
|
||||
detectSourceFromLocation,
|
||||
driverAcceptsCommand,
|
||||
getCleanupOwnerSource,
|
||||
getDriverIdForSource,
|
||||
getDriverMeta,
|
||||
getSourceKeys,
|
||||
getSourceLabel,
|
||||
getSourceMeta,
|
||||
is163MailHost,
|
||||
isSignupEntryHost,
|
||||
isSignupPageHost,
|
||||
matchesSourceUrlFamily,
|
||||
parseUrlSafely,
|
||||
resolveCanonicalSource,
|
||||
shouldReportReadyForFrame,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createSourceRegistry,
|
||||
};
|
||||
});
|
||||
@@ -77,7 +77,7 @@
|
||||
}
|
||||
|
||||
function getContributionSource(currentState = getLatestState()) {
|
||||
return normalizeContributionSource(currentState.contributionSource || currentState.panelMode);
|
||||
return normalizeContributionSource(currentState.contributionSource || getActiveTargetId(currentState));
|
||||
}
|
||||
|
||||
function getContributionSourceLabel(currentState = getLatestState()) {
|
||||
@@ -107,10 +107,8 @@
|
||||
if (selectedTargetId) {
|
||||
return selectedTargetId;
|
||||
}
|
||||
if (activeFlowId === 'kiro') {
|
||||
return normalizeString(currentState.kiroTargetId || currentState.targetId || 'kiro-rs').toLowerCase() || 'kiro-rs';
|
||||
}
|
||||
return normalizeString(currentState.openaiIntegrationTargetId || currentState.panelMode || currentState.targetId || 'cpa').toLowerCase() || 'cpa';
|
||||
return normalizeString(currentState.targetId).toLowerCase()
|
||||
|| (activeFlowId === 'kiro' ? 'kiro-rs' : 'cpa');
|
||||
}
|
||||
|
||||
function applySelectedFlowToState(nextState = {}, flowId = 'openai', targetId = '') {
|
||||
@@ -122,14 +120,14 @@
|
||||
...baseState,
|
||||
activeFlowId: selectedFlowId,
|
||||
flowId: selectedFlowId,
|
||||
panelMode: selectedTargetId || normalizeString(baseState.panelMode).toLowerCase() || 'cpa',
|
||||
targetId: selectedTargetId || normalizeString(baseState.targetId).toLowerCase() || 'cpa',
|
||||
};
|
||||
}
|
||||
return {
|
||||
...baseState,
|
||||
activeFlowId: selectedFlowId,
|
||||
flowId: selectedFlowId,
|
||||
kiroTargetId: selectedTargetId || normalizeString(baseState.kiroTargetId || baseState.targetId).toLowerCase() || 'kiro-rs',
|
||||
targetId: selectedTargetId || normalizeString(baseState.targetId).toLowerCase() || 'kiro-rs',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -164,7 +162,7 @@
|
||||
if (registry?.resolveSidepanelCapabilities) {
|
||||
return Boolean(registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: getActiveFlowId(currentState),
|
||||
panelMode: currentState?.panelMode,
|
||||
targetId: getActiveTargetId(currentState),
|
||||
state: currentState,
|
||||
})?.canShowContributionMode);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
|
||||
<head>
|
||||
@@ -1876,10 +1876,15 @@
|
||||
<script src="../hotmail-utils.js"></script>
|
||||
<script src="../luckmail-utils.js"></script>
|
||||
<script src="../yyds-mail-utils.js"></script>
|
||||
<script src="../shared/flow-registry.js"></script>
|
||||
<script src="../flows/openai/index.js"></script>
|
||||
<script src="../flows/openai/workflow.js"></script>
|
||||
<script src="../flows/kiro/index.js"></script>
|
||||
<script src="../flows/kiro/workflow.js"></script>
|
||||
<script src="../flows/index.js"></script>
|
||||
<script src="../core/flow-kernel/flow-registry.js"></script>
|
||||
<script src="../shared/contribution-registry.js"></script>
|
||||
<script src="../shared/settings-schema.js"></script>
|
||||
<script src="../shared/flow-capabilities.js"></script>
|
||||
<script src="../core/flow-kernel/settings-schema.js"></script>
|
||||
<script src="../core/flow-kernel/flow-capabilities.js"></script>
|
||||
<script src="../data/step-definitions.js"></script>
|
||||
<script src="update-service.js"></script>
|
||||
<script src="contribution-content-update-service.js"></script>
|
||||
|
||||
+432
-149
@@ -2002,13 +2002,44 @@ async function openConfirmModalWithOption({
|
||||
async function openPlusManualConfirmationDialog(options = {}) {
|
||||
const method = String(options.method || '').trim().toLowerCase();
|
||||
const activeFlowId = String(latestState?.activeFlowId || latestState?.flowId || 'openai').trim().toLowerCase();
|
||||
const panelMode = String(latestState?.panelMode || latestState?.openaiIntegrationTargetId || '').trim().toLowerCase();
|
||||
const normalizeTargetIdForFlowSafe = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow
|
||||
: ((flowId, targetId = '', fallback = '') => {
|
||||
const normalizedFlowId = String(flowId || '').trim().toLowerCase() || 'openai';
|
||||
if (normalizedFlowId === 'openai') {
|
||||
const normalizedTargetId = String(targetId || fallback || '').trim().toLowerCase();
|
||||
return normalizedTargetId === 'sub2api' || normalizedTargetId === 'codex2api' ? normalizedTargetId : 'cpa';
|
||||
}
|
||||
const normalizedTargetId = String(targetId || '').trim().toLowerCase();
|
||||
return normalizedTargetId || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||
});
|
||||
const getDefaultTargetIdForFlowSafe = typeof getDefaultTargetIdForFlow === 'function'
|
||||
? getDefaultTargetIdForFlow
|
||||
: ((flowId = 'openai') => (String(flowId || '').trim().toLowerCase() === 'openai' ? 'cpa' : 'kiro-rs'));
|
||||
const normalizePlusStrategyTargetIdSafe = typeof normalizePlusStrategyTargetId === 'function'
|
||||
? normalizePlusStrategyTargetId
|
||||
: ((value = '') => {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === 'sub2api' || normalized === 'codex2api') {
|
||||
return normalized;
|
||||
}
|
||||
return 'cpa';
|
||||
});
|
||||
const targetId = normalizePlusStrategyTargetIdSafe(
|
||||
typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(latestState, activeFlowId)
|
||||
: normalizeTargetIdForFlowSafe(
|
||||
activeFlowId,
|
||||
latestState?.targetId || '',
|
||||
getDefaultTargetIdForFlowSafe(activeFlowId)
|
||||
)
|
||||
);
|
||||
const signupMethod = String(latestState?.resolvedSignupMethod || latestState?.signupMethod || 'email').trim().toLowerCase();
|
||||
const plusModeEnabled = latestState?.plusModeEnabled === undefined ? true : Boolean(latestState.plusModeEnabled);
|
||||
const plusAccountAccessStrategy = String(latestState?.plusAccountAccessStrategy || 'oauth').trim().toLowerCase();
|
||||
const useSub2ApiSessionImport = plusModeEnabled
|
||||
&& activeFlowId === 'openai'
|
||||
&& panelMode === 'sub2api'
|
||||
&& targetId === 'sub2api'
|
||||
&& signupMethod === 'email'
|
||||
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||
const continuationActionLabel = useSub2ApiSessionImport
|
||||
@@ -2042,13 +2073,44 @@ async function syncPlusManualConfirmationDialog() {
|
||||
const step = Number(latestState?.plusManualConfirmationStep) || 0;
|
||||
const method = String(latestState?.plusManualConfirmationMethod || '').trim().toLowerCase();
|
||||
const activeFlowId = String(latestState?.activeFlowId || latestState?.flowId || 'openai').trim().toLowerCase();
|
||||
const panelMode = String(latestState?.panelMode || latestState?.openaiIntegrationTargetId || '').trim().toLowerCase();
|
||||
const normalizeTargetIdForFlowSafe = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow
|
||||
: ((flowId, targetId = '', fallback = '') => {
|
||||
const normalizedFlowId = String(flowId || '').trim().toLowerCase() || 'openai';
|
||||
if (normalizedFlowId === 'openai') {
|
||||
const normalizedTargetId = String(targetId || fallback || '').trim().toLowerCase();
|
||||
return normalizedTargetId === 'sub2api' || normalizedTargetId === 'codex2api' ? normalizedTargetId : 'cpa';
|
||||
}
|
||||
const normalizedTargetId = String(targetId || '').trim().toLowerCase();
|
||||
return normalizedTargetId || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||
});
|
||||
const getDefaultTargetIdForFlowSafe = typeof getDefaultTargetIdForFlow === 'function'
|
||||
? getDefaultTargetIdForFlow
|
||||
: ((flowId = 'openai') => (String(flowId || '').trim().toLowerCase() === 'openai' ? 'cpa' : 'kiro-rs'));
|
||||
const normalizePlusStrategyTargetIdSafe = typeof normalizePlusStrategyTargetId === 'function'
|
||||
? normalizePlusStrategyTargetId
|
||||
: ((value = '') => {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === 'sub2api' || normalized === 'codex2api') {
|
||||
return normalized;
|
||||
}
|
||||
return 'cpa';
|
||||
});
|
||||
const targetId = normalizePlusStrategyTargetIdSafe(
|
||||
typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(latestState, activeFlowId)
|
||||
: normalizeTargetIdForFlowSafe(
|
||||
activeFlowId,
|
||||
latestState?.targetId || '',
|
||||
getDefaultTargetIdForFlowSafe(activeFlowId)
|
||||
)
|
||||
);
|
||||
const signupMethod = String(latestState?.resolvedSignupMethod || latestState?.signupMethod || 'email').trim().toLowerCase();
|
||||
const plusModeEnabled = latestState?.plusModeEnabled === undefined ? true : Boolean(latestState.plusModeEnabled);
|
||||
const plusAccountAccessStrategy = String(latestState?.plusAccountAccessStrategy || 'oauth').trim().toLowerCase();
|
||||
const useSub2ApiSessionImport = plusModeEnabled
|
||||
&& activeFlowId === 'openai'
|
||||
&& panelMode === 'sub2api'
|
||||
&& targetId === 'sub2api'
|
||||
&& signupMethod === 'email'
|
||||
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||
const continuationActionLabel = useSub2ApiSessionImport
|
||||
@@ -2159,10 +2221,10 @@ function getContributionContentFlowId(state = latestState) {
|
||||
|
||||
function getContributionContentTargetId(state = latestState) {
|
||||
const flowId = getContributionContentFlowId(state);
|
||||
if (flowId === 'kiro') {
|
||||
return String(state?.kiroTargetId || state?.targetId || 'kiro-rs').trim().toLowerCase() || 'kiro-rs';
|
||||
if (typeof getSelectedTargetIdForState === 'function') {
|
||||
return getSelectedTargetIdForState(state, flowId);
|
||||
}
|
||||
return String(state?.openaiIntegrationTargetId || state?.panelMode || state?.targetId || 'cpa').trim().toLowerCase() || 'cpa';
|
||||
return normalizeTargetIdForFlow(flowId, state?.targetId || '', getDefaultTargetIdForFlow(flowId));
|
||||
}
|
||||
|
||||
function openNewUserGuidePrompt() {
|
||||
@@ -2255,29 +2317,54 @@ function shouldWarnAutoRunFallbackRisk(totalRuns, autoRunSkipFailures) {
|
||||
return totalRuns >= AUTO_RUN_FALLBACK_RISK_WARNING_MIN_RUNS;
|
||||
}
|
||||
|
||||
function shouldWarnCpaPhoneSignup(signupMethod = null, panelMode = null) {
|
||||
function shouldWarnCpaPhoneSignup(signupMethod = null, targetId = null) {
|
||||
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID === 'string' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
||||
const resolvedSignupMethod = normalizeSignupMethod(
|
||||
signupMethod ?? (
|
||||
typeof getSelectedSignupMethod === 'function'
|
||||
? getSelectedSignupMethod()
|
||||
: DEFAULT_SIGNUP_METHOD
|
||||
)
|
||||
)
|
||||
);
|
||||
const resolvedPanelMode = normalizePanelMode(
|
||||
panelMode ?? (
|
||||
typeof getSelectedPanelMode === 'function'
|
||||
? getSelectedPanelMode()
|
||||
: 'cpa'
|
||||
)
|
||||
const activeFlowId = typeof getSelectedFlowId === 'function'
|
||||
? getSelectedFlowId(latestState)
|
||||
: (
|
||||
typeof normalizeFlowId === 'function'
|
||||
? normalizeFlowId(latestState?.activeFlowId || latestState?.flowId || defaultFlowId)
|
||||
: (String(latestState?.activeFlowId || latestState?.flowId || defaultFlowId).trim().toLowerCase() || defaultFlowId)
|
||||
);
|
||||
const normalizeTargetIdForFlowSafe = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow
|
||||
: ((flowId, value = '', fallback = '') => {
|
||||
const normalizedFlowId = String(flowId || '').trim().toLowerCase() || defaultFlowId;
|
||||
if (normalizedFlowId === defaultFlowId) {
|
||||
return normalizePanelMode(value || fallback);
|
||||
}
|
||||
const normalizedValue = String(value || '').trim().toLowerCase();
|
||||
return normalizedValue || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||
});
|
||||
const resolvedTargetId = normalizeTargetIdForFlowSafe(
|
||||
activeFlowId,
|
||||
targetId ?? (
|
||||
typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(activeFlowId)
|
||||
: getSelectedTargetIdForState(latestState, activeFlowId)
|
||||
),
|
||||
typeof getDefaultTargetIdForFlow === 'function'
|
||||
? getDefaultTargetIdForFlow(activeFlowId)
|
||||
: (activeFlowId === defaultFlowId ? 'cpa' : 'kiro-rs')
|
||||
);
|
||||
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
panelMode: resolvedPanelMode,
|
||||
activeFlowId,
|
||||
targetId: resolvedTargetId,
|
||||
signupMethod: resolvedSignupMethod,
|
||||
state: {
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
panelMode: resolvedPanelMode,
|
||||
activeFlowId,
|
||||
flowId: activeFlowId,
|
||||
targetId: resolvedTargetId,
|
||||
signupMethod: resolvedSignupMethod,
|
||||
},
|
||||
})
|
||||
@@ -2288,12 +2375,14 @@ function shouldWarnCpaPhoneSignup(signupMethod = null, panelMode = null) {
|
||||
}) || null;
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: typeof latestState !== 'undefined' ? latestState?.activeFlowId : '',
|
||||
panelMode: resolvedPanelMode,
|
||||
activeFlowId,
|
||||
targetId: resolvedTargetId,
|
||||
signupMethod: resolvedSignupMethod,
|
||||
state: {
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
panelMode: resolvedPanelMode,
|
||||
activeFlowId,
|
||||
flowId: activeFlowId,
|
||||
targetId: resolvedTargetId,
|
||||
signupMethod: resolvedSignupMethod,
|
||||
},
|
||||
})
|
||||
@@ -2305,7 +2394,7 @@ function shouldWarnCpaPhoneSignup(signupMethod = null, panelMode = null) {
|
||||
}
|
||||
|
||||
return resolvedSignupMethod === SIGNUP_METHOD_PHONE
|
||||
&& resolvedPanelMode === 'cpa'
|
||||
&& resolvedTargetId === 'cpa'
|
||||
&& !isCpaPhoneSignupPromptDismissed();
|
||||
}
|
||||
|
||||
@@ -2327,11 +2416,11 @@ async function confirmCpaPhoneSignupIfNeeded(options = {}) {
|
||||
const signupMethod = Object.prototype.hasOwnProperty.call(options, 'signupMethod')
|
||||
? options.signupMethod
|
||||
: null;
|
||||
const panelMode = Object.prototype.hasOwnProperty.call(options, 'panelMode')
|
||||
? options.panelMode
|
||||
const targetId = Object.prototype.hasOwnProperty.call(options, 'targetId')
|
||||
? options.targetId
|
||||
: null;
|
||||
|
||||
if (!shouldWarnCpaPhoneSignup(signupMethod, panelMode)) {
|
||||
if (!shouldWarnCpaPhoneSignup(signupMethod, targetId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2559,6 +2648,18 @@ function getKiroUploadStatusLabel(value = '') {
|
||||
}
|
||||
}
|
||||
|
||||
function getKiroRuntimeState(state = {}) {
|
||||
const runtimeState = state?.runtimeState?.flowState?.kiro;
|
||||
if (runtimeState && typeof runtimeState === 'object' && !Array.isArray(runtimeState)) {
|
||||
return runtimeState;
|
||||
}
|
||||
const flowState = state?.flowState?.kiro;
|
||||
if (flowState && typeof flowState === 'object' && !Array.isArray(flowState)) {
|
||||
return flowState;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
function setKiroRsConnectionTestStatus(message = '') {
|
||||
const nextText = String(message || '').trim() || '未测试';
|
||||
kiroRsConnectionTestStatusText = nextText;
|
||||
@@ -2873,6 +2974,18 @@ function syncLatestState(nextState) {
|
||||
nodeStatuses: mergedNodeStatuses,
|
||||
};
|
||||
|
||||
const activeFlowId = typeof normalizeFlowId === 'function'
|
||||
? normalizeFlowId(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID, DEFAULT_ACTIVE_FLOW_ID)
|
||||
: (String(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID);
|
||||
const schema = typeof getSettingsSchema === 'function' ? getSettingsSchema() : null;
|
||||
const selectedTargetId = schema?.getSelectedTargetId
|
||||
? schema.getSelectedTargetId(latestState, activeFlowId)
|
||||
: (String(latestState?.targetId || '').trim().toLowerCase()
|
||||
|| (activeFlowId === 'kiro' ? 'kiro-rs' : 'cpa'));
|
||||
latestState.targetId = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow(activeFlowId, selectedTargetId)
|
||||
: selectedTargetId;
|
||||
|
||||
renderAccountRecords(latestState);
|
||||
}
|
||||
|
||||
@@ -3053,7 +3166,12 @@ function getRequestedPlusAccountAccessStrategy(state = latestState) {
|
||||
if (typeof selectPanelMode !== 'undefined' && selectPanelMode?.value) {
|
||||
return selectPanelMode.value;
|
||||
}
|
||||
return state?.panelMode || state?.openaiIntegrationTargetId || 'cpa';
|
||||
return getSelectedTargetIdForState({
|
||||
...(latestState || {}),
|
||||
...(state || {}),
|
||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
flowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
}, DEFAULT_ACTIVE_FLOW_ID);
|
||||
};
|
||||
const resolveStrategyForTarget = typeof resolvePlusAccountAccessStrategyForTarget === 'function'
|
||||
? resolvePlusAccountAccessStrategyForTarget
|
||||
@@ -3136,7 +3254,38 @@ function resolvePlusManualContinuationActionLabelFromState(state = latestState)
|
||||
const activeFlowId = String(state?.activeFlowId || state?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase();
|
||||
const signupMethod = normalizeSignupMethod(state?.resolvedSignupMethod || state?.signupMethod || DEFAULT_SIGNUP_METHOD);
|
||||
const plusModeEnabled = state?.plusModeEnabled === undefined ? true : Boolean(state?.plusModeEnabled);
|
||||
const targetId = normalizePlusStrategyTargetId(state?.panelMode || state?.openaiIntegrationTargetId || 'cpa');
|
||||
const normalizeTargetIdForFlowSafe = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow
|
||||
: ((flowId, targetId = '', fallback = '') => {
|
||||
const normalizedFlowId = String(flowId || '').trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID;
|
||||
if (normalizedFlowId === DEFAULT_ACTIVE_FLOW_ID) {
|
||||
const normalizedTargetId = String(targetId || fallback || '').trim().toLowerCase();
|
||||
return normalizedTargetId === 'sub2api' || normalizedTargetId === 'codex2api' ? normalizedTargetId : 'cpa';
|
||||
}
|
||||
const normalizedTargetId = String(targetId || '').trim().toLowerCase();
|
||||
return normalizedTargetId || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||
});
|
||||
const getDefaultTargetIdForFlowSafe = typeof getDefaultTargetIdForFlow === 'function'
|
||||
? getDefaultTargetIdForFlow
|
||||
: ((flowId = DEFAULT_ACTIVE_FLOW_ID) => (String(flowId || '').trim().toLowerCase() === DEFAULT_ACTIVE_FLOW_ID ? 'cpa' : 'kiro-rs'));
|
||||
const normalizePlusStrategyTargetIdSafe = typeof normalizePlusStrategyTargetId === 'function'
|
||||
? normalizePlusStrategyTargetId
|
||||
: ((value = '') => {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === 'sub2api' || normalized === 'codex2api') {
|
||||
return normalized;
|
||||
}
|
||||
return 'cpa';
|
||||
});
|
||||
const targetId = normalizePlusStrategyTargetIdSafe(
|
||||
typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(state, activeFlowId)
|
||||
: normalizeTargetIdForFlowSafe(
|
||||
activeFlowId,
|
||||
state?.targetId || '',
|
||||
getDefaultTargetIdForFlowSafe(activeFlowId)
|
||||
)
|
||||
);
|
||||
const strategy = normalizePlusAccountAccessStrategy(state?.plusAccountAccessStrategy || DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY);
|
||||
const effectiveStrategy = plusModeEnabled && activeFlowId === DEFAULT_ACTIVE_FLOW_ID && signupMethod === SIGNUP_METHOD_EMAIL
|
||||
? strategy
|
||||
@@ -4478,12 +4627,63 @@ function collectSettingsPayload() {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
return normalized === 'sub2api' || normalized === 'codex2api' ? normalized : 'cpa';
|
||||
});
|
||||
const rawPanelMode = normalizePanelModeSafe(selectPanelMode?.value || latestState?.panelMode || 'cpa');
|
||||
const normalizeTargetIdForFlowSafe = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow
|
||||
: ((flowId, targetId = '', fallback = '') => {
|
||||
const normalizedFlowId = String(flowId || '').trim().toLowerCase() || defaultFlowId;
|
||||
if (normalizedFlowId === defaultFlowId) {
|
||||
return normalizePanelModeSafe(targetId || fallback);
|
||||
}
|
||||
const normalizedTargetId = String(targetId || '').trim().toLowerCase();
|
||||
return normalizedTargetId || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||
});
|
||||
const resolvePlusAccountAccessStrategyForTargetSafe = typeof resolvePlusAccountAccessStrategyForTarget === 'function'
|
||||
? resolvePlusAccountAccessStrategyForTarget
|
||||
: ((value = '', targetId = '') => {
|
||||
const oauthStrategyValue = typeof PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH !== 'undefined'
|
||||
? PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH
|
||||
: 'oauth';
|
||||
const sub2apiSessionStrategyValue = typeof PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION !== 'undefined'
|
||||
? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||
: 'sub2api_codex_session';
|
||||
const cpaSessionStrategyValue = typeof PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION !== 'undefined'
|
||||
? PLUS_ACCOUNT_ACCESS_STRATEGY_CPA_CODEX_SESSION
|
||||
: 'cpa_codex_session';
|
||||
const sessionUiValue = typeof PLUS_ACCOUNT_ACCESS_STRATEGY_CODEX_SESSION_UI !== 'undefined'
|
||||
? PLUS_ACCOUNT_ACCESS_STRATEGY_CODEX_SESSION_UI
|
||||
: 'codex_session';
|
||||
const normalizedValue = String(value || '').trim().toLowerCase();
|
||||
const isSessionImport = normalizedValue === sessionUiValue
|
||||
|| normalizedValue === sub2apiSessionStrategyValue
|
||||
|| normalizedValue === cpaSessionStrategyValue;
|
||||
if (!isSessionImport) {
|
||||
return oauthStrategyValue;
|
||||
}
|
||||
const normalizedTargetId = typeof normalizePlusStrategyTargetId === 'function'
|
||||
? normalizePlusStrategyTargetId(targetId)
|
||||
: normalizePanelModeSafe(targetId || '');
|
||||
if (normalizedTargetId === 'sub2api') {
|
||||
return sub2apiSessionStrategyValue;
|
||||
}
|
||||
if (normalizedTargetId === 'cpa') {
|
||||
return cpaSessionStrategyValue;
|
||||
}
|
||||
return oauthStrategyValue;
|
||||
});
|
||||
const selectedTargetId = typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(activeFlowId)
|
||||
: (activeFlowId === defaultFlowId
|
||||
? rawPanelMode
|
||||
: String(selectPanelMode?.value || latestState?.kiroTargetId || 'kiro-rs').trim().toLowerCase() || 'kiro-rs');
|
||||
: normalizeTargetIdForFlowSafe(
|
||||
activeFlowId,
|
||||
selectPanelMode?.value || latestState?.targetId || '',
|
||||
typeof getDefaultTargetIdForFlow === 'function'
|
||||
? getDefaultTargetIdForFlow(activeFlowId)
|
||||
: (activeFlowId === defaultFlowId ? 'cpa' : 'kiro-rs')
|
||||
);
|
||||
const openAiTargetId = normalizePanelModeSafe(
|
||||
activeFlowId === defaultFlowId
|
||||
? selectedTargetId
|
||||
: getSelectedPanelMode(latestState)
|
||||
);
|
||||
const rawPlusModeEnabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
|
||||
? Boolean(inputPlusModeEnabled.checked)
|
||||
: Boolean(latestState?.plusModeEnabled);
|
||||
@@ -4495,14 +4695,12 @@ function collectSettingsPayload() {
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
activeFlowId,
|
||||
targetId: selectedTargetId,
|
||||
panelMode: rawPanelMode,
|
||||
signupMethod: selectedSignupMethod,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
activeFlowId,
|
||||
...(activeFlowId === defaultFlowId
|
||||
? { panelMode: rawPanelMode }
|
||||
: { kiroTargetId: selectedTargetId }),
|
||||
flowId: activeFlowId,
|
||||
targetId: selectedTargetId,
|
||||
plusModeEnabled: rawPlusModeEnabled,
|
||||
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||
phoneVerificationEnabled: rawPhoneVerificationEnabled,
|
||||
@@ -4517,15 +4715,13 @@ function collectSettingsPayload() {
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId,
|
||||
panelMode: rawPanelMode,
|
||||
targetId: selectedTargetId,
|
||||
signupMethod: selectedSignupMethod,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
activeFlowId,
|
||||
...(activeFlowId === defaultFlowId
|
||||
? { panelMode: rawPanelMode }
|
||||
: { kiroTargetId: selectedTargetId }),
|
||||
flowId: activeFlowId,
|
||||
targetId: selectedTargetId,
|
||||
plusModeEnabled: rawPlusModeEnabled,
|
||||
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||
phoneVerificationEnabled: rawPhoneVerificationEnabled,
|
||||
@@ -4534,8 +4730,12 @@ function collectSettingsPayload() {
|
||||
})
|
||||
: null;
|
||||
})();
|
||||
const effectivePanelMode = capabilityState?.effectivePanelMode || capabilityState?.panelMode || rawPanelMode;
|
||||
const effectiveTargetId = capabilityState?.effectiveTargetId || selectedTargetId;
|
||||
const effectiveOpenAiTargetId = normalizePanelModeSafe(
|
||||
activeFlowId === defaultFlowId
|
||||
? effectiveTargetId
|
||||
: openAiTargetId
|
||||
);
|
||||
const effectivePlusModeEnabled = capabilityState
|
||||
? Boolean(capabilityState.runtimeLocks?.plusModeEnabled)
|
||||
: rawPlusModeEnabled;
|
||||
@@ -4623,16 +4823,7 @@ function collectSettingsPayload() {
|
||||
});
|
||||
return {
|
||||
activeFlowId,
|
||||
...(accountContributionEnabled ? {} : {
|
||||
...(activeFlowId === defaultFlowId ? { panelMode: effectivePanelMode } : {}),
|
||||
}),
|
||||
kiroTargetId: normalizeKiroTargetIdSafe(
|
||||
'kiro',
|
||||
activeFlowId === 'kiro'
|
||||
? effectiveTargetId
|
||||
: (latestState?.kiroTargetId || 'kiro-rs'),
|
||||
'kiro-rs'
|
||||
),
|
||||
targetId: effectiveTargetId,
|
||||
kiroRsUrl: currentKiroRsUrlValue !== null
|
||||
? (currentKiroRsUrlValue || defaultKiroRsUrl)
|
||||
: (String(latestState?.kiroRsUrl || defaultKiroRsUrl).trim() || defaultKiroRsUrl),
|
||||
@@ -4677,7 +4868,9 @@ function collectSettingsPayload() {
|
||||
codex2apiAdminKey: inputCodex2ApiAdminKey.value.trim(),
|
||||
plusModeEnabled: effectivePlusModeEnabled,
|
||||
plusPaymentMethod,
|
||||
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||
plusAccountAccessStrategy: activeFlowId === defaultFlowId
|
||||
? resolvePlusAccountAccessStrategyForTargetSafe(requestedPlusAccountAccessStrategy, effectiveOpenAiTargetId)
|
||||
: requestedPlusAccountAccessStrategy,
|
||||
hostedCheckoutVerificationUrl: typeof inputHostedCheckoutVerificationUrl !== 'undefined' && inputHostedCheckoutVerificationUrl
|
||||
? String(inputHostedCheckoutVerificationUrl.value || '').trim()
|
||||
: String(latestState?.hostedCheckoutVerificationUrl || '').trim(),
|
||||
@@ -8683,12 +8876,9 @@ function getSelectedTargetIdForState(state = latestState, flowId = getSelectedFl
|
||||
if (schema?.getSelectedTargetId) {
|
||||
return schema.getSelectedTargetId(state || {}, normalizedFlowId);
|
||||
}
|
||||
if (normalizedFlowId === DEFAULT_ACTIVE_FLOW_ID) {
|
||||
return normalizePanelMode(state?.panelMode || getDefaultTargetIdForFlow(normalizedFlowId));
|
||||
}
|
||||
return normalizeTargetIdForFlow(
|
||||
normalizedFlowId,
|
||||
state?.kiroTargetId || '',
|
||||
state?.targetId || '',
|
||||
getDefaultTargetIdForFlow(normalizedFlowId)
|
||||
);
|
||||
}
|
||||
@@ -8698,14 +8888,9 @@ function getSelectedTargetId(flowId = getSelectedFlowId()) {
|
||||
const selectedValue = typeof selectPanelMode !== 'undefined' && selectPanelMode
|
||||
? selectPanelMode.value
|
||||
: '';
|
||||
if (normalizedFlowId === DEFAULT_ACTIVE_FLOW_ID) {
|
||||
return normalizePanelMode(
|
||||
selectedValue || latestState?.panelMode || getDefaultTargetIdForFlow(normalizedFlowId)
|
||||
);
|
||||
}
|
||||
return normalizeTargetIdForFlow(
|
||||
normalizedFlowId,
|
||||
selectedValue || latestState?.kiroTargetId || '',
|
||||
selectedValue || latestState?.targetId || '',
|
||||
getDefaultTargetIdForFlow(normalizedFlowId)
|
||||
);
|
||||
}
|
||||
@@ -8857,24 +9042,15 @@ function resolveCurrentSidepanelCapabilities(options = {}) {
|
||||
};
|
||||
const targetId = options?.targetId !== undefined
|
||||
? options.targetId
|
||||
: (activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? (options?.panelMode ?? state?.panelMode)
|
||||
: (options?.kiroTargetId ?? state?.kiroTargetId));
|
||||
if (activeFlowId === DEFAULT_ACTIVE_FLOW_ID) {
|
||||
state.panelMode = normalizePanelMode(
|
||||
targetId || state?.panelMode || getDefaultTargetIdForFlow(activeFlowId)
|
||||
);
|
||||
} else {
|
||||
state.kiroTargetId = normalizeTargetIdForFlow(
|
||||
activeFlowId,
|
||||
targetId || state?.kiroTargetId || '',
|
||||
getDefaultTargetIdForFlow(activeFlowId)
|
||||
);
|
||||
}
|
||||
: (state?.targetId ?? getSelectedTargetIdForState(state, activeFlowId));
|
||||
state.targetId = normalizeTargetIdForFlow(
|
||||
activeFlowId,
|
||||
targetId || state?.targetId || '',
|
||||
getDefaultTargetIdForFlow(activeFlowId)
|
||||
);
|
||||
return registry.resolveSidepanelCapabilities({
|
||||
activeFlowId,
|
||||
panelMode: state?.panelMode,
|
||||
targetId: activeFlowId === DEFAULT_ACTIVE_FLOW_ID ? state?.panelMode : state?.kiroTargetId,
|
||||
targetId: state.targetId,
|
||||
signupMethod: options?.signupMethod ?? state?.signupMethod,
|
||||
state,
|
||||
});
|
||||
@@ -8887,7 +9063,7 @@ function resolveStepDefinitionCapabilityState(state = latestState, options = {})
|
||||
};
|
||||
const capabilityState = resolveCurrentSidepanelCapabilities({
|
||||
activeFlowId: options?.activeFlowId ?? nextState?.activeFlowId,
|
||||
panelMode: options?.panelMode ?? nextState?.panelMode,
|
||||
targetId: options?.targetId ?? nextState?.targetId,
|
||||
signupMethod: options?.signupMethod ?? nextState?.signupMethod,
|
||||
state: nextState,
|
||||
});
|
||||
@@ -8905,16 +9081,35 @@ function resolveStepDefinitionCapabilityState(state = latestState, options = {})
|
||||
};
|
||||
}
|
||||
|
||||
function getSelectedPanelMode() {
|
||||
function getSelectedPanelMode(state = latestState) {
|
||||
const resolvedPanelMode = normalizePanelMode(
|
||||
typeof selectPanelMode !== 'undefined' && selectPanelMode
|
||||
? selectPanelMode.value
|
||||
: (typeof latestState !== 'undefined' ? latestState?.panelMode : '')
|
||||
typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState({
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
...(state || {}),
|
||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
flowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
}, DEFAULT_ACTIVE_FLOW_ID)
|
||||
: (
|
||||
typeof selectPanelMode !== 'undefined' && selectPanelMode
|
||||
? selectPanelMode.value
|
||||
: (typeof state !== 'undefined' ? state?.targetId : '')
|
||||
)
|
||||
);
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({ panelMode: resolvedPanelMode })
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
targetId: resolvedPanelMode,
|
||||
state: {
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
...(state || {}),
|
||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
flowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
targetId: resolvedPanelMode,
|
||||
},
|
||||
})
|
||||
: null;
|
||||
return capabilityState?.effectivePanelMode || capabilityState?.panelMode || resolvedPanelMode;
|
||||
return normalizePanelMode(capabilityState?.effectiveTargetId || resolvedPanelMode);
|
||||
}
|
||||
|
||||
function getSelectedSignupMethod() {
|
||||
@@ -8943,7 +9138,9 @@ function canSelectPhoneSignupMethod() {
|
||||
: Boolean(latestState?.accountContributionEnabled);
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode,
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
state: {
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
phoneVerificationEnabled: phoneEnabled,
|
||||
@@ -8959,7 +9156,9 @@ function canSelectPhoneSignupMethod() {
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: typeof latestState !== 'undefined' ? latestState?.activeFlowId : '',
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : (latestState?.panelMode || 'cpa'),
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
state: {
|
||||
...(typeof latestState !== 'undefined' ? latestState : {}),
|
||||
phoneVerificationEnabled: phoneEnabled,
|
||||
@@ -9061,7 +9260,9 @@ function updatePhoneVerificationSettingsUI() {
|
||||
: Boolean(latestState?.plusModeEnabled);
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode,
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
signupMethod: typeof getSelectedSignupMethod === 'function' ? getSelectedSignupMethod() : latestState?.signupMethod,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
@@ -9077,7 +9278,9 @@ function updatePhoneVerificationSettingsUI() {
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: latestState?.activeFlowId,
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : (latestState?.panelMode || 'cpa'),
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
signupMethod: typeof getSelectedSignupMethod === 'function' ? getSelectedSignupMethod() : latestState?.signupMethod,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
@@ -9366,7 +9569,9 @@ function updatePlusModeUI() {
|
||||
: false;
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode,
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
plusModeEnabled: rawEnabled,
|
||||
@@ -9381,7 +9586,9 @@ function updatePlusModeUI() {
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: latestState?.activeFlowId,
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : (latestState?.panelMode || 'cpa'),
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
plusModeEnabled: rawEnabled,
|
||||
@@ -9403,10 +9610,8 @@ function updatePlusModeUI() {
|
||||
|| requestedPlusAccountAccessStrategy
|
||||
|| oauthStrategyValue;
|
||||
const effectiveTargetId = resolveStrategyTargetId(
|
||||
capabilityState?.effectivePanelMode
|
||||
|| capabilityState?.effectiveTargetId
|
||||
|| capabilityState?.panelMode
|
||||
|| (typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode)
|
||||
capabilityState?.effectiveTargetId
|
||||
|| (typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode(latestState) : latestState?.targetId)
|
||||
|| 'cpa'
|
||||
);
|
||||
const method = enabled ? getSelectedPlusPaymentMethod() : defaultMethod;
|
||||
@@ -9711,7 +9916,12 @@ function syncSignupPhoneInputFromState(state = latestState) {
|
||||
: (String(rawSignupMethod || '').trim().toLowerCase() === 'phone' ? 'phone' : 'email');
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
panelMode: state?.panelMode || latestState?.panelMode,
|
||||
targetId: typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState({
|
||||
...(latestState || {}),
|
||||
...(state || {}),
|
||||
}, state?.activeFlowId || latestState?.activeFlowId || DEFAULT_ACTIVE_FLOW_ID)
|
||||
: (state?.targetId || latestState?.targetId),
|
||||
signupMethod: selectedMethod,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
@@ -9727,7 +9937,12 @@ function syncSignupPhoneInputFromState(state = latestState) {
|
||||
return registry?.resolveSidepanelCapabilities
|
||||
? registry.resolveSidepanelCapabilities({
|
||||
activeFlowId: state?.activeFlowId || latestState?.activeFlowId,
|
||||
panelMode: state?.panelMode || latestState?.panelMode,
|
||||
targetId: typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState({
|
||||
...(latestState || {}),
|
||||
...(state || {}),
|
||||
}, state?.activeFlowId || latestState?.activeFlowId || DEFAULT_ACTIVE_FLOW_ID)
|
||||
: (state?.targetId || latestState?.targetId),
|
||||
signupMethod: selectedMethod,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
@@ -9925,13 +10140,44 @@ async function openPlusManualConfirmationDialog(options = {}) {
|
||||
const method = String(options.method || '').trim().toLowerCase();
|
||||
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
|
||||
const activeFlowId = String(latestState?.activeFlowId || latestState?.flowId || 'openai').trim().toLowerCase();
|
||||
const panelMode = String(latestState?.panelMode || latestState?.openaiIntegrationTargetId || '').trim().toLowerCase();
|
||||
const normalizeTargetIdForFlowSafe = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow
|
||||
: ((flowId, targetId = '', fallback = '') => {
|
||||
const normalizedFlowId = String(flowId || '').trim().toLowerCase() || 'openai';
|
||||
if (normalizedFlowId === 'openai') {
|
||||
const normalizedTargetId = String(targetId || fallback || '').trim().toLowerCase();
|
||||
return normalizedTargetId === 'sub2api' || normalizedTargetId === 'codex2api' ? normalizedTargetId : 'cpa';
|
||||
}
|
||||
const normalizedTargetId = String(targetId || '').trim().toLowerCase();
|
||||
return normalizedTargetId || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||
});
|
||||
const getDefaultTargetIdForFlowSafe = typeof getDefaultTargetIdForFlow === 'function'
|
||||
? getDefaultTargetIdForFlow
|
||||
: ((flowId = 'openai') => (String(flowId || '').trim().toLowerCase() === 'openai' ? 'cpa' : 'kiro-rs'));
|
||||
const normalizePlusStrategyTargetIdSafe = typeof normalizePlusStrategyTargetId === 'function'
|
||||
? normalizePlusStrategyTargetId
|
||||
: ((value = '') => {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === 'sub2api' || normalized === 'codex2api') {
|
||||
return normalized;
|
||||
}
|
||||
return 'cpa';
|
||||
});
|
||||
const targetId = normalizePlusStrategyTargetIdSafe(
|
||||
typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(latestState, activeFlowId)
|
||||
: normalizeTargetIdForFlowSafe(
|
||||
activeFlowId,
|
||||
latestState?.targetId || '',
|
||||
getDefaultTargetIdForFlowSafe(activeFlowId)
|
||||
)
|
||||
);
|
||||
const signupMethod = String(latestState?.resolvedSignupMethod || latestState?.signupMethod || 'email').trim().toLowerCase();
|
||||
const plusModeEnabled = latestState?.plusModeEnabled === undefined ? true : Boolean(latestState.plusModeEnabled);
|
||||
const plusAccountAccessStrategy = String(latestState?.plusAccountAccessStrategy || 'oauth').trim().toLowerCase();
|
||||
const useSub2ApiSessionImport = plusModeEnabled
|
||||
&& activeFlowId === 'openai'
|
||||
&& panelMode === 'sub2api'
|
||||
&& targetId === 'sub2api'
|
||||
&& signupMethod === 'email'
|
||||
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||
const continuationActionLabel = useSub2ApiSessionImport
|
||||
@@ -9996,13 +10242,44 @@ async function syncPlusManualConfirmationDialog() {
|
||||
const step = Number(latestState?.plusManualConfirmationStep) || 0;
|
||||
const method = String(latestState?.plusManualConfirmationMethod || '').trim().toLowerCase();
|
||||
const activeFlowId = String(latestState?.activeFlowId || latestState?.flowId || 'openai').trim().toLowerCase();
|
||||
const panelMode = String(latestState?.panelMode || latestState?.openaiIntegrationTargetId || '').trim().toLowerCase();
|
||||
const normalizeTargetIdForFlowSafe = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow
|
||||
: ((flowId, targetId = '', fallback = '') => {
|
||||
const normalizedFlowId = String(flowId || '').trim().toLowerCase() || 'openai';
|
||||
if (normalizedFlowId === 'openai') {
|
||||
const normalizedTargetId = String(targetId || fallback || '').trim().toLowerCase();
|
||||
return normalizedTargetId === 'sub2api' || normalizedTargetId === 'codex2api' ? normalizedTargetId : 'cpa';
|
||||
}
|
||||
const normalizedTargetId = String(targetId || '').trim().toLowerCase();
|
||||
return normalizedTargetId || String(fallback || '').trim().toLowerCase() || 'kiro-rs';
|
||||
});
|
||||
const getDefaultTargetIdForFlowSafe = typeof getDefaultTargetIdForFlow === 'function'
|
||||
? getDefaultTargetIdForFlow
|
||||
: ((flowId = 'openai') => (String(flowId || '').trim().toLowerCase() === 'openai' ? 'cpa' : 'kiro-rs'));
|
||||
const normalizePlusStrategyTargetIdSafe = typeof normalizePlusStrategyTargetId === 'function'
|
||||
? normalizePlusStrategyTargetId
|
||||
: ((value = '') => {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === 'sub2api' || normalized === 'codex2api') {
|
||||
return normalized;
|
||||
}
|
||||
return 'cpa';
|
||||
});
|
||||
const targetId = normalizePlusStrategyTargetIdSafe(
|
||||
typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(latestState, activeFlowId)
|
||||
: normalizeTargetIdForFlowSafe(
|
||||
activeFlowId,
|
||||
latestState?.targetId || '',
|
||||
getDefaultTargetIdForFlowSafe(activeFlowId)
|
||||
)
|
||||
);
|
||||
const signupMethod = String(latestState?.resolvedSignupMethod || latestState?.signupMethod || 'email').trim().toLowerCase();
|
||||
const plusModeEnabled = latestState?.plusModeEnabled === undefined ? true : Boolean(latestState.plusModeEnabled);
|
||||
const plusAccountAccessStrategy = String(latestState?.plusAccountAccessStrategy || 'oauth').trim().toLowerCase();
|
||||
const useSub2ApiSessionImport = plusModeEnabled
|
||||
&& activeFlowId === 'openai'
|
||||
&& panelMode === 'sub2api'
|
||||
&& targetId === 'sub2api'
|
||||
&& signupMethod === 'email'
|
||||
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||
const continuationActionLabel = useSub2ApiSessionImport
|
||||
@@ -10523,7 +10800,7 @@ function syncStepDefinitionsFromUiState(stateOverrides = {}) {
|
||||
const stepDefinitionState = typeof resolveStepDefinitionCapabilityState === 'function'
|
||||
? resolveStepDefinitionCapabilityState(nextState, {
|
||||
activeFlowId: nextState?.activeFlowId,
|
||||
panelMode: nextState?.panelMode,
|
||||
targetId: nextState?.targetId,
|
||||
signupMethod: nextState?.signupMethod,
|
||||
state: nextState,
|
||||
})
|
||||
@@ -10616,7 +10893,7 @@ function applySettingsState(state) {
|
||||
? syncFlowSelectorsFromState(state)
|
||||
: {
|
||||
activeFlowId: String(state?.activeFlowId || state?.flowId || defaultActiveFlowId).trim().toLowerCase() || defaultActiveFlowId,
|
||||
targetId: String(state?.panelMode || 'cpa').trim().toLowerCase() || 'cpa',
|
||||
targetId: String(state?.targetId || 'cpa').trim().toLowerCase() || 'cpa',
|
||||
};
|
||||
if (typeof applyOperationDelayState === 'function') {
|
||||
applyOperationDelayState(state);
|
||||
@@ -10748,24 +11025,38 @@ function applySettingsState(state) {
|
||||
if (typeof displayKiroRsTestStatus !== 'undefined' && displayKiroRsTestStatus) {
|
||||
displayKiroRsTestStatus.textContent = kiroRsConnectionTestStatusText;
|
||||
}
|
||||
const resolveKiroRuntimeState = typeof getKiroRuntimeState === 'function'
|
||||
? getKiroRuntimeState
|
||||
: ((value = {}) => {
|
||||
const runtimeState = value?.runtimeState?.flowState?.kiro;
|
||||
if (runtimeState && typeof runtimeState === 'object' && !Array.isArray(runtimeState)) {
|
||||
return runtimeState;
|
||||
}
|
||||
const flowState = value?.flowState?.kiro;
|
||||
if (flowState && typeof flowState === 'object' && !Array.isArray(flowState)) {
|
||||
return flowState;
|
||||
}
|
||||
return {};
|
||||
});
|
||||
const kiroRuntimeState = resolveKiroRuntimeState(state);
|
||||
if (typeof displayKiroWebStatus !== 'undefined' && displayKiroWebStatus) {
|
||||
const kiroWebStatus = String(
|
||||
state?.kiroRuntime?.webAuth?.status
|
||||
|| state?.kiroRuntime?.register?.status
|
||||
kiroRuntimeState?.webAuth?.status
|
||||
|| kiroRuntimeState?.register?.status
|
||||
|| ''
|
||||
).trim();
|
||||
displayKiroWebStatus.textContent = kiroWebStatus || '未开始';
|
||||
}
|
||||
if (typeof displayKiroLoginUrl !== 'undefined' && displayKiroLoginUrl) {
|
||||
const kiroLoginUrl = String(
|
||||
state?.kiroRuntime?.register?.loginUrl
|
||||
kiroRuntimeState?.register?.loginUrl
|
||||
|| ''
|
||||
).trim();
|
||||
displayKiroLoginUrl.textContent = kiroLoginUrl || '未打开';
|
||||
}
|
||||
if (typeof displayKiroUploadStatus !== 'undefined' && displayKiroUploadStatus) {
|
||||
const kiroUploadStatus = String(
|
||||
state?.kiroRuntime?.upload?.status
|
||||
kiroRuntimeState?.upload?.status
|
||||
|| ''
|
||||
).trim();
|
||||
displayKiroUploadStatus.textContent = getKiroUploadStatusLabel(kiroUploadStatus);
|
||||
@@ -12404,7 +12695,9 @@ function updateMailProviderUI() {
|
||||
: latestState?.icloudHostPreference;
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode,
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
state: latestState || {},
|
||||
})
|
||||
: null;
|
||||
@@ -13048,23 +13341,16 @@ function updatePanelModeUI() {
|
||||
: normalizeFlowId(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID);
|
||||
const targetId = typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(activeFlowId)
|
||||
: (activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? normalizePanelMode(selectPanelMode?.value || latestState?.panelMode || 'cpa')
|
||||
: String(selectPanelMode?.value || latestState?.kiroTargetId || 'kiro-rs').trim().toLowerCase() || 'kiro-rs');
|
||||
const rawPanelMode = activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? normalizePanelMode(targetId || latestState?.panelMode || 'cpa')
|
||||
: normalizePanelMode(latestState?.panelMode || 'cpa');
|
||||
: normalizeTargetIdForFlow(activeFlowId, selectPanelMode?.value || latestState?.targetId || '', getDefaultTargetIdForFlow(activeFlowId));
|
||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||
? resolveCurrentSidepanelCapabilities({
|
||||
activeFlowId,
|
||||
targetId,
|
||||
panelMode: rawPanelMode,
|
||||
state: {
|
||||
...(latestState || {}),
|
||||
activeFlowId,
|
||||
...(activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? { panelMode: rawPanelMode }
|
||||
: { kiroTargetId: targetId }),
|
||||
flowId: activeFlowId,
|
||||
targetId,
|
||||
},
|
||||
})
|
||||
: null;
|
||||
@@ -13089,12 +13375,16 @@ function updatePanelModeUI() {
|
||||
if (typeof updatePhoneVerificationSettingsUI === 'function') {
|
||||
updatePhoneVerificationSettingsUI();
|
||||
}
|
||||
const panelMode = capabilityState?.effectivePanelMode || capabilityState?.panelMode || rawPanelMode;
|
||||
const displayTargetId = normalizePanelMode(
|
||||
activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? (capabilityState?.effectiveTargetId || targetId)
|
||||
: getSelectedPanelMode(latestState)
|
||||
);
|
||||
|
||||
const useCodex2Api = panelMode === 'codex2api';
|
||||
const useCodex2Api = displayTargetId === 'codex2api';
|
||||
const step9Btn = document.querySelector('.step-btn[data-step-key="platform-verify"]');
|
||||
if (step9Btn && activeFlowId === DEFAULT_ACTIVE_FLOW_ID) {
|
||||
step9Btn.textContent = panelMode === 'sub2api'
|
||||
step9Btn.textContent = displayTargetId === 'sub2api'
|
||||
? 'SUB2API 回调验证'
|
||||
: (useCodex2Api ? 'Codex2API 回调验证' : 'CPA 回调验证');
|
||||
}
|
||||
@@ -14042,7 +14332,7 @@ const accountContributionManager = window.SidepanelContributionMode?.createContr
|
||||
: String(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID),
|
||||
getSelectedTargetId: (flowId, state = latestState) => (typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(state, flowId)
|
||||
: (String(state?.panelMode || state?.kiroTargetId || 'cpa').trim().toLowerCase() || 'cpa')),
|
||||
: normalizeTargetIdForFlow(flowId, state?.targetId || '', getDefaultTargetIdForFlow(flowId))),
|
||||
isModeSwitchBlocked: isContributionModeSwitchBlocked,
|
||||
openConfirmModal,
|
||||
openExternalUrl,
|
||||
@@ -14570,7 +14860,9 @@ async function startAutoRunFromCurrentSettings() {
|
||||
}
|
||||
const validationState = {
|
||||
...(latestState || {}),
|
||||
panelMode: typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode,
|
||||
targetId: typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(getSelectedFlowId(latestState))
|
||||
: latestState?.targetId,
|
||||
signupMethod: typeof getSelectedSignupMethod === 'function' ? getSelectedSignupMethod() : latestState?.signupMethod,
|
||||
phoneVerificationEnabled: typeof inputPhoneVerificationEnabled !== 'undefined' && inputPhoneVerificationEnabled
|
||||
? Boolean(inputPhoneVerificationEnabled.checked)
|
||||
@@ -14582,7 +14874,7 @@ async function startAutoRunFromCurrentSettings() {
|
||||
};
|
||||
return registry.validateAutoRunStart({
|
||||
activeFlowId: validationState.activeFlowId,
|
||||
panelMode: validationState.panelMode,
|
||||
targetId: validationState.targetId,
|
||||
signupMethod: validationState.signupMethod,
|
||||
state: validationState,
|
||||
});
|
||||
@@ -14650,11 +14942,7 @@ async function startAutoRunFromCurrentSettings() {
|
||||
: (String(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID).trim().toLowerCase() || DEFAULT_ACTIVE_FLOW_ID);
|
||||
const targetId = typeof getSelectedTargetId === 'function'
|
||||
? getSelectedTargetId(activeFlowId)
|
||||
: (
|
||||
activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? normalizePanelMode(latestState?.panelMode || 'cpa')
|
||||
: (String(latestState?.kiroTargetId || 'kiro-rs').trim().toLowerCase() || 'kiro-rs')
|
||||
);
|
||||
: normalizeTargetIdForFlow(activeFlowId, latestState?.targetId || '', getDefaultTargetIdForFlow(activeFlowId));
|
||||
inputAutoDelayMinutes.value = String(delayMinutes);
|
||||
btnAutoRun.innerHTML = delayEnabled
|
||||
? '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg> 计划中...'
|
||||
@@ -15230,9 +15518,7 @@ selectPanelMode.addEventListener('change', async () => {
|
||||
: (activeFlowId === DEFAULT_ACTIVE_FLOW_ID ? 'cpa' : 'kiro-rs');
|
||||
const previousTargetId = typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(latestState, activeFlowId)
|
||||
: (activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? normalizePanelMode(latestState?.panelMode || defaultTargetId)
|
||||
: String(latestState?.kiroTargetId || defaultTargetId).trim().toLowerCase() || defaultTargetId);
|
||||
: normalizeTargetIdForFlow(activeFlowId, latestState?.targetId || '', defaultTargetId);
|
||||
let nextTargetId = typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow(activeFlowId, selectPanelMode.value, defaultTargetId)
|
||||
: (activeFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
@@ -15243,7 +15529,7 @@ selectPanelMode.addEventListener('change', async () => {
|
||||
selectPanelMode.value = nextPanelMode;
|
||||
const confirmed = await confirmCpaPhoneSignupIfNeeded({
|
||||
signupMethod: getSelectedSignupMethod(),
|
||||
panelMode: nextPanelMode,
|
||||
targetId: nextPanelMode,
|
||||
});
|
||||
if (!confirmed) {
|
||||
selectPanelMode.value = previousTargetId;
|
||||
@@ -15254,7 +15540,7 @@ selectPanelMode.addEventListener('change', async () => {
|
||||
syncLatestState({
|
||||
activeFlowId,
|
||||
flowId: activeFlowId,
|
||||
panelMode: nextPanelMode,
|
||||
targetId: nextPanelMode,
|
||||
});
|
||||
if (
|
||||
typeof selectPlusAccountAccessStrategy !== 'undefined'
|
||||
@@ -15278,7 +15564,7 @@ selectPanelMode.addEventListener('change', async () => {
|
||||
syncLatestState({
|
||||
activeFlowId,
|
||||
flowId: activeFlowId,
|
||||
kiroTargetId: nextTargetId,
|
||||
targetId: nextTargetId,
|
||||
});
|
||||
}
|
||||
updatePanelModeUI();
|
||||
@@ -15305,7 +15591,7 @@ selectPlusAccountAccessStrategy?.addEventListener('change', () => {
|
||||
selectPlusAccountAccessStrategy.value = nextUiValue;
|
||||
selectPlusAccountAccessStrategy.dataset.requestedValue = resolvePlusAccountAccessStrategyForTarget(
|
||||
nextUiValue,
|
||||
typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode() : latestState?.panelMode
|
||||
typeof getSelectedPanelMode === 'function' ? getSelectedPanelMode(latestState) : latestState?.targetId
|
||||
);
|
||||
updatePlusModeUI();
|
||||
markSettingsDirty(true);
|
||||
@@ -16100,19 +16386,13 @@ selectFlow?.addEventListener('change', () => {
|
||||
: (nextActiveFlowId === DEFAULT_ACTIVE_FLOW_ID ? 'cpa' : 'kiro-rs');
|
||||
const nextTargetId = typeof getSelectedTargetIdForState === 'function'
|
||||
? getSelectedTargetIdForState(nextStateBase, nextActiveFlowId)
|
||||
: (nextActiveFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? normalizePanelMode(nextStateBase?.panelMode || defaultTargetId)
|
||||
: String(nextStateBase?.kiroTargetId || defaultTargetId).trim().toLowerCase() || defaultTargetId);
|
||||
: normalizeTargetIdForFlow(nextActiveFlowId, nextStateBase?.targetId || '', defaultTargetId);
|
||||
syncLatestState({
|
||||
activeFlowId: nextActiveFlowId,
|
||||
flowId: nextActiveFlowId,
|
||||
...(nextActiveFlowId === DEFAULT_ACTIVE_FLOW_ID
|
||||
? { panelMode: normalizePanelMode(nextTargetId || defaultTargetId) }
|
||||
: {
|
||||
kiroTargetId: typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow(nextActiveFlowId, nextTargetId, defaultTargetId)
|
||||
: (String(nextTargetId || defaultTargetId).trim().toLowerCase() || defaultTargetId),
|
||||
}),
|
||||
targetId: typeof normalizeTargetIdForFlow === 'function'
|
||||
? normalizeTargetIdForFlow(nextActiveFlowId, nextTargetId, defaultTargetId)
|
||||
: (String(nextTargetId || defaultTargetId).trim().toLowerCase() || defaultTargetId),
|
||||
});
|
||||
updatePanelModeUI();
|
||||
if (typeof syncStepDefinitionsFromUiState === 'function') {
|
||||
@@ -16320,7 +16600,7 @@ signupMethodButtons.forEach((button) => {
|
||||
const nextSignupMethod = normalizeSignupMethod(button.dataset.signupMethod);
|
||||
const confirmed = await confirmCpaPhoneSignupIfNeeded({
|
||||
signupMethod: nextSignupMethod,
|
||||
panelMode: getSelectedPanelMode(),
|
||||
targetId: getSelectedPanelMode(latestState),
|
||||
});
|
||||
if (!confirmed) {
|
||||
updateSignupMethodUI();
|
||||
@@ -17047,15 +17327,18 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
setLocalCpaStep9Mode(message.payload.localCpaStep9Mode);
|
||||
}
|
||||
if (
|
||||
message.payload.panelMode !== undefined
|
||||
message.payload.targetId !== undefined
|
||||
|| message.payload.activeFlowId !== undefined
|
||||
|| message.payload.flowId !== undefined
|
||||
|| message.payload.kiroTargetId !== undefined
|
||||
) {
|
||||
if (typeof syncFlowSelectorsFromState === 'function') {
|
||||
syncFlowSelectorsFromState(latestState);
|
||||
} else if (message.payload.panelMode !== undefined) {
|
||||
selectPanelMode.value = normalizePanelMode(message.payload.panelMode || 'cpa');
|
||||
} else if (message.payload.targetId !== undefined) {
|
||||
selectPanelMode.value = normalizeTargetIdForFlow(
|
||||
latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID,
|
||||
message.payload.targetId || '',
|
||||
getDefaultTargetIdForFlow(latestState?.activeFlowId || latestState?.flowId || DEFAULT_ACTIVE_FLOW_ID)
|
||||
);
|
||||
}
|
||||
updatePanelModeUI();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const source = fs.readFileSync('content/signup-page.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/content/openai-auth.js', 'utf8');
|
||||
|
||||
function extractFunction(name) {
|
||||
const markers = [`async function ${name}(`, `function ${name}(`];
|
||||
|
||||
@@ -2,8 +2,8 @@ const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const { createAuthPageRecovery } = require('../content/auth-page-recovery.js');
|
||||
const source = fs.readFileSync('content/auth-page-recovery.js', 'utf8');
|
||||
const { createAuthPageRecovery } = require('../flows/openai/content/auth-page-recovery.js');
|
||||
const source = fs.readFileSync('flows/openai/content/auth-page-recovery.js', 'utf8');
|
||||
|
||||
function extractFunction(sourceText, name) {
|
||||
const start = sourceText.indexOf(`function ${name}(`);
|
||||
|
||||
@@ -311,10 +311,10 @@ async function runAutoSequenceFromStep() {
|
||||
10: 'completed',
|
||||
}),
|
||||
tabRegistry: {
|
||||
'signup-page': { tabId: 88, ready: true },
|
||||
'openai-auth': { tabId: 88, ready: true },
|
||||
},
|
||||
sourceLastUrls: {
|
||||
'signup-page': 'https://auth.openai.com/authorize',
|
||||
'openai-auth': 'https://auth.openai.com/authorize',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ return {
|
||||
assert.equal(api.normalizePersistentSettingValue('signupMethod', 'unknown'), 'email');
|
||||
assert.equal(api.normalizePersistentSettingValue('activeFlowId', 'codex'), 'openai');
|
||||
assert.equal(api.normalizePersistentSettingValue('activeFlowId', 'kiro'), 'kiro');
|
||||
assert.equal(api.normalizePersistentSettingValue('kiroTargetId', 'unknown'), 'kiro-rs');
|
||||
assert.equal(api.normalizePersistentSettingValue('targetId', 'sub2api'), 'sub2api');
|
||||
assert.equal(api.normalizePersistentSettingValue('kiroRsUrl', ''), '');
|
||||
assert.equal(api.normalizePersistentSettingValue('kiroRsKey', ' key-1 '), 'key-1');
|
||||
assert.equal(api.normalizePersistentSettingValue('phoneSmsProvider', '5SIM'), '5sim');
|
||||
|
||||
@@ -120,7 +120,7 @@ const self = {
|
||||
},
|
||||
},
|
||||
};
|
||||
const DEFAULT_STATE = { panelMode: 'cpa' };
|
||||
const DEFAULT_STATE = { targetId: 'cpa' };
|
||||
const CONTRIBUTION_RUNTIME_DEFAULTS = {
|
||||
accountContributionEnabled: false,
|
||||
accountContributionExpected: false,
|
||||
@@ -150,7 +150,7 @@ return { buildAccountContributionState };
|
||||
`)();
|
||||
|
||||
const enabledState = api.buildAccountContributionState(true, {
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
customPassword: 'Secret123!',
|
||||
accountRunHistoryTextEnabled: true,
|
||||
}, {
|
||||
@@ -166,12 +166,12 @@ return { buildAccountContributionState };
|
||||
openai: { enabled: true, adapterId: 'openai-oauth' },
|
||||
});
|
||||
assert.equal(enabledState.contributionSessionId, 'session-001');
|
||||
assert.equal(enabledState.panelMode, 'sub2api');
|
||||
assert.equal(enabledState.targetId, 'sub2api');
|
||||
assert.equal(enabledState.customPassword, '');
|
||||
assert.equal(enabledState.accountRunHistoryTextEnabled, false);
|
||||
|
||||
const disabledState = api.buildAccountContributionState(false, {
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
customPassword: 'Secret123!',
|
||||
accountRunHistoryTextEnabled: true,
|
||||
}, {
|
||||
@@ -184,17 +184,17 @@ return { buildAccountContributionState };
|
||||
assert.equal(disabledState.contributionAdapterId, '');
|
||||
assert.deepStrictEqual(disabledState.flowContributionRuntime, {});
|
||||
assert.equal(disabledState.contributionSessionId, '');
|
||||
assert.equal(disabledState.panelMode, 'sub2api');
|
||||
assert.equal(disabledState.targetId, 'sub2api');
|
||||
assert.equal(disabledState.customPassword, 'Secret123!');
|
||||
|
||||
const plusContributionState = api.buildAccountContributionState(true, {
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
plusModeEnabled: true,
|
||||
customPassword: 'Secret123!',
|
||||
accountRunHistoryTextEnabled: true,
|
||||
}, {});
|
||||
assert.equal(plusContributionState.contributionTargetGroupName, 'openai-plus');
|
||||
assert.equal(plusContributionState.panelMode, 'sub2api');
|
||||
assert.equal(plusContributionState.targetId, 'sub2api');
|
||||
});
|
||||
|
||||
test('resetState preserves contribution runtime across reset', () => {
|
||||
@@ -289,7 +289,7 @@ test('message router handles contribution mode, start flow, and status polling m
|
||||
calls.push({ type: 'toggle', enabled });
|
||||
return {
|
||||
accountContributionEnabled: Boolean(enabled),
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
};
|
||||
},
|
||||
startFlowContribution: async (options) => {
|
||||
@@ -383,7 +383,7 @@ test('message router blocks AUTO_RUN and SCHEDULE_AUTO_RUN when shared auto-run
|
||||
getPendingAutoRunTimerPlan: () => null,
|
||||
getState: async () => ({
|
||||
activeFlowId: 'site-a',
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
signupMethod: 'phone',
|
||||
stepStatuses: {},
|
||||
}),
|
||||
@@ -947,7 +947,7 @@ return { refreshOAuthUrlBeforeStep6 };
|
||||
|
||||
const oauthUrl = await api.refreshOAuthUrlBeforeStep6({
|
||||
accountContributionEnabled: false,
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
email: 'user@example.com',
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ const fs = require('node:fs');
|
||||
const test = require('node:test');
|
||||
|
||||
function loadCpaSessionImportModule() {
|
||||
const source = fs.readFileSync('background/steps/cpa-session-import.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/cpa-session-import.js', 'utf8');
|
||||
return new Function('self', `${source}; return self.MultiPageBackgroundCpaSessionImport;`)({});
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ test('CPA session import step reads current ChatGPT session and completes node',
|
||||
assert.deepStrictEqual(ensureCalls[0].options.inject, [
|
||||
'content/utils.js',
|
||||
'content/operation-delay.js',
|
||||
'content/plus-checkout.js',
|
||||
'flows/openai/content/plus-checkout.js',
|
||||
]);
|
||||
assert.deepStrictEqual(sentMessages, [{
|
||||
tabId: 91,
|
||||
|
||||
@@ -120,20 +120,20 @@ function isPlusModeState(state = {}) {
|
||||
return Boolean(state?.plusModeEnabled);
|
||||
}
|
||||
function resolveCurrentFlowCapabilities(state = {}, options = {}) {
|
||||
const normalizedPanelMode = String(options.panelMode || '').trim().toLowerCase();
|
||||
const normalizedTargetId = String(options.targetId || '').trim().toLowerCase();
|
||||
const requestedStrategy = normalizePlusAccountAccessStrategy(state.plusAccountAccessStrategy);
|
||||
const effectiveStrategy = normalizedPanelMode === 'sub2api'
|
||||
const effectiveStrategy = normalizedTargetId === 'sub2api'
|
||||
? (requestedStrategy === 'sub2api_codex_session' ? 'sub2api_codex_session' : 'oauth')
|
||||
: (normalizedPanelMode === 'cpa'
|
||||
: (normalizedTargetId === 'cpa'
|
||||
? (requestedStrategy === 'cpa_codex_session' ? 'cpa_codex_session' : 'oauth')
|
||||
: 'oauth');
|
||||
return {
|
||||
effectivePanelMode: options.panelMode,
|
||||
effectiveTargetId: options.targetId,
|
||||
effectivePlusAccountAccessStrategy: effectiveStrategy,
|
||||
effectiveSignupMethod: 'email',
|
||||
stepDefinitionOptions: {
|
||||
activeFlowId: 'openai',
|
||||
panelMode: options.panelMode,
|
||||
targetId: options.targetId,
|
||||
plusModeEnabled: Boolean(state.plusModeEnabled),
|
||||
plusPaymentMethod: normalizePlusPaymentMethod(state.plusPaymentMethod),
|
||||
plusAccountAccessStrategy: effectiveStrategy,
|
||||
@@ -158,7 +158,7 @@ test('background step resolution keeps SUB2API session tail only when the effect
|
||||
const state = {
|
||||
activeFlowId: 'openai',
|
||||
flowId: 'openai',
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
plusModeEnabled: true,
|
||||
plusPaymentMethod: 'paypal',
|
||||
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||
@@ -184,7 +184,7 @@ test('background step resolution keeps CPA session tail when the effective Plus
|
||||
const state = {
|
||||
activeFlowId: 'openai',
|
||||
flowId: 'openai',
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
plusModeEnabled: true,
|
||||
plusPaymentMethod: 'paypal',
|
||||
plusAccountAccessStrategy: 'cpa_codex_session',
|
||||
@@ -210,7 +210,7 @@ test('background step resolution falls back to OAuth tail when the requested ses
|
||||
const state = {
|
||||
activeFlowId: 'openai',
|
||||
flowId: 'openai',
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
plusModeEnabled: true,
|
||||
plusPaymentMethod: 'paypal',
|
||||
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||
|
||||
@@ -3,34 +3,42 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
function loadDesktopAuthorizeRunnerApi() {
|
||||
const stateSource = fs.readFileSync('background/kiro/state.js', 'utf8');
|
||||
const clientSource = fs.readFileSync('background/kiro/desktop-client.js', 'utf8');
|
||||
const runnerSource = fs.readFileSync('background/kiro/desktop-authorize-runner.js', 'utf8');
|
||||
const stateSource = fs.readFileSync('flows/kiro/background/state.js', 'utf8');
|
||||
const clientSource = fs.readFileSync('flows/kiro/background/desktop-client.js', 'utf8');
|
||||
const runnerSource = fs.readFileSync('flows/kiro/background/desktop-authorize-runner.js', 'utf8');
|
||||
const globalScope = {};
|
||||
new Function('self', `${stateSource}; ${clientSource}; ${runnerSource}; return self;`)(globalScope);
|
||||
return globalScope.MultiPageBackgroundKiroDesktopAuthorizeRunner;
|
||||
}
|
||||
|
||||
function getKiroRuntime(state = {}) {
|
||||
return state?.runtimeState?.flowState?.kiro || {};
|
||||
}
|
||||
|
||||
function createDesktopAuthorizeState(overrides = {}) {
|
||||
return {
|
||||
kiroRuntime: {
|
||||
session: {
|
||||
desktopTabId: 91,
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {
|
||||
desktopTabId: 91,
|
||||
},
|
||||
register: {
|
||||
email: 'kiro-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'desktop-client-id',
|
||||
clientSecret: 'desktop-client-secret',
|
||||
state: 'desktop-state-001',
|
||||
codeVerifier: 'desktop-code-verifier',
|
||||
redirectUri: 'http://127.0.0.1:43121/oauth/callback',
|
||||
redirectPort: 43121,
|
||||
authorizeUrl: 'https://example.com/authorize',
|
||||
},
|
||||
upload: {},
|
||||
},
|
||||
},
|
||||
register: {
|
||||
email: 'kiro-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'desktop-client-id',
|
||||
clientSecret: 'desktop-client-secret',
|
||||
state: 'desktop-state-001',
|
||||
codeVerifier: 'desktop-code-verifier',
|
||||
redirectUri: 'http://127.0.0.1:43121/oauth/callback',
|
||||
redirectPort: 43121,
|
||||
authorizeUrl: 'https://example.com/authorize',
|
||||
},
|
||||
upload: {},
|
||||
},
|
||||
...overrides,
|
||||
};
|
||||
@@ -73,7 +81,7 @@ test('parseDesktopCallbackUrl validates state and redirect port', () => {
|
||||
});
|
||||
|
||||
test('kiro desktop authorize runner uses a shared 3-minute page-load timeout budget', () => {
|
||||
const source = fs.readFileSync('background/kiro/desktop-authorize-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/desktop-authorize-runner.js', 'utf8');
|
||||
assert.match(source, /DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS/);
|
||||
assert.match(source, /createTimeoutBudget/);
|
||||
assert.match(source, /resolveTimeoutBudget/);
|
||||
@@ -95,14 +103,14 @@ test('background wires the Kiro register injector into desktop authorization run
|
||||
});
|
||||
|
||||
test('kiro desktop authorization opens account page when no web session tab is tracked', () => {
|
||||
const source = fs.readFileSync('background/kiro/desktop-authorize-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/desktop-authorize-runner.js', 'utf8');
|
||||
assert.match(source, /KIRO_WEB_ACCOUNT_URL = 'https:\/\/app\.kiro\.dev\/settings\/account'/);
|
||||
assert.match(source, /chrome\.tabs\.create\(\{\s*url: KIRO_WEB_ACCOUNT_URL,\s*active: true,/);
|
||||
assert.match(source, /未能从已打开页面确认 Kiro Web 登录态,正在打开 Kiro 账号页重新确认/);
|
||||
});
|
||||
|
||||
test('kiro desktop authorization is gated by completed Kiro Web sign-in', () => {
|
||||
const source = fs.readFileSync('background/kiro/desktop-authorize-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/desktop-authorize-runner.js', 'utf8');
|
||||
assert.match(source, /restoreKiroWebSessionFromOpenTabs/);
|
||||
assert.match(source, /GET_KIRO_REGISTER_PAGE_STATE/);
|
||||
assert.match(source, /Kiro Web 登录态尚未建立/);
|
||||
@@ -112,12 +120,16 @@ test('kiro desktop authorization is gated by completed Kiro Web sign-in', () =>
|
||||
test('executeKiroStartDesktopAuthorize restores existing Kiro Web session before desktop auth', async () => {
|
||||
const api = loadDesktopAuthorizeRunnerApi();
|
||||
let currentState = {
|
||||
kiroRuntime: {
|
||||
session: {},
|
||||
register: {},
|
||||
webAuth: {},
|
||||
desktopAuth: {},
|
||||
upload: {},
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {},
|
||||
register: {},
|
||||
webAuth: {},
|
||||
desktopAuth: {},
|
||||
upload: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const setStateCalls = [];
|
||||
@@ -178,7 +190,7 @@ test('executeKiroStartDesktopAuthorize restores existing Kiro Web session before
|
||||
getState: async () => currentState,
|
||||
getTabId: async () => null,
|
||||
isTabAlive: async () => false,
|
||||
KIRO_REGISTER_INJECT_FILES: ['content/kiro/register-page.js'],
|
||||
KIRO_REGISTER_INJECT_FILES: ['flows/kiro/content/register-page.js'],
|
||||
registerTab: async (source, tabId) => {
|
||||
if (source === 'kiro-desktop-authorize') {
|
||||
desktopRegisteredTabId = tabId;
|
||||
@@ -213,10 +225,10 @@ test('executeKiroStartDesktopAuthorize restores existing Kiro Web session before
|
||||
assert.equal(desktopRegisteredTabId, 88);
|
||||
assert.match(openedAuthorizeUrl, /client_id=restored-client-id/);
|
||||
assert.equal(currentState.email, 'restored@duck.com');
|
||||
assert.equal(currentState.kiroRuntime.register.email, 'restored@duck.com');
|
||||
assert.equal(currentState.kiroRuntime.register.status, 'completed');
|
||||
assert.equal(currentState.kiroRuntime.webAuth.status, 'signed_in');
|
||||
assert.equal(completedPayload?.kiroRuntime?.desktopAuth?.clientId, 'restored-client-id');
|
||||
assert.equal(getKiroRuntime(currentState).register.email, 'restored@duck.com');
|
||||
assert.equal(getKiroRuntime(currentState).register.status, 'completed');
|
||||
assert.equal(getKiroRuntime(currentState).webAuth.status, 'signed_in');
|
||||
assert.equal(getKiroRuntime(completedPayload).desktopAuth?.clientId, 'restored-client-id');
|
||||
assert.equal(
|
||||
logs.some(({ message }) => message.includes('检测到已有 Kiro Web 登录态,已恢复账号 restored@duck.com')),
|
||||
true
|
||||
@@ -227,12 +239,16 @@ test('executeKiroStartDesktopAuthorize restores existing Kiro Web session before
|
||||
test('executeKiroStartDesktopAuthorize opens Kiro account page to restore login state', async () => {
|
||||
const api = loadDesktopAuthorizeRunnerApi();
|
||||
let currentState = {
|
||||
kiroRuntime: {
|
||||
session: {},
|
||||
register: {},
|
||||
webAuth: {},
|
||||
desktopAuth: {},
|
||||
upload: {},
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {},
|
||||
register: {},
|
||||
webAuth: {},
|
||||
desktopAuth: {},
|
||||
upload: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const logs = [];
|
||||
@@ -278,7 +294,7 @@ test('executeKiroStartDesktopAuthorize opens Kiro account page to restore login
|
||||
ensureContentScriptReadyOnTab: async (source, tabId, options = {}) => {
|
||||
assert.equal(source, 'kiro-register-page');
|
||||
assert.equal(tabId, 91);
|
||||
assert.deepEqual(options.inject, ['content/kiro/register-page.js']);
|
||||
assert.deepEqual(options.inject, ['flows/kiro/content/register-page.js']);
|
||||
assert.equal(options.injectSource, 'kiro-register-page');
|
||||
},
|
||||
fetchImpl: async () => ({
|
||||
@@ -291,7 +307,7 @@ test('executeKiroStartDesktopAuthorize opens Kiro account page to restore login
|
||||
getState: async () => currentState,
|
||||
getTabId: async () => null,
|
||||
isTabAlive: async () => false,
|
||||
KIRO_REGISTER_INJECT_FILES: ['content/kiro/register-page.js'],
|
||||
KIRO_REGISTER_INJECT_FILES: ['flows/kiro/content/register-page.js'],
|
||||
registerTab: async (source, tabId) => {
|
||||
registeredTabs.push({ source, tabId });
|
||||
},
|
||||
@@ -320,8 +336,8 @@ test('executeKiroStartDesktopAuthorize opens Kiro account page to restore login
|
||||
await runner.executeKiroStartDesktopAuthorize(currentState);
|
||||
|
||||
assert.equal(createdTabUrl, 'https://app.kiro.dev/settings/account');
|
||||
assert.equal(currentState.kiroRuntime.register.email, 'opened@duck.com');
|
||||
assert.equal(completedPayload?.kiroRuntime?.desktopAuth?.clientId, 'opened-client-id');
|
||||
assert.equal(getKiroRuntime(currentState).register.email, 'opened@duck.com');
|
||||
assert.equal(getKiroRuntime(completedPayload).desktopAuth?.clientId, 'opened-client-id');
|
||||
assert.deepEqual(registeredTabs, [
|
||||
{ source: 'kiro-register-page', tabId: 91 },
|
||||
{ source: 'kiro-desktop-authorize', tabId: 92 },
|
||||
@@ -391,31 +407,35 @@ test('executeKiroCompleteDesktopAuthorize finishes from callback page without wa
|
||||
|
||||
await runner.executeKiroCompleteDesktopAuthorize(currentState);
|
||||
|
||||
assert.equal(completedPayload?.kiroRuntime?.desktopAuth?.authorizationCode, 'auth-code-001');
|
||||
assert.equal(completedPayload?.kiroRuntime?.desktopAuth?.refreshToken, 'refresh-token-001');
|
||||
assert.equal(getKiroRuntime(completedPayload).desktopAuth?.authorizationCode, 'auth-code-001');
|
||||
assert.equal(getKiroRuntime(completedPayload).desktopAuth?.refreshToken, 'refresh-token-001');
|
||||
});
|
||||
|
||||
test('executeKiroCompleteDesktopAuthorize waits for callback after consent even if original tab disappears', async () => {
|
||||
const api = loadDesktopAuthorizeRunnerApi();
|
||||
let currentState = createDesktopAuthorizeState({
|
||||
kiroRuntime: {
|
||||
session: {
|
||||
desktopTabId: 91,
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {
|
||||
desktopTabId: 91,
|
||||
},
|
||||
register: {
|
||||
email: 'kiro-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'desktop-client-id',
|
||||
clientSecret: 'desktop-client-secret',
|
||||
state: 'desktop-state-002',
|
||||
codeVerifier: 'desktop-code-verifier',
|
||||
redirectUri: 'http://127.0.0.1:43121/oauth/callback',
|
||||
redirectPort: 43121,
|
||||
authorizeUrl: 'https://example.com/authorize',
|
||||
},
|
||||
upload: {},
|
||||
},
|
||||
},
|
||||
register: {
|
||||
email: 'kiro-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'desktop-client-id',
|
||||
clientSecret: 'desktop-client-secret',
|
||||
state: 'desktop-state-002',
|
||||
codeVerifier: 'desktop-code-verifier',
|
||||
redirectUri: 'http://127.0.0.1:43121/oauth/callback',
|
||||
redirectPort: 43121,
|
||||
authorizeUrl: 'https://example.com/authorize',
|
||||
},
|
||||
upload: {},
|
||||
},
|
||||
});
|
||||
let completedPayload = null;
|
||||
@@ -505,6 +525,6 @@ test('executeKiroCompleteDesktopAuthorize waits for callback after consent even
|
||||
|
||||
await runner.executeKiroCompleteDesktopAuthorize(currentState);
|
||||
|
||||
assert.equal(completedPayload?.kiroRuntime?.desktopAuth?.authorizationCode, 'auth-code-002');
|
||||
assert.equal(completedPayload?.kiroRuntime?.desktopAuth?.refreshToken, 'refresh-token-002');
|
||||
assert.equal(getKiroRuntime(completedPayload).desktopAuth?.authorizationCode, 'auth-code-002');
|
||||
assert.equal(getKiroRuntime(completedPayload).desktopAuth?.refreshToken, 'refresh-token-002');
|
||||
});
|
||||
|
||||
@@ -3,13 +3,17 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
function loadPublisherApi() {
|
||||
const stateSource = fs.readFileSync('background/kiro/state.js', 'utf8');
|
||||
const publisherSource = fs.readFileSync('background/kiro/publisher-kiro-rs.js', 'utf8');
|
||||
const stateSource = fs.readFileSync('flows/kiro/background/state.js', 'utf8');
|
||||
const publisherSource = fs.readFileSync('flows/kiro/background/publisher-kiro-rs.js', 'utf8');
|
||||
const globalScope = {};
|
||||
new Function('self', `${stateSource}; ${publisherSource}; return self;`)(globalScope);
|
||||
return globalScope.MultiPageBackgroundKiroPublisherKiroRs;
|
||||
}
|
||||
|
||||
function getKiroRuntime(state = {}) {
|
||||
return state?.runtimeState?.flowState?.kiro || {};
|
||||
}
|
||||
|
||||
test('kiro publisher exposes a factory and upload payload helpers', () => {
|
||||
const api = loadPublisherApi();
|
||||
assert.equal(typeof api?.createKiroRsPublisher, 'function');
|
||||
@@ -20,7 +24,7 @@ test('kiro publisher exposes a factory and upload payload helpers', () => {
|
||||
test('kiro publisher builds kiro.rs payload from desktop auth runtime with BuilderId profileArn', async () => {
|
||||
const api = loadPublisherApi();
|
||||
const payload = api.buildKiroRsPayload({
|
||||
kiroTargetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
kiroRsUrl: 'https://kiro.example.com/admin',
|
||||
kiroRsKey: 'demo-key',
|
||||
ipProxyEnabled: true,
|
||||
@@ -29,18 +33,22 @@ test('kiro publisher builds kiro.rs payload from desktop auth runtime with Build
|
||||
ipProxyProtocol: 'http',
|
||||
ipProxyUsername: 'proxy-user',
|
||||
ipProxyPassword: 'proxy-pass',
|
||||
kiroRuntime: {
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-token-001',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-token-001',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -69,22 +77,26 @@ test('kiro publisher reads latest kiro.rs key from background state instead of s
|
||||
const api = loadPublisherApi();
|
||||
const requests = [];
|
||||
let liveState = {
|
||||
kiroTargetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
kiroRsUrl: 'https://kiro.example.com/admin',
|
||||
kiroRsKey: 'live-key',
|
||||
email: 'aws-user@example.com',
|
||||
kiroRuntime: {
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-token-001',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-token-001',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
settingsState: {
|
||||
@@ -180,19 +192,23 @@ test('kiro publisher routes step 9 through public contribution upload when contr
|
||||
flowId: 'kiro',
|
||||
accountContributionEnabled: true,
|
||||
contributionAdapterId: 'kiro-builder-id',
|
||||
kiroTargetId: 'kiro-rs',
|
||||
kiroRuntime: {
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-token-001',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
},
|
||||
desktopAuth: {
|
||||
region: 'us-east-1',
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-token-001',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -224,10 +240,10 @@ test('kiro publisher routes step 9 through public contribution upload when contr
|
||||
assert.equal(requests.length, 0);
|
||||
assert.equal(completed.length, 1);
|
||||
assert.equal(completed[0].nodeId, 'kiro-upload-credential');
|
||||
assert.equal(completed[0].payload.kiroRuntime.upload.targetId, 'contribution');
|
||||
assert.equal(completed[0].payload.kiroRuntime.upload.status, 'uploaded');
|
||||
assert.equal(completed[0].payload.kiroRuntime.upload.credentialId, 'kiro-contribution-009');
|
||||
assert.equal(completed[0].payload.kiroRuntime.upload.lastMessage, '贡献链路成功:kiro-step-9');
|
||||
assert.equal(getKiroRuntime(completed[0].payload).upload.targetId, 'contribution');
|
||||
assert.equal(getKiroRuntime(completed[0].payload).upload.status, 'uploaded');
|
||||
assert.equal(getKiroRuntime(completed[0].payload).upload.credentialId, 'kiro-contribution-009');
|
||||
assert.equal(getKiroRuntime(completed[0].payload).upload.lastMessage, '贡献链路成功:kiro-step-9');
|
||||
});
|
||||
|
||||
test('kiro publisher trims api key and includes fallback Authorization header during connection check', async () => {
|
||||
|
||||
@@ -3,13 +3,17 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
function loadRegisterRunnerApi() {
|
||||
const stateSource = fs.readFileSync('background/kiro/state.js', 'utf8');
|
||||
const runnerSource = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
|
||||
const stateSource = fs.readFileSync('flows/kiro/background/state.js', 'utf8');
|
||||
const runnerSource = fs.readFileSync('flows/kiro/background/register-runner.js', 'utf8');
|
||||
const globalScope = {};
|
||||
new Function('self', `${stateSource}; ${runnerSource}; return self;`)(globalScope);
|
||||
return globalScope.MultiPageBackgroundKiroRegisterRunner;
|
||||
}
|
||||
|
||||
function getKiroRuntime(state = {}) {
|
||||
return state?.runtimeState?.flowState?.kiro || {};
|
||||
}
|
||||
|
||||
test('kiro register runner module exposes a factory and Kiro official sign-in entry', () => {
|
||||
const api = loadRegisterRunnerApi();
|
||||
assert.equal(typeof api?.createKiroRegisterRunner, 'function');
|
||||
@@ -17,7 +21,7 @@ test('kiro register runner module exposes a factory and Kiro official sign-in en
|
||||
});
|
||||
|
||||
test('kiro register runner removed the old AWS device authorization bootstrap', () => {
|
||||
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/register-runner.js', 'utf8');
|
||||
assert.doesNotMatch(source, /startBuilderIdDeviceLogin/);
|
||||
assert.doesNotMatch(source, /device_authorization/);
|
||||
assert.doesNotMatch(source, /verificationUriComplete/);
|
||||
@@ -25,7 +29,7 @@ test('kiro register runner removed the old AWS device authorization bootstrap',
|
||||
});
|
||||
|
||||
test('kiro register runner uses a shared 3-minute page-load timeout budget', () => {
|
||||
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/register-runner.js', 'utf8');
|
||||
assert.match(source, /DEFAULT_KIRO_PAGE_LOAD_TIMEOUT_MS/);
|
||||
assert.match(source, /createTimeoutBudget/);
|
||||
assert.match(source, /resolveTimeoutBudget/);
|
||||
@@ -34,7 +38,7 @@ test('kiro register runner uses a shared 3-minute page-load timeout budget', ()
|
||||
});
|
||||
|
||||
test('kiro register consent step treats Kiro Web signed-in page as completion', () => {
|
||||
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/register-runner.js', 'utf8');
|
||||
assert.match(source, /readKiroRegisterPageState\(tabId, \{/);
|
||||
assert.match(source, /\['authorization_page', 'success_page', 'kiro_web_signed_in'\]\.includes\(landingResult\?\.state\)/);
|
||||
assert.match(source, /landingResult\?\.state === 'authorization_page'/);
|
||||
@@ -42,7 +46,7 @@ test('kiro register consent step treats Kiro Web signed-in page as completion',
|
||||
});
|
||||
|
||||
test('kiro register runner uses registration-only page states instead of shared OpenAI names', () => {
|
||||
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/register-runner.js', 'utf8');
|
||||
assert.match(source, /KIRO_REGISTER_PAGE_STATES/);
|
||||
assert.match(source, /'register_otp_page'/);
|
||||
assert.match(source, /'create_password_page'/);
|
||||
@@ -54,7 +58,7 @@ test('kiro register runner uses registration-only page states instead of shared
|
||||
});
|
||||
|
||||
test('kiro register runner fails existing-account login branches during registration', () => {
|
||||
const source = fs.readFileSync('background/kiro/register-runner.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/register-runner.js', 'utf8');
|
||||
assert.match(source, /KIRO_REGISTER_EXISTING_ACCOUNT_STATES/);
|
||||
assert.match(source, /assertKiroRegistrationOnlyState\(landingResult, currentState, 2, resolvedEmail\)/);
|
||||
assert.match(source, /邮箱.*已进入 AWS Builder ID 登录页/);
|
||||
@@ -64,12 +68,16 @@ test('kiro register runner fails existing-account login branches during registra
|
||||
test('kiro submit-email stops immediately when AWS routes the email to login', async () => {
|
||||
const api = loadRegisterRunnerApi();
|
||||
const currentState = {
|
||||
kiroRuntime: {
|
||||
session: {
|
||||
registerTabId: 101,
|
||||
},
|
||||
register: {
|
||||
loginUrl: 'https://app.kiro.dev/signin',
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {
|
||||
registerTabId: 101,
|
||||
},
|
||||
register: {
|
||||
loginUrl: 'https://app.kiro.dev/signin',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -119,18 +127,22 @@ test('kiro submit-email stops immediately when AWS routes the email to login', a
|
||||
|
||||
assert.equal(completed, false);
|
||||
assert.equal(sentMessages.some((message) => message.type === 'EXECUTE_NODE'), true);
|
||||
assert.equal(statePatches.some((patch) => /已进入 AWS Builder ID 登录页/.test(patch.kiroRuntime?.session?.lastError || '')), true);
|
||||
assert.equal(statePatches.some((patch) => /已进入 AWS Builder ID 登录页/.test(getKiroRuntime(patch).session?.lastError || '')), true);
|
||||
});
|
||||
|
||||
test('kiro submit-email can adopt an already-open registration OTP page without allocating a new mailbox', async () => {
|
||||
const api = loadRegisterRunnerApi();
|
||||
const currentState = {
|
||||
kiroRuntime: {
|
||||
session: {
|
||||
registerTabId: 102,
|
||||
},
|
||||
register: {
|
||||
loginUrl: 'https://app.kiro.dev/signin',
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {
|
||||
registerTabId: 102,
|
||||
},
|
||||
register: {
|
||||
loginUrl: 'https://app.kiro.dev/signin',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -163,8 +175,8 @@ test('kiro submit-email can adopt an already-open registration OTP page without
|
||||
|
||||
await runner.executeKiroSubmitEmail({ nodeId: 'kiro-submit-email', ...currentState });
|
||||
|
||||
assert.equal(completedPayload?.kiroRuntime?.register?.email, 'manual-user@duck.com');
|
||||
assert.equal(completedPayload?.kiroRuntime?.register?.status, 'waiting_otp');
|
||||
assert.equal(completedPayload?.kiroRuntime?.register?.verificationRequestedAt, 0);
|
||||
assert.equal(getKiroRuntime(completedPayload).register?.email, 'manual-user@duck.com');
|
||||
assert.equal(getKiroRuntime(completedPayload).register?.status, 'waiting_otp');
|
||||
assert.equal(getKiroRuntime(completedPayload).register?.verificationRequestedAt, 0);
|
||||
assert.equal(sentMessages.some((message) => message.type === 'EXECUTE_NODE'), false);
|
||||
});
|
||||
|
||||
@@ -3,109 +3,128 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
function loadKiroStateApi() {
|
||||
const source = fs.readFileSync('background/kiro/state.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/kiro/background/state.js', 'utf8');
|
||||
const globalScope = {};
|
||||
return new Function('self', `${source}; return self.MultiPageBackgroundKiroState;`)(globalScope);
|
||||
}
|
||||
|
||||
test('background imports kiro state module and routes Kiro runtime through dedicated helpers', () => {
|
||||
function getKiroRuntime(state = {}) {
|
||||
return state?.runtimeState?.flowState?.kiro || {};
|
||||
}
|
||||
|
||||
test('background imports kiro state module for Kiro runtime projection and reset helpers', () => {
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
assert.match(source, /background\/kiro\/state\.js/);
|
||||
assert.match(source, /flows\/kiro\/background\/state\.js/);
|
||||
assert.match(source, /const kiroStateHelpers = self\.MultiPageBackgroundKiroState/);
|
||||
assert.match(source, /kiroStateHelpers\?\.buildStateView/);
|
||||
assert.match(source, /kiroStateHelpers\?\.buildSessionStatePatch/);
|
||||
assert.match(source, /kiroStateHelpers\?\.buildDownstreamResetPatch/);
|
||||
assert.match(source, /kiroStateHelpers\?\.applyNodeCompletionPayload/);
|
||||
assert.doesNotMatch(source, /migrateLegacyKiroRuntimeState/);
|
||||
assert.equal(/kiroStateHelpers\?\.buildSessionStatePatch/.test(source), false);
|
||||
assert.equal(/kiroRuntime:\s*kiroStateHelpers\?\.buildDefaultRuntimeState/.test(source), false);
|
||||
});
|
||||
|
||||
test('kiro state module exposes canonical nested kiroRuntime view', () => {
|
||||
test('kiro state module exposes canonical nested runtimeState view', () => {
|
||||
const api = loadKiroStateApi();
|
||||
const view = api.buildStateView({
|
||||
kiroTargetId: 'kiro-rs',
|
||||
kiroRuntime: {
|
||||
session: {
|
||||
currentStage: 'desktop-authorize',
|
||||
registerTabId: 88,
|
||||
pageState: 'name_entry',
|
||||
pageUrl: 'https://view.awsapps.com/start',
|
||||
},
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
fullName: 'Ada Lovelace',
|
||||
loginUrl: 'https://app.kiro.dev/signin',
|
||||
status: 'waiting_name',
|
||||
},
|
||||
webAuth: {
|
||||
status: 'signin_started',
|
||||
hasAccessToken: false,
|
||||
hasSessionToken: false,
|
||||
},
|
||||
desktopAuth: {
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-001',
|
||||
status: 'authorized',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
status: 'ready_to_upload',
|
||||
credentialId: 321,
|
||||
},
|
||||
const runtimeState = api.buildRuntimeStatePatch({}, {
|
||||
session: {
|
||||
currentStage: 'desktop-authorize',
|
||||
registerTabId: 88,
|
||||
pageState: 'name_entry',
|
||||
pageUrl: 'https://view.awsapps.com/start',
|
||||
},
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
fullName: 'Ada Lovelace',
|
||||
loginUrl: 'https://app.kiro.dev/signin',
|
||||
status: 'waiting_name',
|
||||
},
|
||||
webAuth: {
|
||||
status: 'signin_started',
|
||||
hasAccessToken: false,
|
||||
hasSessionToken: false,
|
||||
},
|
||||
desktopAuth: {
|
||||
clientId: 'client-001',
|
||||
clientSecret: 'secret-001',
|
||||
refreshToken: 'refresh-001',
|
||||
status: 'authorized',
|
||||
},
|
||||
upload: {
|
||||
targetId: 'kiro-rs',
|
||||
status: 'ready_to_upload',
|
||||
credentialId: 321,
|
||||
},
|
||||
}).runtimeState;
|
||||
const view = api.buildStateView({
|
||||
targetId: 'kiro-rs',
|
||||
runtimeState,
|
||||
});
|
||||
|
||||
assert.equal(view.kiroTargetId, 'kiro-rs');
|
||||
assert.equal(view.kiroRuntime.session.currentStage, 'desktop-authorize');
|
||||
assert.equal(view.kiroRuntime.session.registerTabId, 88);
|
||||
assert.equal(view.kiroRuntime.register.email, 'aws-user@example.com');
|
||||
assert.equal(view.kiroRuntime.register.loginUrl, 'https://app.kiro.dev/signin');
|
||||
assert.equal(view.kiroRuntime.webAuth.status, 'signin_started');
|
||||
assert.equal(view.kiroRuntime.desktopAuth.clientId, 'client-001');
|
||||
assert.equal(view.kiroRuntime.desktopAuth.refreshToken, 'refresh-001');
|
||||
assert.equal(view.kiroRuntime.upload.status, 'ready_to_upload');
|
||||
assert.equal(view.kiroRuntime.upload.credentialId, 321);
|
||||
assert.equal(view.targetId, 'kiro-rs');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(view, 'kiroRuntime'), false);
|
||||
assert.equal(getKiroRuntime(view).session.currentStage, 'desktop-authorize');
|
||||
assert.equal(getKiroRuntime(view).session.registerTabId, 88);
|
||||
assert.equal(getKiroRuntime(view).register.email, 'aws-user@example.com');
|
||||
assert.equal(getKiroRuntime(view).register.loginUrl, 'https://app.kiro.dev/signin');
|
||||
assert.equal(getKiroRuntime(view).webAuth.status, 'signin_started');
|
||||
assert.equal(getKiroRuntime(view).desktopAuth.clientId, 'client-001');
|
||||
assert.equal(getKiroRuntime(view).desktopAuth.refreshToken, 'refresh-001');
|
||||
assert.equal(getKiroRuntime(view).upload.status, 'ready_to_upload');
|
||||
assert.equal(getKiroRuntime(view).upload.credentialId, 321);
|
||||
assert.equal(view.runtimeState.flowState.kiro.session.currentStage, 'desktop-authorize');
|
||||
assert.equal(view.runtimeState.flowState.kiro.register.email, 'aws-user@example.com');
|
||||
assert.equal(view.runtimeState.flowState.kiro.upload.credentialId, 321);
|
||||
});
|
||||
|
||||
test('kiro state session patch accepts canonical nested runtime updates', () => {
|
||||
const api = loadKiroStateApi();
|
||||
const patch = api.buildSessionStatePatch({
|
||||
kiroRuntime: api.buildDefaultRuntimeState(),
|
||||
runtimeState: api.buildRuntimeStatePatch({}, api.buildDefaultRuntimeState()).runtimeState,
|
||||
}, {
|
||||
kiroRuntime: {
|
||||
session: {
|
||||
currentStage: 'register',
|
||||
pageState: 'register_otp_page',
|
||||
pageUrl: 'https://signin.aws/register',
|
||||
},
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
fullName: 'Ada Lovelace',
|
||||
verificationRequestedAt: 1700000000000,
|
||||
},
|
||||
desktopAuth: {
|
||||
status: 'waiting_callback',
|
||||
},
|
||||
upload: {
|
||||
status: 'waiting_register',
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {
|
||||
currentStage: 'register',
|
||||
pageState: 'register_otp_page',
|
||||
pageUrl: 'https://signin.aws/register',
|
||||
},
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
fullName: 'Ada Lovelace',
|
||||
verificationRequestedAt: 1700000000000,
|
||||
},
|
||||
desktopAuth: {
|
||||
status: 'waiting_callback',
|
||||
},
|
||||
upload: {
|
||||
status: 'waiting_register',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(patch.kiroRuntime.session.currentStage, 'register');
|
||||
assert.equal(patch.kiroRuntime.session.pageState, 'register_otp_page');
|
||||
assert.equal(patch.kiroRuntime.session.pageUrl, 'https://signin.aws/register');
|
||||
assert.equal(patch.kiroRuntime.register.email, 'aws-user@example.com');
|
||||
assert.equal(patch.kiroRuntime.register.fullName, 'Ada Lovelace');
|
||||
assert.equal(patch.kiroRuntime.register.verificationRequestedAt, 1700000000000);
|
||||
assert.equal(patch.kiroRuntime.desktopAuth.status, 'waiting_callback');
|
||||
assert.equal(patch.kiroRuntime.upload.status, 'waiting_register');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'kiroRuntime'), false);
|
||||
assert.equal(getKiroRuntime(patch).session.currentStage, 'register');
|
||||
assert.equal(getKiroRuntime(patch).session.pageState, 'register_otp_page');
|
||||
assert.equal(getKiroRuntime(patch).session.pageUrl, 'https://signin.aws/register');
|
||||
assert.equal(getKiroRuntime(patch).register.email, 'aws-user@example.com');
|
||||
assert.equal(getKiroRuntime(patch).register.fullName, 'Ada Lovelace');
|
||||
assert.equal(getKiroRuntime(patch).register.verificationRequestedAt, 1700000000000);
|
||||
assert.equal(getKiroRuntime(patch).desktopAuth.status, 'waiting_callback');
|
||||
assert.equal(getKiroRuntime(patch).upload.status, 'waiting_register');
|
||||
assert.equal(patch.runtimeState.flowState.kiro.session.currentStage, 'register');
|
||||
assert.equal(patch.runtimeState.flowState.kiro.register.email, 'aws-user@example.com');
|
||||
assert.equal(patch.runtimeState.flowState.kiro.desktopAuth.status, 'waiting_callback');
|
||||
});
|
||||
|
||||
test('kiro state reset helpers clear downstream runtime and fresh keep-state preserves only target selection', () => {
|
||||
const api = loadKiroStateApi();
|
||||
const currentState = {
|
||||
kiroTargetId: 'kiro-rs',
|
||||
kiroRuntime: {
|
||||
targetId: 'kiro-rs',
|
||||
runtimeState: api.buildRuntimeStatePatch({}, {
|
||||
session: {
|
||||
currentStage: 'upload',
|
||||
registerTabId: 88,
|
||||
@@ -126,21 +145,26 @@ test('kiro state reset helpers clear downstream runtime and fresh keep-state pre
|
||||
status: 'uploaded',
|
||||
credentialId: 321,
|
||||
},
|
||||
},
|
||||
}).runtimeState,
|
||||
};
|
||||
|
||||
const resetPatch = api.buildDownstreamResetPatch('kiro-submit-email', currentState);
|
||||
assert.equal(resetPatch.kiroRuntime.session.currentStage, 'register');
|
||||
assert.equal(resetPatch.kiroRuntime.register.email, '');
|
||||
assert.equal(resetPatch.kiroRuntime.register.fullName, '');
|
||||
assert.equal(resetPatch.kiroRuntime.desktopAuth.refreshToken, '');
|
||||
assert.equal(resetPatch.kiroRuntime.upload.status, '');
|
||||
assert.equal(resetPatch.kiroRuntime.upload.credentialId, null);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(resetPatch, 'kiroRuntime'), false);
|
||||
assert.equal(getKiroRuntime(resetPatch).session.currentStage, 'register');
|
||||
assert.equal(getKiroRuntime(resetPatch).register.email, '');
|
||||
assert.equal(getKiroRuntime(resetPatch).register.fullName, '');
|
||||
assert.equal(getKiroRuntime(resetPatch).desktopAuth.refreshToken, '');
|
||||
assert.equal(getKiroRuntime(resetPatch).upload.status, '');
|
||||
assert.equal(getKiroRuntime(resetPatch).upload.credentialId, null);
|
||||
assert.equal(resetPatch.runtimeState.flowState.kiro.register.email, '');
|
||||
assert.equal(resetPatch.runtimeState.flowState.kiro.desktopAuth.refreshToken, '');
|
||||
|
||||
const keepState = api.buildFreshKeepState(currentState);
|
||||
assert.equal(keepState.kiroTargetId, 'kiro-rs');
|
||||
assert.equal(keepState.kiroRuntime.register.email, '');
|
||||
assert.equal(keepState.kiroRuntime.desktopAuth.refreshToken, '');
|
||||
assert.equal(keepState.kiroRuntime.upload.status, '');
|
||||
assert.equal(keepState.kiroRuntime.upload.targetId, 'kiro-rs');
|
||||
assert.equal(keepState.targetId, 'kiro-rs');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(keepState, 'kiroRuntime'), false);
|
||||
assert.equal(getKiroRuntime(keepState).register.email, '');
|
||||
assert.equal(getKiroRuntime(keepState).desktopAuth.refreshToken, '');
|
||||
assert.equal(getKiroRuntime(keepState).upload.status, '');
|
||||
assert.equal(getKiroRuntime(keepState).upload.targetId, 'kiro-rs');
|
||||
assert.equal(keepState.runtimeState.flowState.kiro.upload.targetId, 'kiro-rs');
|
||||
});
|
||||
|
||||
@@ -4,11 +4,11 @@ const fs = require('node:fs');
|
||||
|
||||
test('background imports logging/status module', () => {
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
assert.match(source, /background\/logging-status\.js/);
|
||||
assert.match(source, /core\/flow-kernel\/logging-status\.js/);
|
||||
});
|
||||
|
||||
test('logging/status module exposes a factory', () => {
|
||||
const source = fs.readFileSync('background/logging-status.js', 'utf8');
|
||||
const source = fs.readFileSync('core/flow-kernel/logging-status.js', 'utf8');
|
||||
const globalScope = {};
|
||||
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundLoggingStatus;`)(globalScope);
|
||||
@@ -17,7 +17,7 @@ test('logging/status module exposes a factory', () => {
|
||||
});
|
||||
|
||||
test('logging/status add-phone detection ignores step 2 phone-entry switch failures', () => {
|
||||
const source = fs.readFileSync('background/logging-status.js', 'utf8');
|
||||
const source = fs.readFileSync('core/flow-kernel/logging-status.js', 'utf8');
|
||||
const globalScope = {};
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundLoggingStatus;`)(globalScope);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ test('signup flow helper allocates mail2925 account before generating alias emai
|
||||
calls.setEmail.push(email);
|
||||
},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async () => null,
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ test('signup flow helper skips mail2925 account allocation when account pool swi
|
||||
sendToContentScriptResilient: async () => ({}),
|
||||
setEmailState: async () => {},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async () => null,
|
||||
});
|
||||
|
||||
|
||||
@@ -459,7 +459,7 @@ test('SAVE_SETTING rebuilds Plus node statuses when panel mode forces the effect
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||
const broadcasts = [];
|
||||
let state = {
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
plusModeEnabled: true,
|
||||
plusPaymentMethod: 'paypal',
|
||||
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||
@@ -486,12 +486,12 @@ test('SAVE_SETTING rebuilds Plus node statuses when panel mode forces the effect
|
||||
const router = api.createMessageRouter({
|
||||
addLog: async () => {},
|
||||
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||
buildPersistentSettingsPayload: (input = {}) => Object.prototype.hasOwnProperty.call(input, 'panelMode')
|
||||
? { panelMode: input.panelMode }
|
||||
buildPersistentSettingsPayload: (input = {}) => Object.prototype.hasOwnProperty.call(input, 'targetId')
|
||||
? { targetId: input.targetId }
|
||||
: {},
|
||||
broadcastDataUpdate: (payload) => broadcasts.push(payload),
|
||||
getNodeIdsForState: (nextState = {}) => (
|
||||
String(nextState.panelMode || '').trim() === 'sub2api'
|
||||
String(nextState.targetId || '').trim() === 'sub2api'
|
||||
&& String(nextState.plusAccountAccessStrategy || '').trim() === 'sub2api_codex_session'
|
||||
? [
|
||||
'open-chatgpt',
|
||||
@@ -525,12 +525,12 @@ test('SAVE_SETTING rebuilds Plus node statuses when panel mode forces the effect
|
||||
const response = await router.handleMessage({
|
||||
type: 'SAVE_SETTING',
|
||||
payload: {
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(response.ok, true);
|
||||
assert.equal(state.panelMode, 'cpa');
|
||||
assert.equal(state.targetId, 'cpa');
|
||||
assert.equal(state.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||
assert.equal(state.currentNodeId, '');
|
||||
assert.equal(state.oauthUrl, null);
|
||||
@@ -552,7 +552,7 @@ test('SAVE_SETTING rebuilds Plus node statuses when panel mode forces the effect
|
||||
});
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(state.nodeStatuses, 'sub2api-session-import'), false);
|
||||
assert.deepStrictEqual(broadcasts.at(-1), {
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
signupMethod: 'email',
|
||||
oauthUrl: null,
|
||||
localhostUrl: null,
|
||||
@@ -595,7 +595,7 @@ test('SAVE_SETTING mirrors activeFlowId into flowId when switching to kiro flow'
|
||||
const globalScope = { console };
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||
const broadcasts = [];
|
||||
let state = { activeFlowId: 'openai', flowId: 'openai', panelMode: 'cpa', plusModeEnabled: false, plusPaymentMethod: 'paypal' };
|
||||
let state = { activeFlowId: 'openai', flowId: 'openai', targetId: 'cpa', plusModeEnabled: false, plusPaymentMethod: 'paypal' };
|
||||
|
||||
const router = api.createMessageRouter({
|
||||
addLog: async () => {},
|
||||
@@ -683,7 +683,7 @@ test('SAVE_SETTING syncs canonical kiro settingsState back into session state',
|
||||
let state = {
|
||||
activeFlowId: 'kiro',
|
||||
flowId: 'kiro',
|
||||
kiroTargetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
kiroRsUrl: 'https://kiro.example.com/admin',
|
||||
kiroRsKey: '',
|
||||
settingsSchemaVersion: 4,
|
||||
@@ -718,7 +718,7 @@ test('SAVE_SETTING syncs canonical kiro settingsState back into session state',
|
||||
setPersistentSettings: async () => ({
|
||||
activeFlowId: 'kiro',
|
||||
flowId: 'kiro',
|
||||
kiroTargetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
kiroRsUrl: 'https://kiro.example.com/admin',
|
||||
kiroRsKey: 'live-key',
|
||||
settingsSchemaVersion: 4,
|
||||
@@ -751,7 +751,7 @@ test('CHECK_KIRO_RS_CONNECTION prefers current sidepanel payload over stale save
|
||||
getState: async () => ({
|
||||
activeFlowId: 'kiro',
|
||||
flowId: 'kiro',
|
||||
kiroTargetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
kiroRsUrl: 'https://old.example.com/admin',
|
||||
kiroRsKey: 'old-key',
|
||||
settingsState: {
|
||||
@@ -808,7 +808,7 @@ test('AUTO_RUN applies current flow selection from payload before starting loop'
|
||||
let state = {
|
||||
activeFlowId: 'openai',
|
||||
flowId: 'openai',
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
plusModeEnabled: false,
|
||||
plusPaymentMethod: 'paypal',
|
||||
};
|
||||
@@ -829,7 +829,7 @@ test('AUTO_RUN applies current flow selection from payload before starting loop'
|
||||
validations.push({
|
||||
activeFlowId: validationState?.activeFlowId,
|
||||
flowId: validationState?.flowId,
|
||||
kiroTargetId: validationState?.kiroTargetId,
|
||||
targetId: validationState?.targetId,
|
||||
optionActiveFlowId: options?.activeFlowId,
|
||||
});
|
||||
return { ok: true, errors: [] };
|
||||
@@ -848,14 +848,14 @@ test('AUTO_RUN applies current flow selection from payload before starting loop'
|
||||
assert.equal(response.ok, true);
|
||||
assert.equal(state.activeFlowId, 'kiro');
|
||||
assert.equal(state.flowId, 'kiro');
|
||||
assert.equal(state.kiroTargetId, 'kiro-rs');
|
||||
assert.equal(state.targetId, 'kiro-rs');
|
||||
assert.deepStrictEqual(calls, [
|
||||
{
|
||||
type: 'setState',
|
||||
updates: {
|
||||
activeFlowId: 'kiro',
|
||||
flowId: 'kiro',
|
||||
kiroTargetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -877,7 +877,7 @@ test('AUTO_RUN applies current flow selection from payload before starting loop'
|
||||
{
|
||||
activeFlowId: 'kiro',
|
||||
flowId: 'kiro',
|
||||
kiroTargetId: 'kiro-rs',
|
||||
targetId: 'kiro-rs',
|
||||
optionActiveFlowId: 'kiro',
|
||||
},
|
||||
]);
|
||||
@@ -891,18 +891,18 @@ test('SAVE_SETTING re-resolves signup method when panel mode changes', async ()
|
||||
signupMethod: 'phone',
|
||||
phoneVerificationEnabled: true,
|
||||
plusModeEnabled: false,
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
};
|
||||
|
||||
const router = api.createMessageRouter({
|
||||
addLog: async () => {},
|
||||
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||
buildPersistentSettingsPayload: (input = {}) => Object.prototype.hasOwnProperty.call(input, 'panelMode')
|
||||
? { panelMode: input.panelMode }
|
||||
buildPersistentSettingsPayload: (input = {}) => Object.prototype.hasOwnProperty.call(input, 'targetId')
|
||||
? { targetId: input.targetId }
|
||||
: {},
|
||||
broadcastDataUpdate: () => {},
|
||||
getState: async () => ({ ...state }),
|
||||
resolveSignupMethod: (nextState = {}) => nextState.panelMode === 'cpa' ? 'email' : 'phone',
|
||||
resolveSignupMethod: (nextState = {}) => nextState.targetId === 'cpa' ? 'email' : 'phone',
|
||||
setPersistentSettings: async (updates) => ({ ...updates }),
|
||||
setState: async (updates) => {
|
||||
state = { ...state, ...updates };
|
||||
@@ -911,11 +911,11 @@ test('SAVE_SETTING re-resolves signup method when panel mode changes', async ()
|
||||
|
||||
const response = await router.handleMessage({
|
||||
type: 'SAVE_SETTING',
|
||||
payload: { panelMode: 'cpa' },
|
||||
payload: { targetId: 'cpa' },
|
||||
});
|
||||
|
||||
assert.equal(response.ok, true);
|
||||
assert.equal(state.panelMode, 'cpa');
|
||||
assert.equal(state.targetId, 'cpa');
|
||||
assert.equal(state.signupMethod, 'email');
|
||||
});
|
||||
|
||||
@@ -929,7 +929,7 @@ test('SAVE_SETTING applies shared mode-switch normalization before persisting in
|
||||
signupMethod: 'email',
|
||||
phoneVerificationEnabled: false,
|
||||
plusModeEnabled: false,
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
};
|
||||
|
||||
const router = api.createMessageRouter({
|
||||
|
||||
@@ -426,7 +426,7 @@ test('message router finalizes step 3 before marking it completed', async () =>
|
||||
const response = await router.handleMessage({
|
||||
type: 'NODE_COMPLETE',
|
||||
nodeId: 'fill-password',
|
||||
source: 'signup-page',
|
||||
source: 'openai-auth',
|
||||
payload: {
|
||||
nodeId: 'fill-password',
|
||||
email: 'user@example.com',
|
||||
@@ -548,7 +548,7 @@ test('message router marks step 3 failed when post-submit finalize fails', async
|
||||
const response = await router.handleMessage({
|
||||
type: 'NODE_COMPLETE',
|
||||
nodeId: 'fill-password',
|
||||
source: 'signup-page',
|
||||
source: 'openai-auth',
|
||||
payload: {
|
||||
nodeId: 'fill-password',
|
||||
email: 'user@example.com',
|
||||
@@ -581,7 +581,7 @@ test('message router does not duplicate step 3 mismatch failure log after finali
|
||||
const response = await router.handleMessage({
|
||||
type: 'NODE_ERROR',
|
||||
nodeId: 'fill-password',
|
||||
source: 'signup-page',
|
||||
source: 'openai-auth',
|
||||
payload: { nodeId: 'fill-password' },
|
||||
error: mismatchError,
|
||||
}, {});
|
||||
@@ -604,7 +604,7 @@ test('message router stops the flow and surfaces cloudflare security block error
|
||||
const response = await router.handleMessage({
|
||||
type: 'NODE_ERROR',
|
||||
nodeId: 'oauth-login',
|
||||
source: 'signup-page',
|
||||
source: 'openai-auth',
|
||||
payload: { nodeId: 'oauth-login' },
|
||||
error: 'CF_SECURITY_BLOCKED::您已触发Cloudflare 安全防护系统',
|
||||
}, {});
|
||||
|
||||
@@ -68,7 +68,7 @@ test('navigation utils support codex2api mode and url normalization', () => {
|
||||
utils.normalizeCodex2ApiUrl('https://codex-admin.example.com/'),
|
||||
'https://codex-admin.example.com/admin/accounts'
|
||||
);
|
||||
assert.equal(utils.getPanelMode({ panelMode: 'codex2api' }), 'codex2api');
|
||||
assert.equal(utils.getPanelMode({ targetId: 'codex2api' }), 'codex2api');
|
||||
assert.equal(utils.getPanelModeLabel('codex2api'), 'Codex2API');
|
||||
});
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ const fs = require('node:fs');
|
||||
|
||||
test('confirm-oauth and platform-verify stay free of operation delay gate calls', () => {
|
||||
for (const file of [
|
||||
'background/steps/confirm-oauth.js',
|
||||
'background/steps/platform-verify.js',
|
||||
'flows/openai/background/steps/confirm-oauth.js',
|
||||
'flows/openai/background/steps/platform-verify.js',
|
||||
'background/panel-bridge.js',
|
||||
'content/sub2api-panel.js',
|
||||
'flows/openai/content/sub2api-panel.js',
|
||||
]) {
|
||||
const source = fs.readFileSync(file, 'utf8');
|
||||
assert.doesNotMatch(source, /performOperationWithDelay\(/, `${file} must not call the operation delay gate`);
|
||||
|
||||
@@ -3,7 +3,7 @@ const fs = require('node:fs');
|
||||
const test = require('node:test');
|
||||
|
||||
test('platform verify module supports codex2api protocol callback exchange', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (url, options = {}) => {
|
||||
assert.equal(url, 'http://localhost:8080/api/admin/oauth/exchange-code');
|
||||
@@ -81,7 +81,7 @@ test('platform verify module supports codex2api protocol callback exchange', asy
|
||||
});
|
||||
|
||||
test('platform verify retries transient SUB2API oauth/token exchange errors before succeeding', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep10;`)({});
|
||||
|
||||
const logs = [];
|
||||
@@ -150,7 +150,7 @@ test('platform verify retries transient SUB2API oauth/token exchange errors befo
|
||||
});
|
||||
|
||||
test('platform verify retries transient SUB2API token_exchange_user_error before succeeding', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStep10;`)({});
|
||||
|
||||
const logs = [];
|
||||
|
||||
@@ -44,7 +44,7 @@ function createDeps(overrides = {}) {
|
||||
|
||||
function loadStep10WithSub2Api() {
|
||||
const sub2apiSource = fs.readFileSync('background/sub2api-api.js', 'utf8');
|
||||
const step10Source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const step10Source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
return new Function('self', `${sub2apiSource}\n${step10Source}; return self.MultiPageBackgroundStep10;`)({});
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ function createSub2ApiResponse(payload, status = 200) {
|
||||
}
|
||||
|
||||
test('platform verify module submits CPA callback via management API first', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const originalFetch = globalThis.fetch;
|
||||
let uiCalled = false;
|
||||
globalThis.fetch = async (url, options = {}) => {
|
||||
@@ -114,7 +114,7 @@ test('platform verify module submits CPA callback via management API first', asy
|
||||
});
|
||||
|
||||
test('platform verify module prefers cpaManagementOrigin when provided', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (url, options = {}) => {
|
||||
assert.equal(url, 'http://localhost:9999/v0/management/oauth-callback');
|
||||
@@ -149,7 +149,7 @@ test('platform verify module prefers cpaManagementOrigin when provided', async (
|
||||
});
|
||||
|
||||
test('platform verify module fails fast when CPA API submit fails', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const originalFetch = globalThis.fetch;
|
||||
globalThis.fetch = async () => ({
|
||||
ok: false,
|
||||
@@ -185,7 +185,7 @@ test('platform verify module fails fast when CPA API submit fails', async () =>
|
||||
});
|
||||
|
||||
test('platform verify module requires management key for CPA API-only flow', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const originalFetch = globalThis.fetch;
|
||||
let fetchCalled = false;
|
||||
globalThis.fetch = async () => {
|
||||
@@ -221,7 +221,7 @@ test('platform verify module requires management key for CPA API-only flow', asy
|
||||
});
|
||||
|
||||
test('platform verify module rejects callback when cpa oauth state mismatches', async () => {
|
||||
const source = fs.readFileSync('background/steps/platform-verify.js', 'utf8');
|
||||
const source = fs.readFileSync('flows/openai/background/steps/platform-verify.js', 'utf8');
|
||||
const originalFetch = globalThis.fetch;
|
||||
let fetchCalled = false;
|
||||
globalThis.fetch = async () => {
|
||||
|
||||
@@ -3,14 +3,14 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
function loadRuntimeStateApi() {
|
||||
const source = fs.readFileSync('background/runtime-state.js', 'utf8');
|
||||
const source = fs.readFileSync('core/flow-kernel/runtime-state.js', 'utf8');
|
||||
const globalScope = {};
|
||||
return new Function('self', `${source}; return self.MultiPageBackgroundRuntimeState;`)(globalScope);
|
||||
}
|
||||
|
||||
test('background imports runtime-state module and wires state view helpers', () => {
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
assert.match(source, /background\/runtime-state\.js/);
|
||||
assert.match(source, /core\/flow-kernel\/runtime-state\.js/);
|
||||
assert.match(source, /createRuntimeStateHelpers/);
|
||||
assert.match(source, /buildStateViewWithRuntimeState/);
|
||||
assert.match(source, /buildStatePatchWithRuntimeState/);
|
||||
@@ -46,10 +46,10 @@ test('runtime-state view preserves canonical flow metadata from node state', ()
|
||||
phoneNumber: '+447700900123',
|
||||
},
|
||||
tabRegistry: {
|
||||
'signup-page': { tabId: 12 },
|
||||
'openai-auth': { tabId: 12 },
|
||||
},
|
||||
sourceLastUrls: {
|
||||
'signup-page': 'https://auth.example.com/start',
|
||||
'openai-auth': 'https://auth.example.com/start',
|
||||
},
|
||||
flowStartTime: 12345,
|
||||
});
|
||||
@@ -72,10 +72,10 @@ test('runtime-state view preserves canonical flow metadata from node state', ()
|
||||
});
|
||||
assert.deepStrictEqual(view.sharedState, {
|
||||
tabRegistry: {
|
||||
'signup-page': { tabId: 12 },
|
||||
'openai-auth': { tabId: 12 },
|
||||
},
|
||||
sourceLastUrls: {
|
||||
'signup-page': 'https://auth.example.com/start',
|
||||
'openai-auth': 'https://auth.example.com/start',
|
||||
},
|
||||
flowStartTime: 12345,
|
||||
});
|
||||
@@ -171,3 +171,53 @@ test('runtime-state patch prefers explicit activeFlowId over stale legacy flowId
|
||||
'kiro-open-register-page': 'running',
|
||||
});
|
||||
});
|
||||
|
||||
test('runtime-state patch preserves canonical nested kiro flow state without projecting a top-level alias', () => {
|
||||
const api = loadRuntimeStateApi();
|
||||
const helpers = api.createRuntimeStateHelpers({
|
||||
DEFAULT_ACTIVE_FLOW_ID: 'openai',
|
||||
defaultNodeStatuses: {
|
||||
'open-chatgpt': 'pending',
|
||||
'kiro-open-register-page': 'pending',
|
||||
},
|
||||
});
|
||||
|
||||
const patch = helpers.buildSessionStatePatch({
|
||||
runtimeState: {
|
||||
activeFlowId: 'kiro',
|
||||
flowState: {
|
||||
kiro: {
|
||||
session: {
|
||||
currentStage: 'register',
|
||||
},
|
||||
register: {
|
||||
email: 'old-user@example.com',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}, {
|
||||
runtimeState: {
|
||||
flowState: {
|
||||
kiro: {
|
||||
register: {
|
||||
email: 'aws-user@example.com',
|
||||
},
|
||||
upload: {
|
||||
status: 'uploaded',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(patch, 'kiroRuntime'), false);
|
||||
assert.equal(patch.runtimeState.flowState.kiro.session.currentStage, 'register');
|
||||
assert.equal(patch.runtimeState.flowState.kiro.register.email, 'aws-user@example.com');
|
||||
assert.equal(patch.runtimeState.flowState.kiro.upload.status, 'uploaded');
|
||||
|
||||
const view = helpers.buildStateView(patch);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(view, 'kiroRuntime'), false);
|
||||
assert.equal(view.flowState.kiro.register.email, 'aws-user@example.com');
|
||||
assert.equal(view.flowState.kiro.upload.status, 'uploaded');
|
||||
});
|
||||
|
||||
@@ -52,12 +52,24 @@ test('importSettingsBundle normalizes unsupported capability flags before persis
|
||||
const api = new Function(`
|
||||
const SETTINGS_EXPORT_SCHEMA_VERSION = 1;
|
||||
const DEFAULT_REGISTRATION_EMAIL_STATE = { emailHistory: [] };
|
||||
const DEFAULT_ACTIVE_FLOW_ID = 'openai';
|
||||
const self = {
|
||||
MultiPageLegacySettingsImporter: {
|
||||
createSettingsImporter() {
|
||||
return {
|
||||
importSettings(settings = {}) {
|
||||
return { ...settings };
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
let persistedUpdates = null;
|
||||
let stateUpdates = null;
|
||||
let broadcastPayload = null;
|
||||
let currentState = {
|
||||
activeFlowId: 'site-a',
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
signupMethod: 'phone',
|
||||
plusModeEnabled: false,
|
||||
phoneVerificationEnabled: false,
|
||||
@@ -74,7 +86,7 @@ function validateModeSwitchState() {
|
||||
ok: false,
|
||||
errors: [{ code: 'panel_mode_unsupported', message: '当前 flow 不支持 SUB2API 面板模式。' }],
|
||||
normalizedUpdates: {
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
plusModeEnabled: false,
|
||||
phoneVerificationEnabled: false,
|
||||
signupMethod: 'email',
|
||||
@@ -84,6 +96,9 @@ function validateModeSwitchState() {
|
||||
function resolveSignupMethod(state = {}) {
|
||||
return String(state?.signupMethod || '').trim().toLowerCase() === 'phone' ? 'phone' : 'email';
|
||||
}
|
||||
function getSettingsSchemaApi() {
|
||||
return null;
|
||||
}
|
||||
async function setPersistentSettings(updates) {
|
||||
persistedUpdates = { ...updates };
|
||||
}
|
||||
@@ -109,7 +124,7 @@ return {
|
||||
const result = await api.importSettingsBundle({
|
||||
schemaVersion: 1,
|
||||
settings: {
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
plusModeEnabled: true,
|
||||
phoneVerificationEnabled: true,
|
||||
signupMethod: 'phone',
|
||||
@@ -117,16 +132,164 @@ return {
|
||||
});
|
||||
|
||||
assert.deepEqual(api.getPersistedUpdates(), {
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
plusModeEnabled: false,
|
||||
phoneVerificationEnabled: false,
|
||||
signupMethod: 'email',
|
||||
});
|
||||
assert.equal(api.getStateUpdates().panelMode, 'cpa');
|
||||
assert.equal(api.getStateUpdates().targetId, 'cpa');
|
||||
assert.equal(api.getStateUpdates().plusModeEnabled, false);
|
||||
assert.equal(api.getStateUpdates().phoneVerificationEnabled, false);
|
||||
assert.equal(api.getStateUpdates().signupMethod, 'email');
|
||||
assert.equal(api.getBroadcastPayload().panelMode, 'cpa');
|
||||
assert.equal(api.getBroadcastPayload().targetId, 'cpa');
|
||||
assert.equal(api.getBroadcastPayload().signupMethod, 'email');
|
||||
assert.equal(result.signupMethod, 'email');
|
||||
});
|
||||
|
||||
test('importSettingsBundle routes legacy settings through the legacy importer before persisting', async () => {
|
||||
const api = new Function(`
|
||||
const SETTINGS_EXPORT_SCHEMA_VERSION = 1;
|
||||
const DEFAULT_REGISTRATION_EMAIL_STATE = { emailHistory: [] };
|
||||
const DEFAULT_ACTIVE_FLOW_ID = 'openai';
|
||||
let importerInput = null;
|
||||
let persistedUpdates = null;
|
||||
let currentState = {
|
||||
activeFlowId: 'openai',
|
||||
nodeStatuses: {},
|
||||
};
|
||||
const self = {
|
||||
MultiPageFlowRegistry: {
|
||||
DEFAULT_FLOW_ID: 'openai',
|
||||
},
|
||||
MultiPageLegacySettingsImporter: {
|
||||
createSettingsImporter() {
|
||||
return {
|
||||
importSettings(settings = {}) {
|
||||
importerInput = JSON.parse(JSON.stringify(settings));
|
||||
return {
|
||||
settingsSchemaVersion: 5,
|
||||
settingsState: {
|
||||
schemaVersion: 5,
|
||||
activeFlowId: 'kiro',
|
||||
services: {
|
||||
account: { customPassword: '' },
|
||||
email: { provider: '163' },
|
||||
proxy: { enabled: false, provider: '711proxy', mode: 'account' },
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
selectedTargetId: 'cpa',
|
||||
targets: {
|
||||
cpa: { vpsUrl: '', vpsPassword: '', localCpaStep9Mode: 'submit' },
|
||||
sub2api: {
|
||||
sub2apiUrl: '',
|
||||
sub2apiEmail: '',
|
||||
sub2apiPassword: '',
|
||||
sub2apiGroupName: 'codex',
|
||||
sub2apiGroupNames: ['codex', 'openai-plus'],
|
||||
sub2apiAccountPriority: 1,
|
||||
sub2apiDefaultProxyName: '',
|
||||
},
|
||||
codex2api: { codex2apiUrl: '', codex2apiAdminKey: '' },
|
||||
},
|
||||
signup: {
|
||||
signupMethod: 'email',
|
||||
phoneVerificationEnabled: false,
|
||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||
},
|
||||
plus: {
|
||||
plusModeEnabled: false,
|
||||
plusPaymentMethod: 'paypal',
|
||||
plusAccountAccessStrategy: 'oauth',
|
||||
},
|
||||
autoRun: {
|
||||
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 11 },
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
selectedTargetId: 'kiro-rs',
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
baseUrl: 'https://kiro.example.com/admin',
|
||||
apiKey: 'imported-key',
|
||||
},
|
||||
},
|
||||
autoRun: {
|
||||
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 9 },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
async function ensureManualInteractionAllowed() {
|
||||
return currentState;
|
||||
}
|
||||
function buildPersistentSettingsPayload(settings = {}) {
|
||||
return {
|
||||
activeFlowId: settings.settingsState.activeFlowId,
|
||||
targetId: 'cpa',
|
||||
signupMethod: 'email',
|
||||
targetId: 'kiro-rs',
|
||||
kiroRsUrl: settings.settingsState.flows.kiro.targets['kiro-rs'].baseUrl,
|
||||
kiroRsKey: settings.settingsState.flows.kiro.targets['kiro-rs'].apiKey,
|
||||
settingsSchemaVersion: settings.settingsSchemaVersion,
|
||||
settingsState: settings.settingsState,
|
||||
};
|
||||
}
|
||||
function validateModeSwitchState() {
|
||||
return { normalizedUpdates: {} };
|
||||
}
|
||||
function resolveSignupMethod() {
|
||||
return 'email';
|
||||
}
|
||||
function getSettingsSchemaApi() {
|
||||
return null;
|
||||
}
|
||||
async function setPersistentSettings(updates) {
|
||||
persistedUpdates = { ...updates };
|
||||
return updates;
|
||||
}
|
||||
async function setState(updates) {
|
||||
currentState = { ...currentState, ...updates };
|
||||
}
|
||||
function broadcastDataUpdate() {}
|
||||
async function getState() {
|
||||
return currentState;
|
||||
}
|
||||
${extractFunction('importSettingsBundle')}
|
||||
return {
|
||||
importSettingsBundle,
|
||||
getImporterInput: () => importerInput,
|
||||
getPersistedUpdates: () => persistedUpdates,
|
||||
};
|
||||
`)();
|
||||
|
||||
await api.importSettingsBundle({
|
||||
schemaVersion: 1,
|
||||
settings: {
|
||||
targetId: 'sub2api',
|
||||
kiroRuntime: {
|
||||
upload: {
|
||||
status: 'uploaded',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepEqual(api.getImporterInput(), {
|
||||
targetId: 'sub2api',
|
||||
kiroRuntime: {
|
||||
upload: {
|
||||
status: 'uploaded',
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.equal(api.getPersistedUpdates().activeFlowId, 'kiro');
|
||||
assert.equal(api.getPersistedUpdates().settingsSchemaVersion, 5);
|
||||
assert.equal(api.getPersistedUpdates().settingsState.flows.kiro.targets['kiro-rs'].apiKey, 'imported-key');
|
||||
});
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const { readFlowRegistryBundle } = require('./helpers/script-bundles.js');
|
||||
|
||||
const flowRegistrySource = fs.readFileSync('shared/flow-registry.js', 'utf8');
|
||||
const settingsSchemaSource = fs.readFileSync('shared/settings-schema.js', 'utf8');
|
||||
const flowRegistrySource = readFlowRegistryBundle();
|
||||
const settingsSchemaSource = fs.readFileSync('core/flow-kernel/settings-schema.js', 'utf8');
|
||||
const backgroundSource = fs.readFileSync('background.js', 'utf8');
|
||||
|
||||
function extractFunction(name) {
|
||||
@@ -59,9 +60,7 @@ const DEFAULT_ACTIVE_FLOW_ID = 'openai';
|
||||
const DEFAULT_SUB2API_GROUP_NAMES = ['codex', 'openai-plus'];
|
||||
const SETTINGS_SCHEMA_VIEW_KEYS = Object.freeze([
|
||||
'activeFlowId',
|
||||
'openaiIntegrationTargetId',
|
||||
'panelMode',
|
||||
'kiroTargetId',
|
||||
'targetId',
|
||||
'vpsUrl',
|
||||
'vpsPassword',
|
||||
'localCpaStep9Mode',
|
||||
@@ -92,7 +91,7 @@ const SETTINGS_SCHEMA_VIEW_KEYS = Object.freeze([
|
||||
const SETTINGS_SCHEMA_VIEW_KEY_SET = new Set(SETTINGS_SCHEMA_VIEW_KEYS);
|
||||
const PERSISTED_SETTING_DEFAULTS = {
|
||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||
panelMode: 'cpa',
|
||||
targetId: 'cpa',
|
||||
signupMethod: 'email',
|
||||
plusModeEnabled: false,
|
||||
plusPaymentMethod: 'paypal',
|
||||
@@ -102,7 +101,6 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
ipProxyEnabled: false,
|
||||
ipProxyService: '711proxy',
|
||||
ipProxyMode: 'account',
|
||||
kiroTargetId: 'kiro-rs',
|
||||
kiroRsUrl: '',
|
||||
kiroRsKey: '',
|
||||
stepExecutionRangeByFlow: {},
|
||||
@@ -203,13 +201,13 @@ test('buildPersistentSettingsPayload writes canonical settings schema into persi
|
||||
}, { fillDefaults: true });
|
||||
|
||||
assert.equal(payload.activeFlowId, 'kiro');
|
||||
assert.equal(payload.kiroTargetId, 'kiro-rs');
|
||||
assert.equal(payload.targetId, 'kiro-rs');
|
||||
assert.equal(payload.kiroRsUrl, 'https://kiro.example.com/admin');
|
||||
assert.equal(payload.kiroRsKey, 'secret-key');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(payload, 'kiroRegion'), false);
|
||||
assert.equal(payload.settingsSchemaVersion, 4);
|
||||
assert.equal(payload.settingsSchemaVersion, 5);
|
||||
assert.equal(payload.settingsState.activeFlowId, 'kiro');
|
||||
assert.equal(payload.settingsState.flows.kiro.targetId, 'kiro-rs');
|
||||
assert.equal(payload.settingsState.flows.kiro.selectedTargetId, 'kiro-rs');
|
||||
assert.equal(
|
||||
payload.settingsState.flows.kiro.targets['kiro-rs'].baseUrl,
|
||||
'https://kiro.example.com/admin'
|
||||
@@ -220,7 +218,7 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
|
||||
const api = buildHarness();
|
||||
|
||||
const payload = api.buildPersistentSettingsPayload({
|
||||
settingsSchemaVersion: 4,
|
||||
settingsSchemaVersion: 5,
|
||||
settingsState: {
|
||||
activeFlowId: 'kiro',
|
||||
services: {
|
||||
@@ -230,8 +228,8 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
integrationTargetId: 'cpa',
|
||||
integrationTargets: {
|
||||
selectedTargetId: 'cpa',
|
||||
targets: {
|
||||
cpa: {
|
||||
vpsUrl: '',
|
||||
vpsPassword: '',
|
||||
@@ -266,7 +264,7 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
targetId: 'kiro-rs',
|
||||
selectedTargetId: 'kiro-rs',
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
baseUrl: 'https://kiro.example.com/admin',
|
||||
@@ -282,11 +280,11 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
|
||||
}, { requireKnownKeys: true });
|
||||
|
||||
assert.equal(payload.activeFlowId, 'kiro');
|
||||
assert.equal(payload.kiroTargetId, 'kiro-rs');
|
||||
assert.equal(payload.targetId, 'kiro-rs');
|
||||
assert.equal(payload.kiroRsUrl, 'https://kiro.example.com/admin');
|
||||
assert.equal(payload.kiroRsKey, 'schema-only-key');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(payload, 'kiroRegion'), false);
|
||||
assert.equal(payload.settingsSchemaVersion, 4);
|
||||
assert.equal(payload.settingsSchemaVersion, 5);
|
||||
assert.equal(payload.settingsState.flows.openai.plus.plusAccountAccessStrategy, 'oauth');
|
||||
});
|
||||
|
||||
@@ -313,7 +311,7 @@ function getRequestedKeys() {
|
||||
assert.ok(api.getRequestedKeys().includes('settingsSchemaVersion'));
|
||||
assert.ok(api.getRequestedKeys().includes('settingsState'));
|
||||
assert.ok(api.getRequestedKeys().includes('plusAccountAccessStrategy'));
|
||||
assert.equal(state.settingsSchemaVersion, 4);
|
||||
assert.equal(state.settingsSchemaVersion, 5);
|
||||
assert.equal(state.settingsState.activeFlowId, 'openai');
|
||||
});
|
||||
|
||||
@@ -324,7 +322,7 @@ const chrome = {
|
||||
local: {
|
||||
async get() {
|
||||
return {
|
||||
settingsSchemaVersion: 4,
|
||||
settingsSchemaVersion: 5,
|
||||
settingsState: {
|
||||
activeFlowId: 'kiro',
|
||||
services: {
|
||||
@@ -334,8 +332,8 @@ const chrome = {
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
integrationTargetId: 'sub2api',
|
||||
integrationTargets: {
|
||||
selectedTargetId: 'sub2api',
|
||||
targets: {
|
||||
cpa: {
|
||||
vpsUrl: '',
|
||||
vpsPassword: '',
|
||||
@@ -370,7 +368,7 @@ const chrome = {
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
targetId: 'kiro-rs',
|
||||
selectedTargetId: 'kiro-rs',
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
baseUrl: 'https://kiro.example.com/admin',
|
||||
@@ -393,7 +391,8 @@ const chrome = {
|
||||
const state = await api.getPersistedSettings();
|
||||
|
||||
assert.equal(state.activeFlowId, 'kiro');
|
||||
assert.equal(state.panelMode, 'sub2api');
|
||||
assert.equal(state.targetId, 'kiro-rs');
|
||||
assert.equal(state.settingsState.flows.openai.selectedTargetId, 'sub2api');
|
||||
assert.equal(state.mailProvider, 'hotmail');
|
||||
assert.equal(state.ipProxyEnabled, true);
|
||||
assert.equal(state.kiroRsUrl, 'https://kiro.example.com/admin');
|
||||
@@ -435,7 +434,7 @@ function getRemovedKeys() {
|
||||
`);
|
||||
|
||||
const persisted = await api.setPersistentSettings({
|
||||
settingsSchemaVersion: 4,
|
||||
settingsSchemaVersion: 5,
|
||||
settingsState: {
|
||||
activeFlowId: 'kiro',
|
||||
services: {
|
||||
@@ -445,8 +444,8 @@ function getRemovedKeys() {
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
integrationTargetId: 'cpa',
|
||||
integrationTargets: {
|
||||
selectedTargetId: 'cpa',
|
||||
targets: {
|
||||
cpa: {
|
||||
vpsUrl: '',
|
||||
vpsPassword: '',
|
||||
@@ -481,7 +480,7 @@ function getRemovedKeys() {
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
targetId: 'kiro-rs',
|
||||
selectedTargetId: 'kiro-rs',
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
baseUrl: 'https://kiro.example.com/admin',
|
||||
@@ -499,21 +498,20 @@ function getRemovedKeys() {
|
||||
const write = api.getPersistedWrites().at(-1);
|
||||
|
||||
assert.equal(persisted.activeFlowId, 'kiro');
|
||||
assert.equal(persisted.kiroTargetId, 'kiro-rs');
|
||||
assert.equal(persisted.targetId, 'kiro-rs');
|
||||
assert.equal(persisted.kiroRsUrl, 'https://kiro.example.com/admin');
|
||||
assert.equal(persisted.kiroRsKey, 'nested-only-key');
|
||||
assert.equal(persisted.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(persisted, 'kiroRegion'), false);
|
||||
assert.equal(persisted.settingsSchemaVersion, 4);
|
||||
assert.equal(persisted.settingsSchemaVersion, 5);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'activeFlowId'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRsUrl'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRsKey'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRegion'), false);
|
||||
assert.equal(write.settingsSchemaVersion, 4);
|
||||
assert.equal(write.settingsSchemaVersion, 5);
|
||||
assert.equal(write.settingsState.activeFlowId, 'kiro');
|
||||
assert.equal(write.settingsState.flows.openai.plus.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||
assert.equal(write.settingsState.flows.kiro.targetId, 'kiro-rs');
|
||||
assert.ok(api.getRemovedKeys().includes('panelMode'));
|
||||
assert.equal(write.settingsState.flows.kiro.selectedTargetId, 'kiro-rs');
|
||||
assert.ok(api.getRemovedKeys().includes('kiroRsUrl'));
|
||||
});
|
||||
|
||||
@@ -526,7 +524,7 @@ const chrome = {
|
||||
local: {
|
||||
async get() {
|
||||
return {
|
||||
settingsSchemaVersion: 4,
|
||||
settingsSchemaVersion: 5,
|
||||
settingsState: {
|
||||
activeFlowId: 'openai',
|
||||
services: {
|
||||
@@ -575,7 +573,7 @@ const chrome = {
|
||||
local: {
|
||||
async get() {
|
||||
return {
|
||||
settingsSchemaVersion: 4,
|
||||
settingsSchemaVersion: 5,
|
||||
settingsState: {
|
||||
activeFlowId: 'openai',
|
||||
services: {
|
||||
@@ -585,8 +583,8 @@ const chrome = {
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
integrationTargetId: 'cpa',
|
||||
integrationTargets: {
|
||||
selectedTargetId: 'cpa',
|
||||
targets: {
|
||||
cpa: {
|
||||
vpsUrl: 'https://old-cpa.example.com',
|
||||
vpsPassword: 'old-vps-password',
|
||||
@@ -621,7 +619,7 @@ const chrome = {
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
targetId: 'kiro-rs',
|
||||
selectedTargetId: 'kiro-rs',
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
baseUrl: 'https://kiro.example.com/admin',
|
||||
@@ -654,7 +652,7 @@ function getRemovedKeys() {
|
||||
`);
|
||||
|
||||
const persisted = await api.setPersistentSettings({
|
||||
panelMode: 'sub2api',
|
||||
targetId: 'sub2api',
|
||||
mailProvider: 'cloudflare-temp-email',
|
||||
ipProxyEnabled: true,
|
||||
ipProxyMode: 'api',
|
||||
@@ -664,7 +662,7 @@ function getRemovedKeys() {
|
||||
});
|
||||
const write = api.getPersistedWrites().at(-1);
|
||||
|
||||
assert.equal(persisted.panelMode, 'sub2api');
|
||||
assert.equal(persisted.targetId, 'sub2api');
|
||||
assert.equal(persisted.mailProvider, 'cloudflare-temp-email');
|
||||
assert.equal(persisted.ipProxyEnabled, true);
|
||||
assert.equal(persisted.ipProxyMode, 'api');
|
||||
@@ -673,7 +671,7 @@ function getRemovedKeys() {
|
||||
fromStep: 2,
|
||||
toStep: 4,
|
||||
});
|
||||
assert.equal(write.settingsState.flows.openai.integrationTargetId, 'sub2api');
|
||||
assert.equal(write.settingsState.flows.openai.selectedTargetId, 'sub2api');
|
||||
assert.equal(write.settingsState.services.email.provider, 'cloudflare-temp-email');
|
||||
assert.equal(write.settingsState.services.proxy.enabled, true);
|
||||
assert.equal(write.settingsState.services.proxy.mode, 'api');
|
||||
@@ -682,8 +680,8 @@ function getRemovedKeys() {
|
||||
fromStep: 2,
|
||||
toStep: 4,
|
||||
});
|
||||
assert.equal(write.settingsState.flows.openai.integrationTargets.sub2api.sub2apiUrl, 'https://sub2api.example.com');
|
||||
assert.equal(write.settingsState.flows.openai.integrationTargets.sub2api.sub2apiEmail, 'owner@example.com');
|
||||
assert.equal(write.settingsState.flows.openai.targets.sub2api.sub2apiUrl, 'https://sub2api.example.com');
|
||||
assert.equal(write.settingsState.flows.openai.targets.sub2api.sub2apiEmail, 'owner@example.com');
|
||||
assert.equal(write.settingsState.flows.kiro.targets['kiro-rs'].apiKey, 'kiro-key');
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'mailProvider'), false);
|
||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'panelMode'), false);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
const step2Source = fs.readFileSync('background/steps/submit-signup-email.js', 'utf8');
|
||||
const step2Source = fs.readFileSync('flows/openai/background/steps/submit-signup-email.js', 'utf8');
|
||||
const step2GlobalScope = {};
|
||||
const step2Api = new Function('self', `${step2Source}; return self.MultiPageBackgroundStep2;`)(step2GlobalScope);
|
||||
|
||||
@@ -33,7 +33,7 @@ test('step 2 completes with password step skipped when landing on email verifica
|
||||
isTabAlive: async () => true,
|
||||
resolveSignupEmailForFlow: async () => 'user@example.com',
|
||||
sendToContentScriptResilient: async () => ({ submitted: true }),
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({ email: 'user@example.com' });
|
||||
@@ -72,7 +72,7 @@ test('step 2 keeps password flow when landing on password page', async () => {
|
||||
isTabAlive: async () => true,
|
||||
resolveSignupEmailForFlow: async () => 'user@example.com',
|
||||
sendToContentScriptResilient: async () => ({ submitted: true }),
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({ email: 'user@example.com' });
|
||||
@@ -150,7 +150,7 @@ test('step 2 uses phone activation when resolved signup method is phone', async
|
||||
sentPayloads.push(message.payload);
|
||||
return { submitted: true };
|
||||
},
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({ signupMethod: 'phone' });
|
||||
@@ -233,7 +233,7 @@ test('step 2 reuses existing signup phone activation without acquiring a new num
|
||||
sentPayloads.push(message.payload);
|
||||
return { submitted: true };
|
||||
},
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({
|
||||
@@ -290,7 +290,7 @@ test('step 2 submits manual signup phone without acquiring a number', async () =
|
||||
sentPayloads.push(message.payload);
|
||||
return { submitted: true };
|
||||
},
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({
|
||||
@@ -354,7 +354,7 @@ test('step 2 stops with an explicit error instead of silently skipping 3/4/5 on
|
||||
isTabAlive: async () => true,
|
||||
resolveSignupEmailForFlow: async () => 'user@example.com',
|
||||
sendToContentScriptResilient: async () => ({ submitted: true }),
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
@@ -405,7 +405,7 @@ test('step 2 does not force auth-entry retry on logged-out chatgpt home when con
|
||||
sentPayloads.push(message.payload);
|
||||
return { submitted: true };
|
||||
},
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
});
|
||||
|
||||
await executor.executeStep2({ email: 'user@example.com' });
|
||||
@@ -472,7 +472,7 @@ test('step 2 waits for the existing signup tab to settle before probing the entr
|
||||
}
|
||||
return { submitted: true };
|
||||
},
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabStableComplete: async (_tabId, options) => {
|
||||
events.push({ type: 'wait-stable', options });
|
||||
return { id: 17, url: 'https://chatgpt.com/', status: 'complete' };
|
||||
@@ -543,7 +543,7 @@ test('signup flow helper recognizes email verification page as post-email landin
|
||||
},
|
||||
setEmailState: async () => {},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async () => ({
|
||||
id: 21,
|
||||
url: 'https://auth.openai.com/email-verification',
|
||||
@@ -600,7 +600,7 @@ test('signup flow helper waits for the signup entry tab to settle for step 2 bef
|
||||
},
|
||||
setEmailState: async () => {},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabStableComplete: async (_tabId, options) => {
|
||||
events.push({ type: 'wait-stable', options });
|
||||
return { id: 23, url: 'https://chatgpt.com/', status: 'complete' };
|
||||
@@ -680,7 +680,7 @@ test('signup flow helper accepts phone signup landing on login password page', a
|
||||
},
|
||||
setEmailState: async () => {},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async (_tabId, predicate) => {
|
||||
const url = 'https://auth.openai.com/log-in/password';
|
||||
return predicate(url) ? { id: 22, url } : null;
|
||||
@@ -724,7 +724,7 @@ test('signup flow helper reuses existing managed alias email when it is still co
|
||||
setEmailCalls += 1;
|
||||
},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async () => null,
|
||||
});
|
||||
|
||||
@@ -767,7 +767,7 @@ test('signup flow helper can generate an email on demand when add-email starts f
|
||||
setStateCalls.push(updates);
|
||||
},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async () => null,
|
||||
});
|
||||
|
||||
@@ -836,7 +836,7 @@ test('signup flow helper delegates preserved phone identity email sync to the sh
|
||||
setStateCalls += 1;
|
||||
},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: [],
|
||||
OPENAI_AUTH_INJECT_FILES: [],
|
||||
waitForTabUrlMatch: async () => null,
|
||||
});
|
||||
|
||||
@@ -901,7 +901,7 @@ test('signup flow helper finalizes step 3 submit by reusing signup verification
|
||||
},
|
||||
setEmailState: async () => {},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: ['content/utils.js', 'content/signup-page.js'],
|
||||
OPENAI_AUTH_INJECT_FILES: ['content/utils.js', 'flows/openai/content/openai-auth.js'],
|
||||
waitForTabUrlMatch: async () => null,
|
||||
});
|
||||
|
||||
@@ -943,11 +943,11 @@ test('signup flow helper rewrites retryable step 3 finalize transport timeout in
|
||||
isSignupPasswordPageUrl: () => true,
|
||||
reuseOrCreateTab: async () => 31,
|
||||
sendToContentScriptResilient: async () => {
|
||||
throw new Error('Content script on signup-page did not respond in 45s. Try refreshing the tab and retry.');
|
||||
throw new Error('Content script on openai-auth did not respond in 45s. Try refreshing the tab and retry.');
|
||||
},
|
||||
setEmailState: async () => {},
|
||||
SIGNUP_ENTRY_URL: 'https://chatgpt.com/',
|
||||
SIGNUP_PAGE_INJECT_FILES: ['content/utils.js', 'content/signup-page.js'],
|
||||
OPENAI_AUTH_INJECT_FILES: ['content/utils.js', 'flows/openai/content/openai-auth.js'],
|
||||
waitForTabUrlMatch: async () => null,
|
||||
});
|
||||
|
||||
|
||||
@@ -6,22 +6,22 @@ test('background imports workflow step modules including rebuilt Kiro modules',
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
|
||||
[
|
||||
'background/steps/open-chatgpt.js',
|
||||
'background/steps/submit-signup-email.js',
|
||||
'background/steps/fill-password.js',
|
||||
'background/steps/fetch-signup-code.js',
|
||||
'background/steps/fill-profile.js',
|
||||
'background/steps/wait-registration-success.js',
|
||||
'background/steps/oauth-login.js',
|
||||
'background/steps/fetch-login-code.js',
|
||||
'background/steps/confirm-oauth.js',
|
||||
'background/steps/platform-verify.js',
|
||||
'flows/openai/background/steps/open-chatgpt.js',
|
||||
'flows/openai/background/steps/submit-signup-email.js',
|
||||
'flows/openai/background/steps/fill-password.js',
|
||||
'flows/openai/background/steps/fetch-signup-code.js',
|
||||
'flows/openai/background/steps/fill-profile.js',
|
||||
'flows/openai/background/steps/wait-registration-success.js',
|
||||
'flows/openai/background/steps/oauth-login.js',
|
||||
'flows/openai/background/steps/fetch-login-code.js',
|
||||
'flows/openai/background/steps/confirm-oauth.js',
|
||||
'flows/openai/background/steps/platform-verify.js',
|
||||
'shared/kiro-timeouts.js',
|
||||
'background/kiro/state.js',
|
||||
'background/kiro/register-runner.js',
|
||||
'background/kiro/desktop-client.js',
|
||||
'background/kiro/desktop-authorize-runner.js',
|
||||
'background/kiro/publisher-kiro-rs.js',
|
||||
'flows/kiro/background/state.js',
|
||||
'flows/kiro/background/register-runner.js',
|
||||
'flows/kiro/background/desktop-client.js',
|
||||
'flows/kiro/background/desktop-authorize-runner.js',
|
||||
'flows/kiro/background/publisher-kiro-rs.js',
|
||||
].forEach((path) => {
|
||||
assert.match(source, new RegExp(path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
|
||||
test('background node registry preserves node metadata even before an executor is registered', () => {
|
||||
const source = fs.readFileSync('background/steps/registry.js', 'utf8');
|
||||
const source = fs.readFileSync('core/flow-kernel/step-registry.js', 'utf8');
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStepRegistry;`)({});
|
||||
const registry = api.createNodeRegistry([
|
||||
{
|
||||
@@ -27,7 +27,7 @@ test('background node registry preserves node metadata even before an executor i
|
||||
});
|
||||
|
||||
test('background node registry executes registered nodes in display order', async () => {
|
||||
const source = fs.readFileSync('background/steps/registry.js', 'utf8');
|
||||
const source = fs.readFileSync('core/flow-kernel/step-registry.js', 'utf8');
|
||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundStepRegistry;`)({});
|
||||
const events = [];
|
||||
const registry = api.createNodeRegistry([
|
||||
|
||||
@@ -4,19 +4,19 @@ const fs = require('node:fs');
|
||||
|
||||
test('background imports node registry and wires the rebuilt Kiro executors', () => {
|
||||
const source = fs.readFileSync('background.js', 'utf8');
|
||||
assert.match(source, /background\/steps\/registry\.js/);
|
||||
assert.match(source, /core\/flow-kernel\/step-registry\.js/);
|
||||
assert.match(source, /data\/step-definitions\.js/);
|
||||
assert.match(source, /background\/workflow-engine\.js/);
|
||||
assert.match(source, /core\/flow-kernel\/workflow-engine\.js/);
|
||||
assert.match(source, /MultiPageStepDefinitions\?\.getNodes/);
|
||||
assert.match(source, /buildNodeRegistry\(definitions/);
|
||||
assert.match(source, /const stepRegistryCache = new Map\(\);/);
|
||||
assert.match(source, /const definitions = getNodeDefinitionsForState\(state\);/);
|
||||
assert.match(source, /stepRegistryCache\.set\(cacheKey, buildStepRegistry\(definitions\)\)/);
|
||||
|
||||
assert.match(source, /background\/kiro\/register-runner\.js/);
|
||||
assert.match(source, /background\/kiro\/desktop-client\.js/);
|
||||
assert.match(source, /background\/kiro\/desktop-authorize-runner\.js/);
|
||||
assert.match(source, /background\/kiro\/publisher-kiro-rs\.js/);
|
||||
assert.match(source, /flows\/kiro\/background\/register-runner\.js/);
|
||||
assert.match(source, /flows\/kiro\/background\/desktop-client\.js/);
|
||||
assert.match(source, /flows\/kiro\/background\/desktop-authorize-runner\.js/);
|
||||
assert.match(source, /flows\/kiro\/background\/publisher-kiro-rs\.js/);
|
||||
assert.doesNotMatch(source, /background\/steps\/kiro-device-auth\.js/);
|
||||
|
||||
assert.match(source, /const kiroRegisterRunner = self\.MultiPageBackgroundKiroRegisterRunner\?\.createKiroRegisterRunner\(/);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user