Add Plus SUB2API session access strategy
This commit is contained in:
+177
-18
@@ -55,6 +55,7 @@ importScripts(
|
|||||||
'background/steps/paypal-approve.js',
|
'background/steps/paypal-approve.js',
|
||||||
'background/steps/gopay-approve.js',
|
'background/steps/gopay-approve.js',
|
||||||
'background/steps/plus-return-confirm.js',
|
'background/steps/plus-return-confirm.js',
|
||||||
|
'background/steps/sub2api-session-import.js',
|
||||||
'background/steps/oauth-login.js',
|
'background/steps/oauth-login.js',
|
||||||
'background/steps/fetch-login-code.js',
|
'background/steps/fetch-login-code.js',
|
||||||
'background/steps/confirm-oauth.js',
|
'background/steps/confirm-oauth.js',
|
||||||
@@ -94,6 +95,12 @@ const PLUS_PAYPAL_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
|||||||
plusModeEnabled: true,
|
plusModeEnabled: true,
|
||||||
plusPaymentMethod: 'paypal',
|
plusPaymentMethod: 'paypal',
|
||||||
}) || NORMAL_STEP_DEFINITIONS;
|
}) || NORMAL_STEP_DEFINITIONS;
|
||||||
|
const PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
||||||
|
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION,
|
||||||
|
}) || PLUS_PAYPAL_STEP_DEFINITIONS;
|
||||||
const PLUS_PAYPAL_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
const PLUS_PAYPAL_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
||||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||||
plusModeEnabled: true,
|
plusModeEnabled: true,
|
||||||
@@ -112,6 +119,12 @@ const PLUS_GOPAY_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
|||||||
plusModeEnabled: true,
|
plusModeEnabled: true,
|
||||||
plusPaymentMethod: 'gopay',
|
plusPaymentMethod: 'gopay',
|
||||||
}) || PLUS_PAYPAL_STEP_DEFINITIONS;
|
}) || PLUS_PAYPAL_STEP_DEFINITIONS;
|
||||||
|
const PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
||||||
|
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'gopay',
|
||||||
|
plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION,
|
||||||
|
}) || PLUS_GOPAY_STEP_DEFINITIONS;
|
||||||
const PLUS_GOPAY_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
const PLUS_GOPAY_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
||||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||||
plusModeEnabled: true,
|
plusModeEnabled: true,
|
||||||
@@ -130,6 +143,12 @@ const PLUS_GPC_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
|||||||
plusModeEnabled: true,
|
plusModeEnabled: true,
|
||||||
plusPaymentMethod: 'gpc-helper',
|
plusPaymentMethod: 'gpc-helper',
|
||||||
}) || PLUS_GOPAY_STEP_DEFINITIONS;
|
}) || PLUS_GOPAY_STEP_DEFINITIONS;
|
||||||
|
const PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
||||||
|
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'gpc-helper',
|
||||||
|
plusAccountAccessStrategy: PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION,
|
||||||
|
}) || PLUS_GPC_STEP_DEFINITIONS;
|
||||||
const PLUS_GPC_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
const PLUS_GPC_PHONE_STEP_DEFINITIONS = self.MultiPageStepDefinitions?.getSteps?.({
|
||||||
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
|
||||||
plusModeEnabled: true,
|
plusModeEnabled: true,
|
||||||
@@ -165,12 +184,15 @@ const ALL_STEP_DEFINITIONS = (() => {
|
|||||||
...NORMAL_PHONE_STEP_DEFINITIONS,
|
...NORMAL_PHONE_STEP_DEFINITIONS,
|
||||||
...NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
...PLUS_PAYPAL_STEP_DEFINITIONS,
|
...PLUS_PAYPAL_STEP_DEFINITIONS,
|
||||||
|
...PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
...PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
...PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
||||||
...PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
...PLUS_GOPAY_STEP_DEFINITIONS,
|
...PLUS_GOPAY_STEP_DEFINITIONS,
|
||||||
|
...PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
...PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
...PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
||||||
...PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
...PLUS_GPC_STEP_DEFINITIONS,
|
...PLUS_GPC_STEP_DEFINITIONS,
|
||||||
|
...PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
...PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
...PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
||||||
...PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
];
|
];
|
||||||
@@ -632,6 +654,8 @@ const FIVE_SIM_OPERATOR = DEFAULT_FIVE_SIM_OPERATOR;
|
|||||||
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
||||||
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
||||||
const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper';
|
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 DEFAULT_PLUS_PAYMENT_METHOD = PLUS_PAYMENT_METHOD_PAYPAL;
|
const DEFAULT_PLUS_PAYMENT_METHOD = PLUS_PAYMENT_METHOD_PAYPAL;
|
||||||
const DISPLAY_TIMEZONE = 'Asia/Shanghai';
|
const DISPLAY_TIMEZONE = 'Asia/Shanghai';
|
||||||
const MICROSOFT_TOKEN_DNR_RULE_ID = 1001;
|
const MICROSOFT_TOKEN_DNR_RULE_ID = 1001;
|
||||||
@@ -722,34 +746,108 @@ function getSignupMethodForStepDefinitions(state = {}) {
|
|||||||
return normalizeSignupMethod(state?.resolvedSignupMethod || state?.signupMethod);
|
return normalizeSignupMethod(state?.resolvedSignupMethod || state?.signupMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildResolvedStepDefinitionState(state = {}) {
|
||||||
|
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID === 'string' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
||||||
|
const requestedActiveFlowId = String(state?.activeFlowId || state?.flowId || '').trim().toLowerCase() || defaultFlowId;
|
||||||
|
const requestedSignupMethod = getSignupMethodForStepDefinitions(state);
|
||||||
|
const plusModeEnabled = isPlusModeState(state);
|
||||||
|
const plusPaymentMethod = normalizePlusPaymentMethod(state?.plusPaymentMethod);
|
||||||
|
const capabilityState = typeof resolveCurrentFlowCapabilities === 'function'
|
||||||
|
? resolveCurrentFlowCapabilities({
|
||||||
|
...state,
|
||||||
|
activeFlowId: requestedActiveFlowId,
|
||||||
|
flowId: requestedActiveFlowId,
|
||||||
|
plusModeEnabled,
|
||||||
|
plusPaymentMethod,
|
||||||
|
signupMethod: requestedSignupMethod,
|
||||||
|
}, {
|
||||||
|
activeFlowId: requestedActiveFlowId,
|
||||||
|
panelMode: state?.panelMode,
|
||||||
|
signupMethod: requestedSignupMethod,
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
const stepDefinitionOptions = capabilityState?.stepDefinitionOptions || {};
|
||||||
|
const resolvedActiveFlowId = String(stepDefinitionOptions.activeFlowId || requestedActiveFlowId).trim().toLowerCase() || defaultFlowId;
|
||||||
|
const resolvedSignupMethod = normalizeSignupMethod(
|
||||||
|
stepDefinitionOptions.signupMethod
|
||||||
|
|| capabilityState?.effectiveSignupMethod
|
||||||
|
|| requestedSignupMethod
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeFlowId: resolvedActiveFlowId,
|
||||||
|
flowId: resolvedActiveFlowId,
|
||||||
|
panelMode: stepDefinitionOptions.panelMode || capabilityState?.effectivePanelMode || state?.panelMode,
|
||||||
|
targetId: stepDefinitionOptions.targetId || capabilityState?.effectiveTargetId || state?.targetId,
|
||||||
|
plusModeEnabled: stepDefinitionOptions.plusModeEnabled === undefined
|
||||||
|
? plusModeEnabled
|
||||||
|
: Boolean(stepDefinitionOptions.plusModeEnabled),
|
||||||
|
plusPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(
|
||||||
|
stepDefinitionOptions.plusAccountAccessStrategy
|
||||||
|
?? capabilityState?.effectivePlusAccountAccessStrategy
|
||||||
|
?? state?.plusAccountAccessStrategy
|
||||||
|
),
|
||||||
|
signupMethod: resolvedSignupMethod,
|
||||||
|
resolvedSignupMethod: resolvedSignupMethod,
|
||||||
|
phoneSignupReloginAfterBindEmailEnabled: Boolean(state?.phoneSignupReloginAfterBindEmailEnabled),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function getStepDefinitionsForState(state = {}) {
|
function getStepDefinitionsForState(state = {}) {
|
||||||
|
const resolvedState = buildResolvedStepDefinitionState(state);
|
||||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||||
if (rootScope.MultiPageStepDefinitions?.getSteps) {
|
if (rootScope.MultiPageStepDefinitions?.getSteps) {
|
||||||
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID === 'string' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID === 'string' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
||||||
const activeFlowId = String(state?.activeFlowId || '').trim().toLowerCase() || defaultFlowId;
|
const activeFlowId = String(resolvedState?.activeFlowId || '').trim().toLowerCase() || defaultFlowId;
|
||||||
const definitions = rootScope.MultiPageStepDefinitions.getSteps({
|
const definitions = rootScope.MultiPageStepDefinitions.getSteps({
|
||||||
activeFlowId,
|
activeFlowId,
|
||||||
plusModeEnabled: isPlusModeState(state),
|
plusModeEnabled: Boolean(resolvedState?.plusModeEnabled),
|
||||||
plusPaymentMethod: normalizePlusPaymentMethod(state?.plusPaymentMethod),
|
plusPaymentMethod: normalizePlusPaymentMethod(resolvedState?.plusPaymentMethod),
|
||||||
signupMethod: getSignupMethodForStepDefinitions(state),
|
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(resolvedState?.plusAccountAccessStrategy),
|
||||||
phoneSignupReloginAfterBindEmailEnabled: Boolean(state?.phoneSignupReloginAfterBindEmailEnabled),
|
signupMethod: getSignupMethodForStepDefinitions(resolvedState),
|
||||||
|
phoneSignupReloginAfterBindEmailEnabled: Boolean(resolvedState?.phoneSignupReloginAfterBindEmailEnabled),
|
||||||
});
|
});
|
||||||
if (Array.isArray(definitions)) {
|
if (Array.isArray(definitions)) {
|
||||||
return definitions;
|
return definitions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const activeFlowId = String(state?.activeFlowId || '').trim().toLowerCase();
|
const activeFlowId = String(resolvedState?.activeFlowId || '').trim().toLowerCase();
|
||||||
if (activeFlowId && activeFlowId !== DEFAULT_ACTIVE_FLOW_ID) {
|
if (activeFlowId && activeFlowId !== DEFAULT_ACTIVE_FLOW_ID) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (!isPlusModeState(state)) {
|
if (!Boolean(resolvedState?.plusModeEnabled)) {
|
||||||
return NORMAL_STEP_DEFINITIONS;
|
return NORMAL_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
const paymentMethod = normalizePlusPaymentMethod(state?.plusPaymentMethod);
|
const paymentMethod = normalizePlusPaymentMethod(resolvedState?.plusPaymentMethod);
|
||||||
|
const signupMethod = getSignupMethodForStepDefinitions(resolvedState);
|
||||||
|
const plusAccountAccessStrategy = normalizePlusAccountAccessStrategy(resolvedState?.plusAccountAccessStrategy);
|
||||||
if (paymentMethod === PLUS_PAYMENT_METHOD_GPC_HELPER) {
|
if (paymentMethod === PLUS_PAYMENT_METHOD_GPC_HELPER) {
|
||||||
|
if (
|
||||||
|
signupMethod === SIGNUP_METHOD_EMAIL
|
||||||
|
&& plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
) {
|
||||||
|
return PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||||
|
}
|
||||||
return PLUS_GPC_STEP_DEFINITIONS;
|
return PLUS_GPC_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
return paymentMethod === PLUS_PAYMENT_METHOD_GOPAY ? PLUS_GOPAY_STEP_DEFINITIONS : PLUS_PAYPAL_STEP_DEFINITIONS;
|
if (paymentMethod === PLUS_PAYMENT_METHOD_GOPAY) {
|
||||||
|
if (
|
||||||
|
signupMethod === SIGNUP_METHOD_EMAIL
|
||||||
|
&& plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
) {
|
||||||
|
return PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||||
|
}
|
||||||
|
return PLUS_GOPAY_STEP_DEFINITIONS;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
signupMethod === SIGNUP_METHOD_EMAIL
|
||||||
|
&& plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
) {
|
||||||
|
return PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||||
|
}
|
||||||
|
return PLUS_PAYPAL_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStepIdsForState(state = {}) {
|
function getStepIdsForState(state = {}) {
|
||||||
@@ -806,17 +904,18 @@ function getStepIdByKeyForState(stepKey, state = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getNodeDefinitionsForState(state = {}) {
|
function getNodeDefinitionsForState(state = {}) {
|
||||||
|
const resolvedState = buildResolvedStepDefinitionState(state);
|
||||||
if (workflowEngine?.getNodesForState) {
|
if (workflowEngine?.getNodesForState) {
|
||||||
return workflowEngine.getNodesForState(state);
|
return workflowEngine.getNodesForState(resolvedState);
|
||||||
}
|
}
|
||||||
if (self.MultiPageStepDefinitions?.getNodes) {
|
if (self.MultiPageStepDefinitions?.getNodes) {
|
||||||
return self.MultiPageStepDefinitions.getNodes({
|
return self.MultiPageStepDefinitions.getNodes({
|
||||||
...state,
|
...resolvedState,
|
||||||
activeFlowId: state?.activeFlowId || state?.flowId || DEFAULT_ACTIVE_FLOW_ID,
|
activeFlowId: resolvedState?.activeFlowId || resolvedState?.flowId || DEFAULT_ACTIVE_FLOW_ID,
|
||||||
flowId: state?.flowId || state?.activeFlowId || DEFAULT_ACTIVE_FLOW_ID,
|
flowId: resolvedState?.flowId || resolvedState?.activeFlowId || DEFAULT_ACTIVE_FLOW_ID,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return getStepDefinitionsForState(state)
|
return getStepDefinitionsForState(resolvedState)
|
||||||
.map((definition) => ({
|
.map((definition) => ({
|
||||||
nodeId: String(definition?.key || '').trim(),
|
nodeId: String(definition?.key || '').trim(),
|
||||||
displayOrder: Number.isFinite(Number(definition?.id)) ? Number(definition.id) : Number(definition?.order),
|
displayOrder: Number.isFinite(Number(definition?.id)) ? Number(definition.id) : Number(definition?.order),
|
||||||
@@ -827,19 +926,21 @@ function getNodeDefinitionsForState(state = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getNodeIdsForState(state = {}) {
|
function getNodeIdsForState(state = {}) {
|
||||||
|
const resolvedState = buildResolvedStepDefinitionState(state);
|
||||||
if (workflowEngine?.getNodeIdsForState) {
|
if (workflowEngine?.getNodeIdsForState) {
|
||||||
return workflowEngine.getNodeIdsForState(state);
|
return workflowEngine.getNodeIdsForState(resolvedState);
|
||||||
}
|
}
|
||||||
return getNodeDefinitionsForState(state).map((definition) => definition.nodeId).filter(Boolean);
|
return getNodeDefinitionsForState(resolvedState).map((definition) => definition.nodeId).filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeDefinitionForState(nodeId, state = {}) {
|
function getNodeDefinitionForState(nodeId, state = {}) {
|
||||||
const normalizedNodeId = String(nodeId || '').trim();
|
const normalizedNodeId = String(nodeId || '').trim();
|
||||||
if (!normalizedNodeId) return null;
|
if (!normalizedNodeId) return null;
|
||||||
|
const resolvedState = buildResolvedStepDefinitionState(state);
|
||||||
if (workflowEngine?.getNodeById) {
|
if (workflowEngine?.getNodeById) {
|
||||||
return workflowEngine.getNodeById(normalizedNodeId, state);
|
return workflowEngine.getNodeById(normalizedNodeId, resolvedState);
|
||||||
}
|
}
|
||||||
return getNodeDefinitionsForState(state).find((definition) => definition.nodeId === normalizedNodeId) || null;
|
return getNodeDefinitionsForState(resolvedState).find((definition) => definition.nodeId === normalizedNodeId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLastNodeIdForState(state = {}) {
|
function getLastNodeIdForState(state = {}) {
|
||||||
@@ -947,6 +1048,7 @@ const PERSISTED_SETTING_DEFAULTS = {
|
|||||||
customPassword: '',
|
customPassword: '',
|
||||||
plusModeEnabled: false,
|
plusModeEnabled: false,
|
||||||
plusPaymentMethod: DEFAULT_PLUS_PAYMENT_METHOD,
|
plusPaymentMethod: DEFAULT_PLUS_PAYMENT_METHOD,
|
||||||
|
plusAccountAccessStrategy: 'oauth',
|
||||||
paypalEmail: '',
|
paypalEmail: '',
|
||||||
paypalPassword: '',
|
paypalPassword: '',
|
||||||
currentPayPalAccountId: '',
|
currentPayPalAccountId: '',
|
||||||
@@ -1120,6 +1222,7 @@ const SETTINGS_SCHEMA_VIEW_KEYS = Object.freeze([
|
|||||||
'phoneSignupReloginAfterBindEmailEnabled',
|
'phoneSignupReloginAfterBindEmailEnabled',
|
||||||
'plusModeEnabled',
|
'plusModeEnabled',
|
||||||
'plusPaymentMethod',
|
'plusPaymentMethod',
|
||||||
|
'plusAccountAccessStrategy',
|
||||||
'mailProvider',
|
'mailProvider',
|
||||||
'ipProxyEnabled',
|
'ipProxyEnabled',
|
||||||
'ipProxyService',
|
'ipProxyService',
|
||||||
@@ -1693,6 +1796,13 @@ function normalizePlusPaymentMethod(value = '') {
|
|||||||
return normalized === PLUS_PAYMENT_METHOD_GOPAY ? PLUS_PAYMENT_METHOD_GOPAY : PLUS_PAYMENT_METHOD_PAYPAL;
|
return normalized === PLUS_PAYMENT_METHOD_GOPAY ? PLUS_PAYMENT_METHOD_GOPAY : PLUS_PAYMENT_METHOD_PAYPAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePlusAccountAccessStrategy(value = '') {
|
||||||
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
|
return normalized === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
: PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeFiveSimCountryId(value, fallback = FIVE_SIM_COUNTRY_ID) {
|
function normalizeFiveSimCountryId(value, fallback = FIVE_SIM_COUNTRY_ID) {
|
||||||
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
const rootScope = typeof self !== 'undefined' ? self : globalThis;
|
||||||
const rawNormalized = rootScope.PhoneSmsFiveSimProvider?.normalizeFiveSimCountryId
|
const rawNormalized = rootScope.PhoneSmsFiveSimProvider?.normalizeFiveSimCountryId
|
||||||
@@ -2866,6 +2976,10 @@ function normalizePersistentSettingValue(key, value) {
|
|||||||
return normalizeSignupMethod(value);
|
return normalizeSignupMethod(value);
|
||||||
case 'plusPaymentMethod':
|
case 'plusPaymentMethod':
|
||||||
return normalizePlusPaymentMethod(value);
|
return normalizePlusPaymentMethod(value);
|
||||||
|
case 'plusAccountAccessStrategy':
|
||||||
|
return String(value || '').trim().toLowerCase() === 'sub2api_codex_session'
|
||||||
|
? 'sub2api_codex_session'
|
||||||
|
: 'oauth';
|
||||||
case 'paypalEmail':
|
case 'paypalEmail':
|
||||||
return String(value || '').trim();
|
return String(value || '').trim();
|
||||||
case 'paypalPassword':
|
case 'paypalPassword':
|
||||||
@@ -10241,6 +10355,7 @@ const AUTO_RUN_BACKGROUND_COMPLETED_STEP_KEYS = new Set([
|
|||||||
'plus-checkout-billing',
|
'plus-checkout-billing',
|
||||||
'paypal-approve',
|
'paypal-approve',
|
||||||
'plus-checkout-return',
|
'plus-checkout-return',
|
||||||
|
'sub2api-session-import',
|
||||||
'oauth-login',
|
'oauth-login',
|
||||||
'fetch-login-code',
|
'fetch-login-code',
|
||||||
'post-login-phone-verification',
|
'post-login-phone-verification',
|
||||||
@@ -11339,6 +11454,7 @@ const AUTO_RUN_NODE_DELAYS = Object.freeze({
|
|||||||
'gopay-subscription-confirm': 2000,
|
'gopay-subscription-confirm': 2000,
|
||||||
'paypal-approve': 2000,
|
'paypal-approve': 2000,
|
||||||
'plus-checkout-return': 1000,
|
'plus-checkout-return': 1000,
|
||||||
|
'sub2api-session-import': 0,
|
||||||
'oauth-login': 2000,
|
'oauth-login': 2000,
|
||||||
'fetch-login-code': 2000,
|
'fetch-login-code': 2000,
|
||||||
'confirm-oauth': 1000,
|
'confirm-oauth': 1000,
|
||||||
@@ -13096,6 +13212,7 @@ const goPayManualConfirmExecutor = self.MultiPageBackgroundGoPayManualConfirm?.c
|
|||||||
broadcastDataUpdate,
|
broadcastDataUpdate,
|
||||||
chrome,
|
chrome,
|
||||||
getTabId,
|
getTabId,
|
||||||
|
getNodeIdsForState,
|
||||||
isTabAlive,
|
isTabAlive,
|
||||||
registerTab,
|
registerTab,
|
||||||
createAutomationTab,
|
createAutomationTab,
|
||||||
@@ -13143,6 +13260,21 @@ const plusReturnConfirmExecutor = self.MultiPageBackgroundPlusReturnConfirm?.cre
|
|||||||
sleepWithStop,
|
sleepWithStop,
|
||||||
waitForTabUrlMatchUntilStopped,
|
waitForTabUrlMatchUntilStopped,
|
||||||
});
|
});
|
||||||
|
const sub2ApiSessionImportExecutor = self.MultiPageBackgroundSub2ApiSessionImport?.createSub2ApiSessionImportExecutor({
|
||||||
|
addLog,
|
||||||
|
chrome,
|
||||||
|
completeNodeFromBackground,
|
||||||
|
ensureContentScriptReadyOnTabUntilStopped,
|
||||||
|
getTabId,
|
||||||
|
isTabAlive,
|
||||||
|
normalizeSub2ApiUrl,
|
||||||
|
registerTab,
|
||||||
|
sendTabMessageUntilStopped,
|
||||||
|
sleepWithStop,
|
||||||
|
throwIfStopped,
|
||||||
|
waitForTabCompleteUntilStopped,
|
||||||
|
DEFAULT_SUB2API_GROUP_NAME,
|
||||||
|
});
|
||||||
const kiroRegisterRunner = self.MultiPageBackgroundKiroRegisterRunner?.createKiroRegisterRunner({
|
const kiroRegisterRunner = self.MultiPageBackgroundKiroRegisterRunner?.createKiroRegisterRunner({
|
||||||
addLog,
|
addLog,
|
||||||
chrome,
|
chrome,
|
||||||
@@ -13290,6 +13422,7 @@ const stepExecutorsByKey = {
|
|||||||
? goPayApproveExecutor.executeGoPayApprove(state)
|
? goPayApproveExecutor.executeGoPayApprove(state)
|
||||||
: payPalApproveExecutor.executePayPalApprove(state),
|
: payPalApproveExecutor.executePayPalApprove(state),
|
||||||
'plus-checkout-return': (state) => plusReturnConfirmExecutor.executePlusReturnConfirm(state),
|
'plus-checkout-return': (state) => plusReturnConfirmExecutor.executePlusReturnConfirm(state),
|
||||||
|
'sub2api-session-import': (state) => sub2ApiSessionImportExecutor.executeSub2ApiSessionImport(state),
|
||||||
'oauth-login': (state) => step7Executor.executeStep7(state),
|
'oauth-login': (state) => step7Executor.executeStep7(state),
|
||||||
'fetch-login-code': (state) => step8Executor.executeStep8(state),
|
'fetch-login-code': (state) => step8Executor.executeStep8(state),
|
||||||
'post-login-phone-verification': (state) => step8Executor.executePostLoginPhoneVerification(state),
|
'post-login-phone-verification': (state) => step8Executor.executePostLoginPhoneVerification(state),
|
||||||
@@ -13956,6 +14089,7 @@ async function getPostStep6AutoRestartDecision(step, error) {
|
|||||||
const errorMessage = getErrorMessage(error);
|
const errorMessage = getErrorMessage(error);
|
||||||
const shouldForceRestartFromStep7 = /restart step 7 with a new number/i.test(errorMessage);
|
const shouldForceRestartFromStep7 = /restart step 7 with a new number/i.test(errorMessage);
|
||||||
const latestState = await getState();
|
const latestState = await getState();
|
||||||
|
const explicitAuthChainStartStep = findStepIdByKeyForState('oauth-login', latestState);
|
||||||
const authChainStartStep = typeof getAuthChainStartStepId === 'function'
|
const authChainStartStep = typeof getAuthChainStartStepId === 'function'
|
||||||
? getAuthChainStartStepId(latestState)
|
? getAuthChainStartStepId(latestState)
|
||||||
: FINAL_OAUTH_CHAIN_START_STEP;
|
: FINAL_OAUTH_CHAIN_START_STEP;
|
||||||
@@ -13963,6 +14097,20 @@ async function getPostStep6AutoRestartDecision(step, error) {
|
|||||||
? getLastStepIdForState(latestState)
|
? getLastStepIdForState(latestState)
|
||||||
: (typeof LAST_STEP_ID === 'number' ? LAST_STEP_ID : 10);
|
: (typeof LAST_STEP_ID === 'number' ? LAST_STEP_ID : 10);
|
||||||
const currentNodeKey = resolveStepKey(normalizedStep, latestState);
|
const currentNodeKey = resolveStepKey(normalizedStep, latestState);
|
||||||
|
const currentNodeIsAuthChain = typeof isAuthChainNode === 'function'
|
||||||
|
? isAuthChainNode(currentNodeKey)
|
||||||
|
: [
|
||||||
|
'oauth-login',
|
||||||
|
'fetch-login-code',
|
||||||
|
'post-login-phone-verification',
|
||||||
|
'bind-email',
|
||||||
|
'fetch-bind-email-code',
|
||||||
|
'relogin-bound-email',
|
||||||
|
'fetch-bound-email-login-code',
|
||||||
|
'post-bound-email-phone-verification',
|
||||||
|
'confirm-oauth',
|
||||||
|
'platform-verify',
|
||||||
|
].includes(currentNodeKey);
|
||||||
const confirmOauthStep = findStepIdByKeyForState('confirm-oauth', latestState);
|
const confirmOauthStep = findStepIdByKeyForState('confirm-oauth', latestState);
|
||||||
const boundEmailReloginStep = findStepIdByKeyForState('relogin-bound-email', latestState);
|
const boundEmailReloginStep = findStepIdByKeyForState('relogin-bound-email', latestState);
|
||||||
const isBoundEmailReloginTailStep = [
|
const isBoundEmailReloginTailStep = [
|
||||||
@@ -13991,6 +14139,17 @@ async function getPostStep6AutoRestartDecision(step, error) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(explicitAuthChainStartStep) || explicitAuthChainStartStep <= 0 || !currentNodeIsAuthChain) {
|
||||||
|
return {
|
||||||
|
shouldRestart: false,
|
||||||
|
blockedByAddPhone: false,
|
||||||
|
forcedByPhoneVerificationTimeout: false,
|
||||||
|
restartStep: authChainStartStep,
|
||||||
|
errorMessage,
|
||||||
|
authState: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (!Number.isFinite(normalizedStep) || normalizedStep < authChainStartStep || normalizedStep > lastStepId) {
|
if (!Number.isFinite(normalizedStep) || normalizedStep < authChainStartStep || normalizedStep > lastStepId) {
|
||||||
return {
|
return {
|
||||||
shouldRestart: false,
|
shouldRestart: false,
|
||||||
|
|||||||
@@ -592,6 +592,18 @@
|
|||||||
return method === 'gopay' ? 'GoPay' : 'PayPal';
|
return method === 'gopay' ? 'GoPay' : 'PayPal';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePlusAccountAccessStrategyForDisplay(value = '') {
|
||||||
|
return String(value || '').trim().toLowerCase() === 'sub2api_codex_session'
|
||||||
|
? 'sub2api_codex_session'
|
||||||
|
: 'oauth';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlusAccountAccessStrategyLabel(value = '') {
|
||||||
|
return normalizePlusAccountAccessStrategyForDisplay(value) === 'sub2api_codex_session'
|
||||||
|
? '导入当前 ChatGPT 会话到 SUB2API'
|
||||||
|
: 'OAuth';
|
||||||
|
}
|
||||||
|
|
||||||
async function handlePlatformVerifyStepData(payload) {
|
async function handlePlatformVerifyStepData(payload) {
|
||||||
if (payload.localhostUrl) {
|
if (payload.localhostUrl) {
|
||||||
await closeLocalhostCallbackTabs(payload.localhostUrl);
|
await closeLocalhostCallbackTabs(payload.localhostUrl);
|
||||||
@@ -1421,6 +1433,9 @@
|
|||||||
const plusPaymentChanged = Object.prototype.hasOwnProperty.call(updates, 'plusPaymentMethod')
|
const plusPaymentChanged = Object.prototype.hasOwnProperty.call(updates, 'plusPaymentMethod')
|
||||||
&& normalizePlusPaymentMethodForDisplay(currentState?.plusPaymentMethod || 'paypal')
|
&& normalizePlusPaymentMethodForDisplay(currentState?.plusPaymentMethod || 'paypal')
|
||||||
!== normalizePlusPaymentMethodForDisplay(updates.plusPaymentMethod || 'paypal');
|
!== normalizePlusPaymentMethodForDisplay(updates.plusPaymentMethod || 'paypal');
|
||||||
|
const plusAccountAccessStrategyChanged = Object.prototype.hasOwnProperty.call(updates, 'plusAccountAccessStrategy')
|
||||||
|
&& normalizePlusAccountAccessStrategyForDisplay(currentState?.plusAccountAccessStrategy || 'oauth')
|
||||||
|
!== normalizePlusAccountAccessStrategyForDisplay(updates.plusAccountAccessStrategy || 'oauth');
|
||||||
const phoneSignupReloginAfterBindEmailChanged = Object.prototype.hasOwnProperty.call(updates, 'phoneSignupReloginAfterBindEmailEnabled')
|
const phoneSignupReloginAfterBindEmailChanged = Object.prototype.hasOwnProperty.call(updates, 'phoneSignupReloginAfterBindEmailEnabled')
|
||||||
&& Boolean(currentState?.phoneSignupReloginAfterBindEmailEnabled) !== Boolean(updates.phoneSignupReloginAfterBindEmailEnabled);
|
&& Boolean(currentState?.phoneSignupReloginAfterBindEmailEnabled) !== Boolean(updates.phoneSignupReloginAfterBindEmailEnabled);
|
||||||
const nextPlusModeEnabled = Object.prototype.hasOwnProperty.call(updates, 'plusModeEnabled')
|
const nextPlusModeEnabled = Object.prototype.hasOwnProperty.call(updates, 'plusModeEnabled')
|
||||||
@@ -1428,6 +1443,7 @@
|
|||||||
: Boolean(currentState?.plusModeEnabled);
|
: Boolean(currentState?.plusModeEnabled);
|
||||||
const stepModeChanged = modeChanged
|
const stepModeChanged = modeChanged
|
||||||
|| (nextPlusModeEnabled && plusPaymentChanged)
|
|| (nextPlusModeEnabled && plusPaymentChanged)
|
||||||
|
|| (nextPlusModeEnabled && plusAccountAccessStrategyChanged)
|
||||||
|| phoneSignupReloginAfterBindEmailChanged;
|
|| phoneSignupReloginAfterBindEmailChanged;
|
||||||
const oauthFlowTimeoutDisabled = Object.prototype.hasOwnProperty.call(updates, 'oauthFlowTimeoutEnabled')
|
const oauthFlowTimeoutDisabled = Object.prototype.hasOwnProperty.call(updates, 'oauthFlowTimeoutEnabled')
|
||||||
&& updates.oauthFlowTimeoutEnabled === false;
|
&& updates.oauthFlowTimeoutEnabled === false;
|
||||||
@@ -1450,11 +1466,45 @@
|
|||||||
? nextHostPreference
|
? nextHostPreference
|
||||||
: '';
|
: '';
|
||||||
}
|
}
|
||||||
if (stepModeChanged && typeof getStepIdsForState === 'function') {
|
const currentNodeIds = typeof getNodeIdsForState === 'function'
|
||||||
const nextStateForSteps = { ...currentState, ...stateUpdates };
|
? getNodeIdsForState(currentState)
|
||||||
const nextNodeIds = typeof getNodeIdsForState === 'function'
|
: (typeof getStepIdsForState === 'function'
|
||||||
? getNodeIdsForState(nextStateForSteps)
|
? getStepIdsForState(currentState).map((stepId) => getStepKeyForState(stepId, currentState)).filter(Boolean)
|
||||||
: getStepIdsForState(nextStateForSteps).map((stepId) => getStepKeyForState(stepId, nextStateForSteps)).filter(Boolean);
|
: []);
|
||||||
|
const nextStateForSteps = { ...currentState, ...stateUpdates };
|
||||||
|
const nextNodeIds = typeof getNodeIdsForState === 'function'
|
||||||
|
? getNodeIdsForState(nextStateForSteps)
|
||||||
|
: (typeof getStepIdsForState === 'function'
|
||||||
|
? getStepIdsForState(nextStateForSteps).map((stepId) => getStepKeyForState(stepId, nextStateForSteps)).filter(Boolean)
|
||||||
|
: []);
|
||||||
|
const nodeTopologyChanged = currentNodeIds.length !== nextNodeIds.length
|
||||||
|
|| currentNodeIds.some((nodeId, index) => nodeId !== nextNodeIds[index]);
|
||||||
|
const shouldRebuildNodeStatuses = stepModeChanged || nodeTopologyChanged;
|
||||||
|
if (shouldRebuildNodeStatuses && nextNodeIds.length > 0) {
|
||||||
|
Object.assign(stateUpdates, {
|
||||||
|
oauthUrl: null,
|
||||||
|
localhostUrl: null,
|
||||||
|
oauthFlowDeadlineAt: null,
|
||||||
|
oauthFlowDeadlineSourceUrl: null,
|
||||||
|
cpaOAuthState: null,
|
||||||
|
cpaManagementOrigin: null,
|
||||||
|
sub2apiSessionId: null,
|
||||||
|
sub2apiOAuthState: null,
|
||||||
|
sub2apiGroupId: null,
|
||||||
|
sub2apiGroupIds: [],
|
||||||
|
sub2apiDraftName: null,
|
||||||
|
sub2apiProxyId: null,
|
||||||
|
codex2apiSessionId: null,
|
||||||
|
codex2apiOAuthState: null,
|
||||||
|
plusManualConfirmationPending: false,
|
||||||
|
plusManualConfirmationRequestId: '',
|
||||||
|
plusManualConfirmationStep: 0,
|
||||||
|
plusManualConfirmationMethod: '',
|
||||||
|
plusManualConfirmationTitle: '',
|
||||||
|
plusManualConfirmationMessage: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (shouldRebuildNodeStatuses && nextNodeIds.length > 0) {
|
||||||
stateUpdates.nodeStatuses = Object.fromEntries(nextNodeIds.map((nodeId) => [nodeId, 'pending']));
|
stateUpdates.nodeStatuses = Object.fromEntries(nextNodeIds.map((nodeId) => [nodeId, 'pending']));
|
||||||
stateUpdates.currentNodeId = '';
|
stateUpdates.currentNodeId = '';
|
||||||
}
|
}
|
||||||
@@ -1510,9 +1560,12 @@
|
|||||||
const selectedPlusPaymentMethod = getPlusPaymentMethodLabel(
|
const selectedPlusPaymentMethod = getPlusPaymentMethodLabel(
|
||||||
stateUpdates.plusPaymentMethod ?? currentState?.plusPaymentMethod ?? 'paypal'
|
stateUpdates.plusPaymentMethod ?? currentState?.plusPaymentMethod ?? 'paypal'
|
||||||
);
|
);
|
||||||
|
const selectedPlusAccountAccessStrategy = getPlusAccountAccessStrategyLabel(
|
||||||
|
stateUpdates.plusAccountAccessStrategy ?? currentState?.plusAccountAccessStrategy ?? 'oauth'
|
||||||
|
);
|
||||||
await addLog(
|
await addLog(
|
||||||
Boolean(updates.plusModeEnabled)
|
Boolean(updates.plusModeEnabled)
|
||||||
? `Plus 模式已开启,已切换为 Plus Checkout 步骤,当前支付方式:${selectedPlusPaymentMethod}。`
|
? `Plus 模式已开启,已切换为 Plus Checkout 步骤,当前支付方式:${selectedPlusPaymentMethod},账号接入策略:${selectedPlusAccountAccessStrategy}。`
|
||||||
: 'Plus 模式已关闭,已恢复普通注册授权步骤。',
|
: 'Plus 模式已关闭,已恢复普通注册授权步骤。',
|
||||||
'info'
|
'info'
|
||||||
);
|
);
|
||||||
@@ -1521,6 +1574,11 @@
|
|||||||
stateUpdates.plusPaymentMethod ?? currentState?.plusPaymentMethod ?? 'paypal'
|
stateUpdates.plusPaymentMethod ?? currentState?.plusPaymentMethod ?? 'paypal'
|
||||||
);
|
);
|
||||||
await addLog(`Plus 支付方式已切换为 ${selectedPlusPaymentMethod},已更新对应的 Plus 步骤。`, 'info');
|
await addLog(`Plus 支付方式已切换为 ${selectedPlusPaymentMethod},已更新对应的 Plus 步骤。`, 'info');
|
||||||
|
} else if (plusAccountAccessStrategyChanged && nextPlusModeEnabled) {
|
||||||
|
const selectedPlusAccountAccessStrategy = getPlusAccountAccessStrategyLabel(
|
||||||
|
stateUpdates.plusAccountAccessStrategy ?? currentState?.plusAccountAccessStrategy ?? 'oauth'
|
||||||
|
);
|
||||||
|
await addLog(`Plus 账号接入策略已切换为 ${selectedPlusAccountAccessStrategy},已更新对应的 Plus 尾链。`, 'info');
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|||||||
@@ -2,8 +2,42 @@
|
|||||||
root.MultiPageBackgroundGoPayManualConfirm = factory();
|
root.MultiPageBackgroundGoPayManualConfirm = factory();
|
||||||
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundGoPayManualConfirmModule() {
|
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundGoPayManualConfirmModule() {
|
||||||
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
const PLUS_CHECKOUT_SOURCE = 'plus-checkout';
|
||||||
|
const GOPAY_CONFIRM_NODE_ID = 'gopay-subscription-confirm';
|
||||||
|
const SUB2API_SESSION_IMPORT_NODE_ID = 'sub2api-session-import';
|
||||||
const DEFAULT_CONFIRM_TITLE = 'GoPay 订阅确认';
|
const DEFAULT_CONFIRM_TITLE = 'GoPay 订阅确认';
|
||||||
const DEFAULT_CONFIRM_MESSAGE = 'GoPay 订阅页已打开。请先手动完成订阅,完成后确认继续 OAuth 登录。';
|
const OAUTH_CONTINUATION_LABEL = 'OAuth 登录';
|
||||||
|
const SUB2API_SESSION_CONTINUATION_LABEL = '导入当前 ChatGPT 会话到 SUB2API';
|
||||||
|
|
||||||
|
function normalizeString(value = '') {
|
||||||
|
return String(value || '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContinuationActionLabel(state = {}, options = {}) {
|
||||||
|
const { getNodeIdsForState = null } = options;
|
||||||
|
if (typeof getNodeIdsForState === 'function') {
|
||||||
|
const nodeIds = getNodeIdsForState(state)
|
||||||
|
.map((nodeId) => normalizeString(nodeId))
|
||||||
|
.filter(Boolean);
|
||||||
|
const currentNodeId = normalizeString(state?.nodeId || GOPAY_CONFIRM_NODE_ID) || GOPAY_CONFIRM_NODE_ID;
|
||||||
|
const currentNodeIndex = nodeIds.indexOf(currentNodeId);
|
||||||
|
const nextNodeId = currentNodeIndex >= 0
|
||||||
|
? normalizeString(nodeIds[currentNodeIndex + 1])
|
||||||
|
: '';
|
||||||
|
|
||||||
|
if (
|
||||||
|
nextNodeId === SUB2API_SESSION_IMPORT_NODE_ID
|
||||||
|
|| (currentNodeIndex < 0 && nodeIds.includes(SUB2API_SESSION_IMPORT_NODE_ID))
|
||||||
|
) {
|
||||||
|
return SUB2API_SESSION_CONTINUATION_LABEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OAUTH_CONTINUATION_LABEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDefaultConfirmMessage(state = {}, options = {}) {
|
||||||
|
const continuationActionLabel = getContinuationActionLabel(state, options);
|
||||||
|
return `GoPay 订阅页已打开。请先手动完成订阅,完成后确认继续${continuationActionLabel}。`;
|
||||||
|
}
|
||||||
|
|
||||||
function createGoPayManualConfirmExecutor(deps = {}) {
|
function createGoPayManualConfirmExecutor(deps = {}) {
|
||||||
const {
|
const {
|
||||||
@@ -12,6 +46,7 @@
|
|||||||
chrome,
|
chrome,
|
||||||
createAutomationTab = null,
|
createAutomationTab = null,
|
||||||
getTabId,
|
getTabId,
|
||||||
|
getNodeIdsForState = null,
|
||||||
isTabAlive,
|
isTabAlive,
|
||||||
registerTab,
|
registerTab,
|
||||||
setState,
|
setState,
|
||||||
@@ -40,7 +75,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkoutUrl = String(state?.plusCheckoutUrl || '').trim();
|
const checkoutUrl = normalizeString(state?.plusCheckoutUrl);
|
||||||
if (!checkoutUrl) {
|
if (!checkoutUrl) {
|
||||||
throw new Error('步骤 7:未检测到 GoPay 订阅页,请先执行步骤 6。');
|
throw new Error('步骤 7:未检测到 GoPay 订阅页,请先执行步骤 6。');
|
||||||
}
|
}
|
||||||
@@ -63,19 +98,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function executeGoPayManualConfirm(state = {}) {
|
async function executeGoPayManualConfirm(state = {}) {
|
||||||
|
const visibleStep = Number(state?.visibleStep) || 7;
|
||||||
const tabId = await resolveCheckoutTabId(state);
|
const tabId = await resolveCheckoutTabId(state);
|
||||||
if (chrome?.tabs?.update && tabId) {
|
if (chrome?.tabs?.update && tabId) {
|
||||||
await chrome.tabs.update(tabId, { active: true }).catch(() => {});
|
await chrome.tabs.update(tabId, { active: true }).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const continuationActionLabel = getContinuationActionLabel(state, { getNodeIdsForState });
|
||||||
const payload = {
|
const payload = {
|
||||||
plusCheckoutTabId: tabId,
|
plusCheckoutTabId: tabId,
|
||||||
plusManualConfirmationPending: true,
|
plusManualConfirmationPending: true,
|
||||||
plusManualConfirmationRequestId: buildRequestId(),
|
plusManualConfirmationRequestId: buildRequestId(),
|
||||||
plusManualConfirmationStep: 7,
|
plusManualConfirmationStep: visibleStep,
|
||||||
plusManualConfirmationMethod: 'gopay',
|
plusManualConfirmationMethod: 'gopay',
|
||||||
plusManualConfirmationTitle: DEFAULT_CONFIRM_TITLE,
|
plusManualConfirmationTitle: DEFAULT_CONFIRM_TITLE,
|
||||||
plusManualConfirmationMessage: DEFAULT_CONFIRM_MESSAGE,
|
plusManualConfirmationMessage: buildDefaultConfirmMessage(state, { getNodeIdsForState }),
|
||||||
};
|
};
|
||||||
|
|
||||||
await setState(payload);
|
await setState(payload);
|
||||||
@@ -83,7 +120,10 @@
|
|||||||
broadcastDataUpdate(payload);
|
broadcastDataUpdate(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
await addLog('步骤 7:正在等待手动完成 GoPay 订阅,确认后继续 OAuth 登录。', 'info');
|
await addLog(
|
||||||
|
`步骤 ${visibleStep}:正在等待手动完成 GoPay 订阅,确认后继续${continuationActionLabel}。`,
|
||||||
|
'info'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
(function attachBackgroundSub2ApiSessionImport(root, factory) {
|
||||||
|
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'];
|
||||||
|
|
||||||
|
function createSub2ApiSessionImportExecutor(deps = {}) {
|
||||||
|
const {
|
||||||
|
addLog: rawAddLog = async () => {},
|
||||||
|
chrome,
|
||||||
|
completeNodeFromBackground,
|
||||||
|
ensureContentScriptReadyOnTabUntilStopped,
|
||||||
|
getTabId,
|
||||||
|
isTabAlive,
|
||||||
|
normalizeSub2ApiUrl = (value) => value,
|
||||||
|
registerTab,
|
||||||
|
sendTabMessageUntilStopped,
|
||||||
|
sleepWithStop = async () => {},
|
||||||
|
throwIfStopped = () => {},
|
||||||
|
waitForTabCompleteUntilStopped = async () => {},
|
||||||
|
DEFAULT_SUB2API_GROUP_NAME = 'codex',
|
||||||
|
} = deps;
|
||||||
|
|
||||||
|
let sub2ApiApi = null;
|
||||||
|
|
||||||
|
function addStepLog(step, message, level = 'info') {
|
||||||
|
return rawAddLog(message, level, {
|
||||||
|
step,
|
||||||
|
stepKey: 'sub2api-session-import',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSub2ApiApi() {
|
||||||
|
if (sub2ApiApi) {
|
||||||
|
return sub2ApiApi;
|
||||||
|
}
|
||||||
|
const factory = deps.createSub2ApiApi
|
||||||
|
|| self.MultiPageBackgroundSub2ApiApi?.createSub2ApiApi;
|
||||||
|
if (typeof factory !== 'function') {
|
||||||
|
throw new Error('SUB2API 接口模块未加载,无法导入当前 ChatGPT 会话。');
|
||||||
|
}
|
||||||
|
sub2ApiApi = factory({
|
||||||
|
addLog: rawAddLog,
|
||||||
|
normalizeSub2ApiUrl,
|
||||||
|
DEFAULT_SUB2API_GROUP_NAME,
|
||||||
|
});
|
||||||
|
return sub2ApiApi;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeString(value = '') {
|
||||||
|
return String(value || '').trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveVisibleStep(state = {}) {
|
||||||
|
const visibleStep = Math.floor(Number(state?.visibleStep) || 0);
|
||||||
|
return visibleStep > 0 ? visibleStep : 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSupportedChatGptSessionUrl(url = '') {
|
||||||
|
try {
|
||||||
|
const parsed = new URL(String(url || ''));
|
||||||
|
if (!/^https?:$/i.test(parsed.protocol)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const hostname = String(parsed.hostname || '').trim().toLowerCase();
|
||||||
|
return /(^|\.)chatgpt\.com$/.test(hostname)
|
||||||
|
|| hostname === 'chat.openai.com'
|
||||||
|
|| /(^|\.)openai\.com$/.test(hostname);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveSessionTabId(state = {}) {
|
||||||
|
const registeredTabId = typeof getTabId === 'function'
|
||||||
|
? await getTabId(PLUS_CHECKOUT_SOURCE)
|
||||||
|
: null;
|
||||||
|
if (registeredTabId && typeof isTabAlive === 'function' && await isTabAlive(PLUS_CHECKOUT_SOURCE)) {
|
||||||
|
return Number(registeredTabId) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storedTabId = Number(state?.plusCheckoutTabId) || 0;
|
||||||
|
if (storedTabId && chrome?.tabs?.get) {
|
||||||
|
const tab = await chrome.tabs.get(storedTabId).catch(() => null);
|
||||||
|
if (tab?.id) {
|
||||||
|
if (typeof registerTab === 'function') {
|
||||||
|
await registerTab(PLUS_CHECKOUT_SOURCE, tab.id);
|
||||||
|
}
|
||||||
|
return tab.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('未找到可读取 ChatGPT 会话的 Plus 标签页,请先完成当前 Plus 支付链路。');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getResolvedSessionTab(tabId, visibleStep) {
|
||||||
|
const tab = await chrome?.tabs?.get?.(tabId).catch(() => null);
|
||||||
|
if (!tab?.id) {
|
||||||
|
throw new Error(`步骤 ${visibleStep}:Plus 会话标签页不存在或已关闭,无法继续导入 SUB2API。`);
|
||||||
|
}
|
||||||
|
if (!isSupportedChatGptSessionUrl(tab.url)) {
|
||||||
|
throw new Error(`步骤 ${visibleStep}:当前标签页不在 ChatGPT / OpenAI 页面,无法读取当前登录会话。`);
|
||||||
|
}
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readCurrentChatGptSession(tabId, visibleStep) {
|
||||||
|
await waitForTabCompleteUntilStopped(tabId);
|
||||||
|
await sleepWithStop(1000);
|
||||||
|
await ensureContentScriptReadyOnTabUntilStopped(PLUS_CHECKOUT_SOURCE, tabId, {
|
||||||
|
inject: PLUS_CHECKOUT_INJECT_FILES,
|
||||||
|
injectSource: PLUS_CHECKOUT_SOURCE,
|
||||||
|
logMessage: `步骤 ${visibleStep}:正在等待 ChatGPT 会话页完成加载,再继续读取当前登录会话...`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sessionResult = await sendTabMessageUntilStopped(tabId, PLUS_CHECKOUT_SOURCE, {
|
||||||
|
type: 'PLUS_CHECKOUT_GET_STATE',
|
||||||
|
source: 'background',
|
||||||
|
payload: {
|
||||||
|
includeSession: true,
|
||||||
|
includeAccessToken: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (sessionResult?.error) {
|
||||||
|
throw new Error(sessionResult.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = sessionResult?.session && typeof sessionResult.session === 'object' && !Array.isArray(sessionResult.session)
|
||||||
|
? sessionResult.session
|
||||||
|
: null;
|
||||||
|
const accessToken = normalizeString(
|
||||||
|
sessionResult?.accessToken
|
||||||
|
|| session?.accessToken
|
||||||
|
);
|
||||||
|
if (!session && !accessToken) {
|
||||||
|
throw new Error(`步骤 ${visibleStep}:未读取到有效的 ChatGPT 会话或 accessToken,请确认当前标签页仍处于已登录状态。`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
session,
|
||||||
|
accessToken,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function executeSub2ApiSessionImport(state = {}) {
|
||||||
|
throwIfStopped();
|
||||||
|
const visibleStep = resolveVisibleStep(state);
|
||||||
|
const api = getSub2ApiApi();
|
||||||
|
|
||||||
|
await addStepLog(visibleStep, '正在定位当前 Plus 会话页并准备导入 SUB2API...', 'info');
|
||||||
|
const tabId = await resolveSessionTabId(state);
|
||||||
|
const tab = await getResolvedSessionTab(tabId, visibleStep);
|
||||||
|
if (chrome?.tabs?.update) {
|
||||||
|
await chrome.tabs.update(tab.id, { active: true }).catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
await addStepLog(visibleStep, '正在读取当前 ChatGPT 登录会话...', 'info');
|
||||||
|
const sessionState = await readCurrentChatGptSession(tab.id, visibleStep);
|
||||||
|
throwIfStopped();
|
||||||
|
|
||||||
|
const result = await api.importCurrentChatGptSession({
|
||||||
|
...state,
|
||||||
|
session: sessionState.session,
|
||||||
|
accessToken: sessionState.accessToken,
|
||||||
|
}, {
|
||||||
|
visibleStep,
|
||||||
|
logLabel: `步骤 ${visibleStep}`,
|
||||||
|
logOptions: { step: visibleStep, stepKey: 'sub2api-session-import' },
|
||||||
|
timeoutMs: 120000,
|
||||||
|
importTimeoutMs: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
|
await completeNodeFromBackground(state?.nodeId || 'sub2api-session-import', result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
executeSub2ApiSessionImport,
|
||||||
|
isSupportedChatGptSessionUrl,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
createSub2ApiSessionImportExecutor,
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -345,6 +345,83 @@
|
|||||||
return `${prefix}-${stamp}-${random}`;
|
return `${prefix}-${stamp}-${random}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeCodexSessionObject(value) {
|
||||||
|
return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCodexSessionImportContent(session, accessToken = '') {
|
||||||
|
const normalizedAccessToken = normalizeString(accessToken);
|
||||||
|
const sessionObject = normalizeCodexSessionObject(session);
|
||||||
|
|
||||||
|
if (sessionObject) {
|
||||||
|
const contentObject = normalizedAccessToken
|
||||||
|
? {
|
||||||
|
...sessionObject,
|
||||||
|
accessToken: normalizedAccessToken,
|
||||||
|
}
|
||||||
|
: sessionObject;
|
||||||
|
return JSON.stringify(contentObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedAccessToken) {
|
||||||
|
return normalizedAccessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('未读取到可导入的 ChatGPT 会话或 accessToken。');
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveCodexSessionImportExpiresAt(session) {
|
||||||
|
const sessionObject = normalizeCodexSessionObject(session);
|
||||||
|
const expiresValue = normalizeString(sessionObject?.expires);
|
||||||
|
if (!expiresValue) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const expiresAtMs = Date.parse(expiresValue);
|
||||||
|
if (!Number.isFinite(expiresAtMs) || expiresAtMs <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Math.floor(expiresAtMs / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCodexSessionImportMessages(messages) {
|
||||||
|
return (Array.isArray(messages) ? messages : [])
|
||||||
|
.map((item, index) => ({
|
||||||
|
index: Number(item?.index) || index + 1,
|
||||||
|
name: normalizeString(item?.name),
|
||||||
|
message: normalizeString(item?.message),
|
||||||
|
}))
|
||||||
|
.filter((item) => item.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCodexSessionImportResult(result) {
|
||||||
|
return {
|
||||||
|
total: Math.max(0, Number(result?.total) || 0),
|
||||||
|
created: Math.max(0, Number(result?.created) || 0),
|
||||||
|
updated: Math.max(0, Number(result?.updated) || 0),
|
||||||
|
skipped: Math.max(0, Number(result?.skipped) || 0),
|
||||||
|
failed: Math.max(0, Number(result?.failed) || 0),
|
||||||
|
items: Array.isArray(result?.items) ? result.items : [],
|
||||||
|
warnings: normalizeCodexSessionImportMessages(result?.warnings),
|
||||||
|
errors: normalizeCodexSessionImportMessages(result?.errors),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCodexSessionImportSummary(result) {
|
||||||
|
const normalized = normalizeCodexSessionImportResult(result);
|
||||||
|
return `SUB2API 会话导入完成:新建 ${normalized.created},更新 ${normalized.updated},跳过 ${normalized.skipped},失败 ${normalized.failed}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCodexSessionImportFailureMessage(result) {
|
||||||
|
const normalized = normalizeCodexSessionImportResult(result);
|
||||||
|
const detail = normalized.errors.map((item) => item.message).find(Boolean)
|
||||||
|
|| normalized.warnings.map((item) => item.message).find(Boolean)
|
||||||
|
|| normalized.items
|
||||||
|
.map((item) => normalizeString(item?.message))
|
||||||
|
.find(Boolean)
|
||||||
|
|| buildCodexSessionImportSummary(normalized);
|
||||||
|
return detail || 'SUB2API 会话导入失败。';
|
||||||
|
}
|
||||||
|
|
||||||
function parseLocalhostCallback(rawUrl, visibleStep = 10) {
|
function parseLocalhostCallback(rawUrl, visibleStep = 10) {
|
||||||
let parsed;
|
let parsed;
|
||||||
try {
|
try {
|
||||||
@@ -580,14 +657,93 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function importCurrentChatGptSession(state = {}, options = {}) {
|
||||||
|
const logLabel = normalizeString(options.logLabel) || 'SUB2API 会话导入';
|
||||||
|
const session = normalizeCodexSessionObject(state?.session);
|
||||||
|
const accessToken = normalizeString(
|
||||||
|
state?.accessToken
|
||||||
|
|| session?.accessToken
|
||||||
|
);
|
||||||
|
const importContent = buildCodexSessionImportContent(session, accessToken);
|
||||||
|
const importExpiresAt = resolveCodexSessionImportExpiresAt(session);
|
||||||
|
|
||||||
|
await logWithOptions(`${logLabel}:正在通过 SUB2API 管理接口登录并准备导入当前 ChatGPT 会话...`, 'info', options);
|
||||||
|
const { origin, token } = await loginSub2Api(state, options);
|
||||||
|
const groupNames = state.sub2apiGroupName || DEFAULT_SUB2API_GROUP_NAME;
|
||||||
|
const groups = await getGroupsByNames(origin, token, groupNames, options);
|
||||||
|
const groupLabel = groups.map((item) => `${item.name}(${item.id})`).join('、');
|
||||||
|
const proxyPreference = resolveSub2ApiProxyPreference(state);
|
||||||
|
const proxy = proxyPreference ? await resolveSub2ApiProxy(origin, token, proxyPreference, options) : null;
|
||||||
|
const proxyId = normalizeProxyId(proxy?.id);
|
||||||
|
const accountPriority = resolveSub2ApiAccountPriority(state);
|
||||||
|
|
||||||
|
await logWithOptions(`${logLabel}:已登录 SUB2API,使用分组 ${groupLabel}。`, 'info', options);
|
||||||
|
if (proxy) {
|
||||||
|
await logWithOptions(`${logLabel}:已选择 SUB2API 默认代理 ${buildProxyDisplayName(proxy)}。`, 'info', options);
|
||||||
|
} else {
|
||||||
|
await logWithOptions(`${logLabel}:未配置 SUB2API 默认代理,本次将不使用代理。`, 'info', options);
|
||||||
|
}
|
||||||
|
|
||||||
|
const importPayload = {
|
||||||
|
content: importContent,
|
||||||
|
group_ids: groups
|
||||||
|
.map((group) => Number(group?.id))
|
||||||
|
.filter((id) => Number.isFinite(id) && id > 0),
|
||||||
|
priority: accountPriority,
|
||||||
|
auto_pause_on_expired: true,
|
||||||
|
update_existing: true,
|
||||||
|
};
|
||||||
|
if (!importPayload.group_ids.length) {
|
||||||
|
throw new Error('SUB2API 返回的目标分组 ID 无效。');
|
||||||
|
}
|
||||||
|
if (proxyId) {
|
||||||
|
importPayload.proxy_id = proxyId;
|
||||||
|
}
|
||||||
|
if (importExpiresAt) {
|
||||||
|
importPayload.expires_at = importExpiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
await logWithOptions(`${logLabel}:正在导入当前 ChatGPT 会话到 SUB2API...`, 'info', options);
|
||||||
|
const importResult = normalizeCodexSessionImportResult(await requestJson(origin, '/api/v1/admin/accounts/import/codex-session', {
|
||||||
|
method: 'POST',
|
||||||
|
token,
|
||||||
|
timeoutMs: options.importTimeoutMs || options.timeoutMs,
|
||||||
|
body: importPayload,
|
||||||
|
}));
|
||||||
|
|
||||||
|
for (const warning of importResult.warnings) {
|
||||||
|
await logWithOptions(`${logLabel}:${warning.message}`, 'warn', options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (importResult.failed > 0) {
|
||||||
|
throw new Error(getCodexSessionImportFailureMessage(importResult));
|
||||||
|
}
|
||||||
|
if (importResult.created <= 0 && importResult.updated <= 0) {
|
||||||
|
throw new Error(getCodexSessionImportFailureMessage(importResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifiedStatus = buildCodexSessionImportSummary(importResult);
|
||||||
|
await logWithOptions(verifiedStatus, 'ok', options);
|
||||||
|
return {
|
||||||
|
verifiedStatus,
|
||||||
|
sub2apiImportTotal: importResult.total,
|
||||||
|
sub2apiImportCreated: importResult.created,
|
||||||
|
sub2apiImportUpdated: importResult.updated,
|
||||||
|
sub2apiImportSkipped: importResult.skipped,
|
||||||
|
sub2apiImportFailed: importResult.failed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
buildDraftAccountName,
|
buildDraftAccountName,
|
||||||
|
buildCodexSessionImportContent,
|
||||||
buildOpenAiCredentials,
|
buildOpenAiCredentials,
|
||||||
buildOpenAiExtra,
|
buildOpenAiExtra,
|
||||||
buildProxyDisplayName,
|
buildProxyDisplayName,
|
||||||
extractStateFromAuthUrl,
|
extractStateFromAuthUrl,
|
||||||
generateOpenAiAuthUrl,
|
generateOpenAiAuthUrl,
|
||||||
getGroupsByNames,
|
getGroupsByNames,
|
||||||
|
importCurrentChatGptSession,
|
||||||
loginSub2Api,
|
loginSub2Api,
|
||||||
normalizeProxyId,
|
normalizeProxyId,
|
||||||
normalizeRedirectUri,
|
normalizeRedirectUri,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
||||||
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
||||||
const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper';
|
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_PAYMENT_STEP_KEY = 'paypal-approve';
|
const PLUS_PAYMENT_STEP_KEY = 'paypal-approve';
|
||||||
const SIGNUP_METHOD_EMAIL = 'email';
|
const SIGNUP_METHOD_EMAIL = 'email';
|
||||||
const SIGNUP_METHOD_PHONE = 'phone';
|
const SIGNUP_METHOD_PHONE = 'phone';
|
||||||
@@ -92,10 +94,41 @@
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 normalizePlusAccountAccessStrategy(value = '') {
|
||||||
|
return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
: PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldUseSub2ApiSessionImportTail(options = {}, signupMethod = SIGNUP_METHOD_EMAIL) {
|
||||||
|
return signupMethod === SIGNUP_METHOD_EMAIL
|
||||||
|
&& normalizePlusAccountAccessStrategy(options?.plusAccountAccessStrategy)
|
||||||
|
=== PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION;
|
||||||
|
}
|
||||||
|
|
||||||
function createOpenAiSteps(prefixSteps, startId, startOrder, signupMethod = SIGNUP_METHOD_EMAIL, options = {}) {
|
function createOpenAiSteps(prefixSteps, startId, startOrder, signupMethod = SIGNUP_METHOD_EMAIL, options = {}) {
|
||||||
|
const tailSteps = shouldUseSub2ApiSessionImportTail(options, signupMethod)
|
||||||
|
? createSub2ApiSessionImportTail(startId, startOrder)
|
||||||
|
: createOpenAiAuthTail(startId, startOrder, signupMethod, options);
|
||||||
return [
|
return [
|
||||||
...prefixSteps,
|
...prefixSteps,
|
||||||
...createOpenAiAuthTail(startId, startOrder, signupMethod, options),
|
...tailSteps,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,12 +136,33 @@
|
|||||||
const NORMAL_PHONE_STEP_DEFINITIONS = createOpenAiSteps(NORMAL_PREFIX_STEP_DEFINITIONS, 7, 70, SIGNUP_METHOD_PHONE);
|
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 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_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_PHONE_STEP_DEFINITIONS = createOpenAiSteps(PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE);
|
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_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS = createOpenAiSteps(PLUS_PAYPAL_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE, { phoneSignupReloginAfterBindEmailEnabled: true });
|
||||||
const PLUS_GOPAY_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GOPAY_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_EMAIL);
|
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_PHONE_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GOPAY_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE);
|
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_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_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_PHONE_STEP_DEFINITIONS = createOpenAiSteps(PLUS_GPC_PREFIX_STEP_DEFINITIONS, 10, 100, SIGNUP_METHOD_PHONE);
|
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 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 = [
|
const KIRO_STEP_DEFINITIONS = [
|
||||||
@@ -244,12 +298,16 @@
|
|||||||
return NORMAL_STEP_DEFINITIONS;
|
return NORMAL_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
const paymentMethod = normalizePlusPaymentMethod(options?.plusPaymentMethod || options?.paymentMethod);
|
const paymentMethod = normalizePlusPaymentMethod(options?.plusPaymentMethod || options?.paymentMethod);
|
||||||
|
const plusAccountAccessStrategy = normalizePlusAccountAccessStrategy(options?.plusAccountAccessStrategy);
|
||||||
if (paymentMethod === PLUS_PAYMENT_METHOD_GPC_HELPER) {
|
if (paymentMethod === PLUS_PAYMENT_METHOD_GPC_HELPER) {
|
||||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||||
return reloginAfterBindEmail
|
return reloginAfterBindEmail
|
||||||
? PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
? PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||||
: PLUS_GPC_PHONE_STEP_DEFINITIONS;
|
: PLUS_GPC_PHONE_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
|
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||||
|
return PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||||
|
}
|
||||||
return PLUS_GPC_STEP_DEFINITIONS;
|
return PLUS_GPC_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
if (paymentMethod === PLUS_PAYMENT_METHOD_GOPAY) {
|
if (paymentMethod === PLUS_PAYMENT_METHOD_GOPAY) {
|
||||||
@@ -258,6 +316,9 @@
|
|||||||
? PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
? PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||||
: PLUS_GOPAY_PHONE_STEP_DEFINITIONS;
|
: PLUS_GOPAY_PHONE_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
|
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||||
|
return PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||||
|
}
|
||||||
return PLUS_GOPAY_STEP_DEFINITIONS;
|
return PLUS_GOPAY_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
if (signupMethod === SIGNUP_METHOD_PHONE) {
|
||||||
@@ -265,6 +326,9 @@
|
|||||||
? PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
? PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS
|
||||||
: PLUS_PAYPAL_PHONE_STEP_DEFINITIONS;
|
: PLUS_PAYPAL_PHONE_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
|
if (plusAccountAccessStrategy === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION) {
|
||||||
|
return PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS;
|
||||||
|
}
|
||||||
return PLUS_PAYPAL_STEP_DEFINITIONS;
|
return PLUS_PAYPAL_STEP_DEFINITIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,12 +363,15 @@
|
|||||||
...NORMAL_PHONE_STEP_DEFINITIONS,
|
...NORMAL_PHONE_STEP_DEFINITIONS,
|
||||||
...NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
...PLUS_PAYPAL_STEP_DEFINITIONS,
|
...PLUS_PAYPAL_STEP_DEFINITIONS,
|
||||||
|
...PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
...PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
...PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
||||||
...PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
...PLUS_GOPAY_STEP_DEFINITIONS,
|
...PLUS_GOPAY_STEP_DEFINITIONS,
|
||||||
|
...PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
...PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
...PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
||||||
...PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
...PLUS_GPC_STEP_DEFINITIONS,
|
...PLUS_GPC_STEP_DEFINITIONS,
|
||||||
|
...PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
...PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
...PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
||||||
...PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
...PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
]) {
|
]) {
|
||||||
@@ -497,12 +564,15 @@
|
|||||||
NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
NORMAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
PLUS_STEP_DEFINITIONS: PLUS_PAYPAL_STEP_DEFINITIONS,
|
PLUS_STEP_DEFINITIONS: PLUS_PAYPAL_STEP_DEFINITIONS,
|
||||||
PLUS_PAYPAL_STEP_DEFINITIONS,
|
PLUS_PAYPAL_STEP_DEFINITIONS,
|
||||||
|
PLUS_PAYPAL_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
PLUS_PAYPAL_PHONE_STEP_DEFINITIONS,
|
||||||
PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
PLUS_PAYPAL_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
PLUS_GOPAY_STEP_DEFINITIONS,
|
PLUS_GOPAY_STEP_DEFINITIONS,
|
||||||
|
PLUS_GOPAY_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
PLUS_GOPAY_PHONE_STEP_DEFINITIONS,
|
||||||
PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
PLUS_GOPAY_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
PLUS_GPC_STEP_DEFINITIONS,
|
PLUS_GPC_STEP_DEFINITIONS,
|
||||||
|
PLUS_GPC_SUB2API_SESSION_STEP_DEFINITIONS,
|
||||||
PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
PLUS_GPC_PHONE_STEP_DEFINITIONS,
|
||||||
PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
PLUS_GPC_PHONE_BOUND_EMAIL_RELOGIN_STEP_DEFINITIONS,
|
||||||
SIGNUP_METHOD_EMAIL,
|
SIGNUP_METHOD_EMAIL,
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
const DEFAULT_OPENAI_TARGET_ID = flowRegistryApi.DEFAULT_OPENAI_TARGET_ID || 'cpa';
|
const DEFAULT_OPENAI_TARGET_ID = flowRegistryApi.DEFAULT_OPENAI_TARGET_ID || 'cpa';
|
||||||
const SIGNUP_METHOD_EMAIL = 'email';
|
const SIGNUP_METHOD_EMAIL = 'email';
|
||||||
const SIGNUP_METHOD_PHONE = 'phone';
|
const SIGNUP_METHOD_PHONE = 'phone';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
const VALID_OPENAI_TARGET_IDS = Array.isArray(flowRegistryApi.OPENAI_TARGET_IDS)
|
const VALID_OPENAI_TARGET_IDS = Array.isArray(flowRegistryApi.OPENAI_TARGET_IDS)
|
||||||
? flowRegistryApi.OPENAI_TARGET_IDS.slice()
|
? flowRegistryApi.OPENAI_TARGET_IDS.slice()
|
||||||
: ['cpa', 'sub2api', 'codex2api'];
|
: ['cpa', 'sub2api', 'codex2api'];
|
||||||
@@ -50,6 +52,7 @@
|
|||||||
const DEFAULT_TARGET_CAPABILITIES = Object.freeze({
|
const DEFAULT_TARGET_CAPABILITIES = Object.freeze({
|
||||||
supportsPhoneSignup: true,
|
supportsPhoneSignup: true,
|
||||||
requiresPhoneSignupWarning: false,
|
requiresPhoneSignupWarning: false,
|
||||||
|
supportedPlusAccountAccessStrategies: Object.freeze([PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH]),
|
||||||
});
|
});
|
||||||
|
|
||||||
const MODE_SWITCH_RELEVANT_KEYS = Object.freeze([
|
const MODE_SWITCH_RELEVANT_KEYS = Object.freeze([
|
||||||
@@ -59,6 +62,7 @@
|
|||||||
'phoneVerificationEnabled',
|
'phoneVerificationEnabled',
|
||||||
'plusModeEnabled',
|
'plusModeEnabled',
|
||||||
'signupMethod',
|
'signupMethod',
|
||||||
|
'plusAccountAccessStrategy',
|
||||||
'openaiIntegrationTargetId',
|
'openaiIntegrationTargetId',
|
||||||
'kiroTargetId',
|
'kiroTargetId',
|
||||||
]);
|
]);
|
||||||
@@ -67,14 +71,20 @@
|
|||||||
cpa: Object.freeze({
|
cpa: Object.freeze({
|
||||||
supportsPhoneSignup: true,
|
supportsPhoneSignup: true,
|
||||||
requiresPhoneSignupWarning: true,
|
requiresPhoneSignupWarning: true,
|
||||||
|
supportedPlusAccountAccessStrategies: Object.freeze([PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH]),
|
||||||
}),
|
}),
|
||||||
sub2api: Object.freeze({
|
sub2api: Object.freeze({
|
||||||
supportsPhoneSignup: true,
|
supportsPhoneSignup: true,
|
||||||
requiresPhoneSignupWarning: false,
|
requiresPhoneSignupWarning: false,
|
||||||
|
supportedPlusAccountAccessStrategies: Object.freeze([
|
||||||
|
PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH,
|
||||||
|
PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION,
|
||||||
|
]),
|
||||||
}),
|
}),
|
||||||
codex2api: Object.freeze({
|
codex2api: Object.freeze({
|
||||||
supportsPhoneSignup: true,
|
supportsPhoneSignup: true,
|
||||||
requiresPhoneSignupWarning: false,
|
requiresPhoneSignupWarning: false,
|
||||||
|
supportedPlusAccountAccessStrategies: Object.freeze([PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH]),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -116,6 +126,12 @@
|
|||||||
: SIGNUP_METHOD_EMAIL;
|
: SIGNUP_METHOD_EMAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePlusAccountAccessStrategy(value = '') {
|
||||||
|
return String(value || '').trim().toLowerCase() === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
: PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeOpenAiTargetList(values = []) {
|
function normalizeOpenAiTargetList(values = []) {
|
||||||
if (!Array.isArray(values)) {
|
if (!Array.isArray(values)) {
|
||||||
return [];
|
return [];
|
||||||
@@ -336,6 +352,28 @@
|
|||||||
: (effectiveSignupMethods.includes(SIGNUP_METHOD_EMAIL)
|
: (effectiveSignupMethods.includes(SIGNUP_METHOD_EMAIL)
|
||||||
? SIGNUP_METHOD_EMAIL
|
? SIGNUP_METHOD_EMAIL
|
||||||
: effectiveSignupMethods[0]);
|
: effectiveSignupMethods[0]);
|
||||||
|
const requestedPlusAccountAccessStrategy = normalizePlusAccountAccessStrategy(
|
||||||
|
options?.plusAccountAccessStrategy ?? state?.plusAccountAccessStrategy
|
||||||
|
);
|
||||||
|
const availablePlusAccountAccessStrategies = activeFlowId === 'openai'
|
||||||
|
&& Boolean(flowState.supportsPlusMode)
|
||||||
|
&& Boolean(runtimeLocks.plusModeEnabled)
|
||||||
|
&& effectiveSignupMethod === SIGNUP_METHOD_EMAIL
|
||||||
|
? (
|
||||||
|
Array.isArray(targetState.supportedPlusAccountAccessStrategies)
|
||||||
|
&& targetState.supportedPlusAccountAccessStrategies.length > 0
|
||||||
|
? targetState.supportedPlusAccountAccessStrategies.slice()
|
||||||
|
: [PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH]
|
||||||
|
)
|
||||||
|
: [PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH];
|
||||||
|
const effectivePlusAccountAccessStrategy = availablePlusAccountAccessStrategies.includes(requestedPlusAccountAccessStrategy)
|
||||||
|
? requestedPlusAccountAccessStrategy
|
||||||
|
: PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
|
const canEditPlusAccountAccessStrategy = activeFlowId === 'openai'
|
||||||
|
&& Boolean(flowState.supportsPlusMode)
|
||||||
|
&& Boolean(runtimeLocks.plusModeEnabled)
|
||||||
|
&& effectiveSignupMethod === SIGNUP_METHOD_EMAIL
|
||||||
|
&& availablePlusAccountAccessStrategies.length > 1;
|
||||||
const visibleGroupIds = typeof flowRegistryApi.getVisibleGroupIds === 'function'
|
const visibleGroupIds = typeof flowRegistryApi.getVisibleGroupIds === 'function'
|
||||||
&& isRegisteredFlowId(activeFlowId)
|
&& isRegisteredFlowId(activeFlowId)
|
||||||
? flowRegistryApi.getVisibleGroupIds(activeFlowId, effectiveTargetId)
|
? flowRegistryApi.getVisibleGroupIds(activeFlowId, effectiveTargetId)
|
||||||
@@ -348,8 +386,10 @@
|
|||||||
canShowPhoneSettings: activeFlowId === 'openai' && Boolean(flowState.supportsPhoneVerificationSettings),
|
canShowPhoneSettings: activeFlowId === 'openai' && Boolean(flowState.supportsPhoneVerificationSettings),
|
||||||
canShowPlusSettings: activeFlowId === 'openai' && Boolean(flowState.supportsPlusMode),
|
canShowPlusSettings: activeFlowId === 'openai' && Boolean(flowState.supportsPlusMode),
|
||||||
canSwitchFlow: Boolean(flowState.canSwitchFlow),
|
canSwitchFlow: Boolean(flowState.canSwitchFlow),
|
||||||
|
canEditPlusAccountAccessStrategy,
|
||||||
canUsePhoneSignup: canSelectPhoneSignup,
|
canUsePhoneSignup: canSelectPhoneSignup,
|
||||||
canUseSelectedTarget: targetSupported,
|
canUseSelectedTarget: targetSupported,
|
||||||
|
effectivePlusAccountAccessStrategy,
|
||||||
effectivePanelMode: effectiveTargetId,
|
effectivePanelMode: effectiveTargetId,
|
||||||
effectiveSignupMethod,
|
effectiveSignupMethod,
|
||||||
effectiveSignupMethods,
|
effectiveSignupMethods,
|
||||||
@@ -357,9 +397,11 @@
|
|||||||
flowCapabilities: flowState,
|
flowCapabilities: flowState,
|
||||||
panelCapabilities: targetState,
|
panelCapabilities: targetState,
|
||||||
panelMode: effectiveTargetId,
|
panelMode: effectiveTargetId,
|
||||||
|
requestedPlusAccountAccessStrategy,
|
||||||
requestedSignupMethod,
|
requestedSignupMethod,
|
||||||
requestedTargetId,
|
requestedTargetId,
|
||||||
runtimeLocks,
|
runtimeLocks,
|
||||||
|
availablePlusAccountAccessStrategies,
|
||||||
shouldWarnCpaPhoneSignup: effectiveSignupMethod === SIGNUP_METHOD_PHONE
|
shouldWarnCpaPhoneSignup: effectiveSignupMethod === SIGNUP_METHOD_PHONE
|
||||||
&& Boolean(targetState.requiresPhoneSignupWarning),
|
&& Boolean(targetState.requiresPhoneSignupWarning),
|
||||||
stepDefinitionOptions: {
|
stepDefinitionOptions: {
|
||||||
@@ -367,6 +409,7 @@
|
|||||||
integrationTargetId: effectiveTargetId,
|
integrationTargetId: effectiveTargetId,
|
||||||
panelMode: effectiveTargetId,
|
panelMode: effectiveTargetId,
|
||||||
targetId: effectiveTargetId,
|
targetId: effectiveTargetId,
|
||||||
|
plusAccountAccessStrategy: effectivePlusAccountAccessStrategy,
|
||||||
plusModeEnabled: runtimeLocks.plusModeEnabled,
|
plusModeEnabled: runtimeLocks.plusModeEnabled,
|
||||||
signupMethod: effectiveSignupMethod,
|
signupMethod: effectiveSignupMethod,
|
||||||
},
|
},
|
||||||
@@ -556,6 +599,7 @@
|
|||||||
getOpenAiTargetCapabilities,
|
getOpenAiTargetCapabilities,
|
||||||
normalizeFlowId,
|
normalizeFlowId,
|
||||||
normalizeOpenAiTargetId,
|
normalizeOpenAiTargetId,
|
||||||
|
normalizePlusAccountAccessStrategy,
|
||||||
normalizeSignupMethod,
|
normalizeSignupMethod,
|
||||||
resolveSidepanelCapabilities,
|
resolveSidepanelCapabilities,
|
||||||
resolveSignupMethod,
|
resolveSignupMethod,
|
||||||
@@ -572,11 +616,14 @@
|
|||||||
DEFAULT_OPENAI_TARGET_ID,
|
DEFAULT_OPENAI_TARGET_ID,
|
||||||
FLOW_CAPABILITIES,
|
FLOW_CAPABILITIES,
|
||||||
OPENAI_TARGET_CAPABILITIES,
|
OPENAI_TARGET_CAPABILITIES,
|
||||||
|
PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH,
|
||||||
|
PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION,
|
||||||
SIGNUP_METHOD_EMAIL,
|
SIGNUP_METHOD_EMAIL,
|
||||||
SIGNUP_METHOD_PHONE,
|
SIGNUP_METHOD_PHONE,
|
||||||
VALID_OPENAI_TARGET_IDS,
|
VALID_OPENAI_TARGET_IDS,
|
||||||
normalizeFlowId,
|
normalizeFlowId,
|
||||||
normalizeOpenAiTargetId,
|
normalizeOpenAiTargetId,
|
||||||
|
normalizePlusAccountAccessStrategy,
|
||||||
normalizeSignupMethod,
|
normalizeSignupMethod,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -336,7 +336,7 @@
|
|||||||
'openai-plus': {
|
'openai-plus': {
|
||||||
id: 'openai-plus',
|
id: 'openai-plus',
|
||||||
label: 'Plus',
|
label: 'Plus',
|
||||||
rowIds: ['row-plus-mode'],
|
rowIds: ['row-plus-mode', 'row-plus-payment-method', 'row-plus-account-access-strategy'],
|
||||||
},
|
},
|
||||||
'openai-phone': {
|
'openai-phone': {
|
||||||
id: 'openai-phone',
|
id: 'openai-phone',
|
||||||
|
|||||||
@@ -47,6 +47,11 @@
|
|||||||
const normalizeTargetId = typeof flowRegistry.normalizeTargetId === 'function'
|
const normalizeTargetId = typeof flowRegistry.normalizeTargetId === 'function'
|
||||||
? flowRegistry.normalizeTargetId
|
? flowRegistry.normalizeTargetId
|
||||||
: ((_flowId, value = '', fallback = '') => String(value || fallback || '').trim().toLowerCase());
|
: ((_flowId, value = '', fallback = '') => String(value || fallback || '').trim().toLowerCase());
|
||||||
|
const normalizePlusAccountAccessStrategy = (value = '') => (
|
||||||
|
String(value || '').trim().toLowerCase() === 'sub2api_codex_session'
|
||||||
|
? 'sub2api_codex_session'
|
||||||
|
: 'oauth'
|
||||||
|
);
|
||||||
|
|
||||||
function buildDefaultSettingsState() {
|
function buildDefaultSettingsState() {
|
||||||
return {
|
return {
|
||||||
@@ -96,6 +101,7 @@
|
|||||||
plus: {
|
plus: {
|
||||||
plusModeEnabled: false,
|
plusModeEnabled: false,
|
||||||
plusPaymentMethod: 'paypal',
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'oauth',
|
||||||
},
|
},
|
||||||
autoRun: {
|
autoRun: {
|
||||||
stepExecutionRange: {
|
stepExecutionRange: {
|
||||||
@@ -301,6 +307,11 @@
|
|||||||
?? nested?.flows?.openai?.plus?.plusPaymentMethod
|
?? nested?.flows?.openai?.plus?.plusPaymentMethod
|
||||||
?? defaults.flows.openai.plus.plusPaymentMethod
|
?? defaults.flows.openai.plus.plusPaymentMethod
|
||||||
).trim() || defaults.flows.openai.plus.plusPaymentMethod,
|
).trim() || defaults.flows.openai.plus.plusPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(
|
||||||
|
input?.plusAccountAccessStrategy
|
||||||
|
?? nested?.flows?.openai?.plus?.plusAccountAccessStrategy
|
||||||
|
?? defaults.flows.openai.plus.plusAccountAccessStrategy
|
||||||
|
),
|
||||||
},
|
},
|
||||||
autoRun: {
|
autoRun: {
|
||||||
stepExecutionRange: normalizeStepExecutionRangeEntry(
|
stepExecutionRange: normalizeStepExecutionRangeEntry(
|
||||||
@@ -439,6 +450,7 @@
|
|||||||
next.phoneSignupReloginAfterBindEmailEnabled = openaiState.signup.phoneSignupReloginAfterBindEmailEnabled;
|
next.phoneSignupReloginAfterBindEmailEnabled = openaiState.signup.phoneSignupReloginAfterBindEmailEnabled;
|
||||||
next.plusModeEnabled = openaiState.plus.plusModeEnabled;
|
next.plusModeEnabled = openaiState.plus.plusModeEnabled;
|
||||||
next.plusPaymentMethod = openaiState.plus.plusPaymentMethod;
|
next.plusPaymentMethod = openaiState.plus.plusPaymentMethod;
|
||||||
|
next.plusAccountAccessStrategy = openaiState.plus.plusAccountAccessStrategy;
|
||||||
next.mailProvider = normalizedState.services.email.provider;
|
next.mailProvider = normalizedState.services.email.provider;
|
||||||
next.ipProxyEnabled = normalizedState.services.proxy.enabled;
|
next.ipProxyEnabled = normalizedState.services.proxy.enabled;
|
||||||
next.ipProxyService = normalizedState.services.proxy.provider;
|
next.ipProxyService = normalizedState.services.proxy.provider;
|
||||||
|
|||||||
@@ -313,6 +313,16 @@
|
|||||||
<span class="setting-caption" id="plus-payment-method-caption">PayPal 订阅链路</span>
|
<span class="setting-caption" id="plus-payment-method-caption">PayPal 订阅链路</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="data-row" id="row-plus-account-access-strategy" style="display:none;">
|
||||||
|
<span class="data-label">账号接入策略</span>
|
||||||
|
<div class="data-inline">
|
||||||
|
<select id="select-plus-account-access-strategy" class="data-select">
|
||||||
|
<option value="oauth">OAuth</option>
|
||||||
|
<option value="sub2api_codex_session">导入当前 ChatGPT 会话到 SUB2API</option>
|
||||||
|
</select>
|
||||||
|
<span class="setting-caption" id="plus-account-access-strategy-caption">当前来源仅支持 OAuth</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="data-row" id="row-paypal-account" style="display:none;">
|
<div class="data-row" id="row-paypal-account" style="display:none;">
|
||||||
<span class="data-label">PayPal 账号</span>
|
<span class="data-label">PayPal 账号</span>
|
||||||
<div class="data-inline">
|
<div class="data-inline">
|
||||||
|
|||||||
+193
-4
@@ -192,6 +192,9 @@ const rowPlusPaymentMethod = document.getElementById('row-plus-payment-method');
|
|||||||
const selectPlusPaymentMethod = document.getElementById('select-plus-payment-method');
|
const selectPlusPaymentMethod = document.getElementById('select-plus-payment-method');
|
||||||
const btnGpcCardKeyPurchase = document.getElementById('btn-gpc-card-key-purchase');
|
const btnGpcCardKeyPurchase = document.getElementById('btn-gpc-card-key-purchase');
|
||||||
const plusPaymentMethodCaption = document.getElementById('plus-payment-method-caption');
|
const plusPaymentMethodCaption = document.getElementById('plus-payment-method-caption');
|
||||||
|
const rowPlusAccountAccessStrategy = document.getElementById('row-plus-account-access-strategy');
|
||||||
|
const selectPlusAccountAccessStrategy = document.getElementById('select-plus-account-access-strategy');
|
||||||
|
const plusAccountAccessStrategyCaption = document.getElementById('plus-account-access-strategy-caption');
|
||||||
const rowPayPalAccount = document.getElementById('row-paypal-account');
|
const rowPayPalAccount = document.getElementById('row-paypal-account');
|
||||||
const selectPayPalAccount = document.getElementById('select-paypal-account');
|
const selectPayPalAccount = document.getElementById('select-paypal-account');
|
||||||
const payPalAccountPickerRoot = document.getElementById('paypal-account-picker');
|
const payPalAccountPickerRoot = document.getElementById('paypal-account-picker');
|
||||||
@@ -542,6 +545,9 @@ const GPC_HELPER_PORTAL_URL = 'https://gpc.qlhazycoder.top/';
|
|||||||
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
const DEFAULT_PLUS_PAYMENT_METHOD = PLUS_PAYMENT_METHOD_PAYPAL;
|
const DEFAULT_PLUS_PAYMENT_METHOD = PLUS_PAYMENT_METHOD_PAYPAL;
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
const SIGNUP_METHOD_EMAIL = 'email';
|
const SIGNUP_METHOD_EMAIL = 'email';
|
||||||
const SIGNUP_METHOD_PHONE = 'phone';
|
const SIGNUP_METHOD_PHONE = 'phone';
|
||||||
const DEFAULT_SIGNUP_METHOD = SIGNUP_METHOD_EMAIL;
|
const DEFAULT_SIGNUP_METHOD = SIGNUP_METHOD_EMAIL;
|
||||||
@@ -551,6 +557,7 @@ const PHONE_SIGNUP_REUSE_LOCK_TITLE = '手机号注册流程不使用号码复
|
|||||||
let latestState = null;
|
let latestState = null;
|
||||||
let currentPlusModeEnabled = false;
|
let currentPlusModeEnabled = false;
|
||||||
let currentPlusPaymentMethod = DEFAULT_PLUS_PAYMENT_METHOD;
|
let currentPlusPaymentMethod = DEFAULT_PLUS_PAYMENT_METHOD;
|
||||||
|
let currentPlusAccountAccessStrategy = DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY;
|
||||||
let currentSignupMethod = DEFAULT_SIGNUP_METHOD;
|
let currentSignupMethod = DEFAULT_SIGNUP_METHOD;
|
||||||
let currentPhoneSignupReloginAfterBindEmailEnabled = DEFAULT_PHONE_SIGNUP_RELOGIN_AFTER_BIND_EMAIL_ENABLED;
|
let currentPhoneSignupReloginAfterBindEmailEnabled = DEFAULT_PHONE_SIGNUP_RELOGIN_AFTER_BIND_EMAIL_ENABLED;
|
||||||
let currentStepDefinitionFlowId = DEFAULT_ACTIVE_FLOW_ID;
|
let currentStepDefinitionFlowId = DEFAULT_ACTIVE_FLOW_ID;
|
||||||
@@ -573,11 +580,13 @@ let nexSmsCountryMenuSearchKeyword = '';
|
|||||||
const nexSmsCountrySearchTextById = new Map();
|
const nexSmsCountrySearchTextById = new Map();
|
||||||
let stepDefinitions = getStepDefinitionsForMode(false, {
|
let stepDefinitions = getStepDefinitionsForMode(false, {
|
||||||
plusPaymentMethod: currentPlusPaymentMethod,
|
plusPaymentMethod: currentPlusPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: currentPlusAccountAccessStrategy,
|
||||||
signupMethod: currentSignupMethod,
|
signupMethod: currentSignupMethod,
|
||||||
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
||||||
});
|
});
|
||||||
let workflowNodes = getWorkflowNodesForMode(false, {
|
let workflowNodes = getWorkflowNodesForMode(false, {
|
||||||
plusPaymentMethod: currentPlusPaymentMethod,
|
plusPaymentMethod: currentPlusPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: currentPlusAccountAccessStrategy,
|
||||||
signupMethod: currentSignupMethod,
|
signupMethod: currentSignupMethod,
|
||||||
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
||||||
});
|
});
|
||||||
@@ -838,9 +847,13 @@ function initPhoneVerificationSectionExpandedState() {
|
|||||||
function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) {
|
function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) {
|
||||||
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
||||||
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
||||||
|
const defaultStrategy = typeof DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY !== 'undefined' ? DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY : 'oauth';
|
||||||
const rawPaymentMethod = typeof options === 'string'
|
const rawPaymentMethod = typeof options === 'string'
|
||||||
? options
|
? options
|
||||||
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
||||||
|
const rawPlusAccountAccessStrategy = typeof options === 'string'
|
||||||
|
? currentPlusAccountAccessStrategy
|
||||||
|
: (options.plusAccountAccessStrategy || currentPlusAccountAccessStrategy || defaultStrategy);
|
||||||
const rawSignupMethod = typeof options === 'string'
|
const rawSignupMethod = typeof options === 'string'
|
||||||
? currentSignupMethod
|
? currentSignupMethod
|
||||||
: (options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
: (options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
||||||
@@ -854,6 +867,7 @@ function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) {
|
|||||||
activeFlowId: String(activeFlowId || '').trim().toLowerCase() || defaultFlowId,
|
activeFlowId: String(activeFlowId || '').trim().toLowerCase() || defaultFlowId,
|
||||||
plusModeEnabled,
|
plusModeEnabled,
|
||||||
plusPaymentMethod: normalizePlusPaymentMethod(rawPaymentMethod),
|
plusPaymentMethod: normalizePlusPaymentMethod(rawPaymentMethod),
|
||||||
|
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(rawPlusAccountAccessStrategy),
|
||||||
signupMethod: normalizeSignupMethod(rawSignupMethod),
|
signupMethod: normalizeSignupMethod(rawSignupMethod),
|
||||||
phoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled,
|
||||||
}) || [])
|
}) || [])
|
||||||
@@ -868,9 +882,13 @@ function getStepDefinitionsForMode(plusModeEnabled = false, options = {}) {
|
|||||||
function getWorkflowNodesForMode(plusModeEnabled = false, options = {}) {
|
function getWorkflowNodesForMode(plusModeEnabled = false, options = {}) {
|
||||||
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
||||||
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
||||||
|
const defaultStrategy = typeof DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY !== 'undefined' ? DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY : 'oauth';
|
||||||
const rawPaymentMethod = typeof options === 'string'
|
const rawPaymentMethod = typeof options === 'string'
|
||||||
? options
|
? options
|
||||||
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
||||||
|
const rawPlusAccountAccessStrategy = typeof options === 'string'
|
||||||
|
? currentPlusAccountAccessStrategy
|
||||||
|
: (options.plusAccountAccessStrategy || currentPlusAccountAccessStrategy || defaultStrategy);
|
||||||
const rawSignupMethod = typeof options === 'string'
|
const rawSignupMethod = typeof options === 'string'
|
||||||
? currentSignupMethod
|
? currentSignupMethod
|
||||||
: (options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
: (options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
||||||
@@ -884,6 +902,7 @@ function getWorkflowNodesForMode(plusModeEnabled = false, options = {}) {
|
|||||||
activeFlowId: String(activeFlowId || '').trim().toLowerCase() || defaultFlowId,
|
activeFlowId: String(activeFlowId || '').trim().toLowerCase() || defaultFlowId,
|
||||||
plusModeEnabled,
|
plusModeEnabled,
|
||||||
plusPaymentMethod: normalizePlusPaymentMethod(rawPaymentMethod),
|
plusPaymentMethod: normalizePlusPaymentMethod(rawPaymentMethod),
|
||||||
|
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(rawPlusAccountAccessStrategy),
|
||||||
signupMethod: normalizeSignupMethod(rawSignupMethod),
|
signupMethod: normalizeSignupMethod(rawSignupMethod),
|
||||||
phoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled,
|
||||||
});
|
});
|
||||||
@@ -940,9 +959,13 @@ function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) {
|
|||||||
currentPlusModeEnabled = Boolean(plusModeEnabled);
|
currentPlusModeEnabled = Boolean(plusModeEnabled);
|
||||||
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
||||||
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
||||||
|
const defaultStrategy = typeof DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY !== 'undefined' ? DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY : 'oauth';
|
||||||
const rawPaymentMethod = typeof options === 'string'
|
const rawPaymentMethod = typeof options === 'string'
|
||||||
? options
|
? options
|
||||||
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
: (options.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
||||||
|
const rawPlusAccountAccessStrategy = typeof options === 'string'
|
||||||
|
? currentPlusAccountAccessStrategy
|
||||||
|
: (options.plusAccountAccessStrategy || currentPlusAccountAccessStrategy || defaultStrategy);
|
||||||
const rawSignupMethod = typeof options === 'string'
|
const rawSignupMethod = typeof options === 'string'
|
||||||
? currentSignupMethod
|
? currentSignupMethod
|
||||||
: (options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
: (options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
||||||
@@ -950,6 +973,7 @@ function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) {
|
|||||||
? currentPhoneSignupReloginAfterBindEmailEnabled
|
? currentPhoneSignupReloginAfterBindEmailEnabled
|
||||||
: Boolean(options.phoneSignupReloginAfterBindEmailEnabled ?? currentPhoneSignupReloginAfterBindEmailEnabled);
|
: Boolean(options.phoneSignupReloginAfterBindEmailEnabled ?? currentPhoneSignupReloginAfterBindEmailEnabled);
|
||||||
currentPlusPaymentMethod = normalizePlusPaymentMethod(rawPaymentMethod);
|
currentPlusPaymentMethod = normalizePlusPaymentMethod(rawPaymentMethod);
|
||||||
|
currentPlusAccountAccessStrategy = normalizePlusAccountAccessStrategy(rawPlusAccountAccessStrategy);
|
||||||
currentSignupMethod = normalizeSignupMethod(rawSignupMethod);
|
currentSignupMethod = normalizeSignupMethod(rawSignupMethod);
|
||||||
currentPhoneSignupReloginAfterBindEmailEnabled = phoneSignupReloginAfterBindEmailEnabled;
|
currentPhoneSignupReloginAfterBindEmailEnabled = phoneSignupReloginAfterBindEmailEnabled;
|
||||||
const nextActiveFlowId = String(
|
const nextActiveFlowId = String(
|
||||||
@@ -963,6 +987,7 @@ function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) {
|
|||||||
stepDefinitions = getStepDefinitionsForMode(currentPlusModeEnabled, {
|
stepDefinitions = getStepDefinitionsForMode(currentPlusModeEnabled, {
|
||||||
activeFlowId: nextActiveFlowId,
|
activeFlowId: nextActiveFlowId,
|
||||||
plusPaymentMethod: currentPlusPaymentMethod,
|
plusPaymentMethod: currentPlusPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: currentPlusAccountAccessStrategy,
|
||||||
signupMethod: currentSignupMethod,
|
signupMethod: currentSignupMethod,
|
||||||
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
||||||
});
|
});
|
||||||
@@ -970,6 +995,7 @@ function rebuildStepDefinitionState(plusModeEnabled = false, options = {}) {
|
|||||||
? getWorkflowNodesForMode(currentPlusModeEnabled, {
|
? getWorkflowNodesForMode(currentPlusModeEnabled, {
|
||||||
activeFlowId: nextActiveFlowId,
|
activeFlowId: nextActiveFlowId,
|
||||||
plusPaymentMethod: currentPlusPaymentMethod,
|
plusPaymentMethod: currentPlusPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: currentPlusAccountAccessStrategy,
|
||||||
signupMethod: currentSignupMethod,
|
signupMethod: currentSignupMethod,
|
||||||
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled: currentPhoneSignupReloginAfterBindEmailEnabled,
|
||||||
})
|
})
|
||||||
@@ -1899,6 +1925,19 @@ async function openConfirmModalWithOption({
|
|||||||
|
|
||||||
async function openPlusManualConfirmationDialog(options = {}) {
|
async function openPlusManualConfirmationDialog(options = {}) {
|
||||||
const method = String(options.method || '').trim().toLowerCase();
|
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 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'
|
||||||
|
&& signupMethod === 'email'
|
||||||
|
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||||
|
const continuationActionLabel = useSub2ApiSessionImport
|
||||||
|
? '导入当前 ChatGPT 会话到 SUB2API'
|
||||||
|
: 'OAuth 登录';
|
||||||
const title = String(options.title || '').trim() || (method === 'gopay' ? 'GoPay 订阅确认' : '手动确认');
|
const title = String(options.title || '').trim() || (method === 'gopay' ? 'GoPay 订阅确认' : '手动确认');
|
||||||
const message = String(options.message || '').trim()
|
const message = String(options.message || '').trim()
|
||||||
|| (method === 'gopay'
|
|| (method === 'gopay'
|
||||||
@@ -1912,7 +1951,7 @@ async function openPlusManualConfirmationDialog(options = {}) {
|
|||||||
{ id: 'confirm', label: '我已完成订阅', variant: 'btn-primary' },
|
{ id: 'confirm', label: '我已完成订阅', variant: 'btn-primary' },
|
||||||
],
|
],
|
||||||
alert: method === 'gopay'
|
alert: method === 'gopay'
|
||||||
? { text: '确认后流程会直接继续到 Plus 模式第 10 步 OAuth 登录。', tone: 'info' }
|
? { text: `确认后流程会直接继续到 Plus 模式后续的${continuationActionLabel}。`, tone: 'info' }
|
||||||
: null,
|
: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1926,6 +1965,19 @@ async function syncPlusManualConfirmationDialog() {
|
|||||||
|
|
||||||
const step = Number(latestState?.plusManualConfirmationStep) || 0;
|
const step = Number(latestState?.plusManualConfirmationStep) || 0;
|
||||||
const method = String(latestState?.plusManualConfirmationMethod || '').trim().toLowerCase();
|
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 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'
|
||||||
|
&& signupMethod === 'email'
|
||||||
|
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||||
|
const continuationActionLabel = useSub2ApiSessionImport
|
||||||
|
? '导入当前 ChatGPT 会话到 SUB2API'
|
||||||
|
: 'OAuth 登录';
|
||||||
const title = latestState?.plusManualConfirmationTitle;
|
const title = latestState?.plusManualConfirmationTitle;
|
||||||
const message = latestState?.plusManualConfirmationMessage;
|
const message = latestState?.plusManualConfirmationMessage;
|
||||||
activePlusManualConfirmationRequestId = requestId;
|
activePlusManualConfirmationRequestId = requestId;
|
||||||
@@ -1963,7 +2015,7 @@ async function syncPlusManualConfirmationDialog() {
|
|||||||
throw new Error(response.error);
|
throw new Error(response.error);
|
||||||
}
|
}
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
showToast(method === 'gopay' ? 'GoPay 订阅已确认,正在继续 OAuth 登录...' : '已确认,流程继续执行中...', 'info', 2200);
|
showToast(method === 'gopay' ? `GoPay 订阅已确认,正在继续${continuationActionLabel}...` : '已确认,流程继续执行中...', 'info', 2200);
|
||||||
} else {
|
} else {
|
||||||
showToast(method === 'gopay' ? '已取消 GoPay 订阅等待。' : '已取消当前手动确认。', 'warn', 2200);
|
showToast(method === 'gopay' ? '已取消 GoPay 订阅等待。' : '已取消当前手动确认。', 'warn', 2200);
|
||||||
}
|
}
|
||||||
@@ -2799,6 +2851,13 @@ function normalizePlusPaymentMethod(value = '') {
|
|||||||
return normalized === gopayValue ? gopayValue : paypalValue;
|
return normalized === gopayValue ? gopayValue : paypalValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizePlusAccountAccessStrategy(value = '') {
|
||||||
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
|
return normalized === PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
? PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION
|
||||||
|
: PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
|
}
|
||||||
|
|
||||||
function getSelectedPlusPaymentMethod(state = latestState) {
|
function getSelectedPlusPaymentMethod(state = latestState) {
|
||||||
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : 'paypal';
|
||||||
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod?.value) {
|
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod?.value) {
|
||||||
@@ -2807,6 +2866,26 @@ function getSelectedPlusPaymentMethod(state = latestState) {
|
|||||||
return normalizePlusPaymentMethod(state?.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
return normalizePlusPaymentMethod(state?.plusPaymentMethod || currentPlusPaymentMethod || defaultMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRequestedPlusAccountAccessStrategy(state = latestState) {
|
||||||
|
const defaultStrategy = typeof DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY !== 'undefined'
|
||||||
|
? DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY
|
||||||
|
: 'oauth';
|
||||||
|
const fallbackStrategy = normalizePlusAccountAccessStrategy(
|
||||||
|
(typeof selectPlusAccountAccessStrategy !== 'undefined' && selectPlusAccountAccessStrategy?.dataset?.requestedValue)
|
||||||
|
|| state?.plusAccountAccessStrategy
|
||||||
|
|| currentPlusAccountAccessStrategy
|
||||||
|
|| defaultStrategy
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
typeof selectPlusAccountAccessStrategy !== 'undefined'
|
||||||
|
&& selectPlusAccountAccessStrategy
|
||||||
|
&& !selectPlusAccountAccessStrategy.disabled
|
||||||
|
) {
|
||||||
|
return normalizePlusAccountAccessStrategy(selectPlusAccountAccessStrategy.value || fallbackStrategy);
|
||||||
|
}
|
||||||
|
return fallbackStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeGpcHelperPhoneModeValue(value = '') {
|
function normalizeGpcHelperPhoneModeValue(value = '') {
|
||||||
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
const rootScope = typeof window !== 'undefined' ? window : globalThis;
|
||||||
if (rootScope.GoPayUtils?.normalizeGpcHelperPhoneMode) {
|
if (rootScope.GoPayUtils?.normalizeGpcHelperPhoneMode) {
|
||||||
@@ -4150,6 +4229,9 @@ function collectSettingsPayload() {
|
|||||||
const rawPlusModeEnabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
|
const rawPlusModeEnabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
|
||||||
? Boolean(inputPlusModeEnabled.checked)
|
? Boolean(inputPlusModeEnabled.checked)
|
||||||
: Boolean(latestState?.plusModeEnabled);
|
: Boolean(latestState?.plusModeEnabled);
|
||||||
|
const requestedPlusAccountAccessStrategy = typeof getRequestedPlusAccountAccessStrategy === 'function'
|
||||||
|
? getRequestedPlusAccountAccessStrategy(latestState)
|
||||||
|
: normalizePlusAccountAccessStrategy(latestState?.plusAccountAccessStrategy || DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY);
|
||||||
const rawPhoneVerificationEnabled = Boolean(inputPhoneVerificationEnabled?.checked);
|
const rawPhoneVerificationEnabled = Boolean(inputPhoneVerificationEnabled?.checked);
|
||||||
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
const capabilityState = typeof resolveCurrentSidepanelCapabilities === 'function'
|
||||||
? resolveCurrentSidepanelCapabilities({
|
? resolveCurrentSidepanelCapabilities({
|
||||||
@@ -4164,6 +4246,7 @@ function collectSettingsPayload() {
|
|||||||
? { panelMode: rawPanelMode }
|
? { panelMode: rawPanelMode }
|
||||||
: { kiroTargetId: selectedTargetId }),
|
: { kiroTargetId: selectedTargetId }),
|
||||||
plusModeEnabled: rawPlusModeEnabled,
|
plusModeEnabled: rawPlusModeEnabled,
|
||||||
|
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||||
phoneVerificationEnabled: rawPhoneVerificationEnabled,
|
phoneVerificationEnabled: rawPhoneVerificationEnabled,
|
||||||
signupMethod: selectedSignupMethod,
|
signupMethod: selectedSignupMethod,
|
||||||
},
|
},
|
||||||
@@ -4186,6 +4269,7 @@ function collectSettingsPayload() {
|
|||||||
? { panelMode: rawPanelMode }
|
? { panelMode: rawPanelMode }
|
||||||
: { kiroTargetId: selectedTargetId }),
|
: { kiroTargetId: selectedTargetId }),
|
||||||
plusModeEnabled: rawPlusModeEnabled,
|
plusModeEnabled: rawPlusModeEnabled,
|
||||||
|
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||||
phoneVerificationEnabled: rawPhoneVerificationEnabled,
|
phoneVerificationEnabled: rawPhoneVerificationEnabled,
|
||||||
signupMethod: selectedSignupMethod,
|
signupMethod: selectedSignupMethod,
|
||||||
},
|
},
|
||||||
@@ -4326,6 +4410,7 @@ function collectSettingsPayload() {
|
|||||||
codex2apiAdminKey: inputCodex2ApiAdminKey.value.trim(),
|
codex2apiAdminKey: inputCodex2ApiAdminKey.value.trim(),
|
||||||
plusModeEnabled: effectivePlusModeEnabled,
|
plusModeEnabled: effectivePlusModeEnabled,
|
||||||
plusPaymentMethod,
|
plusPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||||
paypalEmail: String(currentPayPalAccount?.email || latestState?.paypalEmail || '').trim(),
|
paypalEmail: String(currentPayPalAccount?.email || latestState?.paypalEmail || '').trim(),
|
||||||
paypalPassword: String(currentPayPalAccount?.password || latestState?.paypalPassword || ''),
|
paypalPassword: String(currentPayPalAccount?.password || latestState?.paypalPassword || ''),
|
||||||
currentPayPalAccountId: String(latestState?.currentPayPalAccountId || '').trim(),
|
currentPayPalAccountId: String(latestState?.currentPayPalAccountId || '').trim(),
|
||||||
@@ -8505,6 +8590,10 @@ function resolveStepDefinitionCapabilityState(state = latestState, options = {})
|
|||||||
plusModeEnabled: capabilityState
|
plusModeEnabled: capabilityState
|
||||||
? Boolean(capabilityState.runtimeLocks?.plusModeEnabled)
|
? Boolean(capabilityState.runtimeLocks?.plusModeEnabled)
|
||||||
: Boolean(nextState?.plusModeEnabled),
|
: Boolean(nextState?.plusModeEnabled),
|
||||||
|
plusAccountAccessStrategy: capabilityState?.effectivePlusAccountAccessStrategy
|
||||||
|
|| normalizePlusAccountAccessStrategy(
|
||||||
|
nextState?.plusAccountAccessStrategy || DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY
|
||||||
|
),
|
||||||
signupMethod: capabilityState?.effectiveSignupMethod
|
signupMethod: capabilityState?.effectiveSignupMethod
|
||||||
|| normalizeSignupMethod((options?.signupMethod ?? nextState?.signupMethod) || DEFAULT_SIGNUP_METHOD),
|
|| normalizeSignupMethod((options?.signupMethod ?? nextState?.signupMethod) || DEFAULT_SIGNUP_METHOD),
|
||||||
};
|
};
|
||||||
@@ -8905,7 +8994,16 @@ function updatePlusModeUI() {
|
|||||||
const paypalValue = typeof PLUS_PAYMENT_METHOD_PAYPAL !== 'undefined' ? PLUS_PAYMENT_METHOD_PAYPAL : 'paypal';
|
const paypalValue = typeof PLUS_PAYMENT_METHOD_PAYPAL !== 'undefined' ? PLUS_PAYMENT_METHOD_PAYPAL : 'paypal';
|
||||||
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
|
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
|
||||||
const gpcValue = typeof PLUS_PAYMENT_METHOD_GPC_HELPER !== 'undefined' ? PLUS_PAYMENT_METHOD_GPC_HELPER : 'gpc-helper';
|
const gpcValue = typeof PLUS_PAYMENT_METHOD_GPC_HELPER !== 'undefined' ? PLUS_PAYMENT_METHOD_GPC_HELPER : 'gpc-helper';
|
||||||
|
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 defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : paypalValue;
|
const defaultMethod = typeof DEFAULT_PLUS_PAYMENT_METHOD !== 'undefined' ? DEFAULT_PLUS_PAYMENT_METHOD : paypalValue;
|
||||||
|
const requestedPlusAccountAccessStrategy = typeof getRequestedPlusAccountAccessStrategy === 'function'
|
||||||
|
? getRequestedPlusAccountAccessStrategy(latestState)
|
||||||
|
: normalizePlusAccountAccessStrategy(latestState?.plusAccountAccessStrategy || DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY);
|
||||||
const rawEnabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
|
const rawEnabled = typeof inputPlusModeEnabled !== 'undefined' && inputPlusModeEnabled
|
||||||
? Boolean(inputPlusModeEnabled.checked)
|
? Boolean(inputPlusModeEnabled.checked)
|
||||||
: false;
|
: false;
|
||||||
@@ -8915,6 +9013,7 @@ function updatePlusModeUI() {
|
|||||||
state: {
|
state: {
|
||||||
...(latestState || {}),
|
...(latestState || {}),
|
||||||
plusModeEnabled: rawEnabled,
|
plusModeEnabled: rawEnabled,
|
||||||
|
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
: (() => {
|
: (() => {
|
||||||
@@ -8929,6 +9028,7 @@ function updatePlusModeUI() {
|
|||||||
state: {
|
state: {
|
||||||
...(latestState || {}),
|
...(latestState || {}),
|
||||||
plusModeEnabled: rawEnabled,
|
plusModeEnabled: rawEnabled,
|
||||||
|
plusAccountAccessStrategy: requestedPlusAccountAccessStrategy,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
@@ -8937,6 +9037,10 @@ function updatePlusModeUI() {
|
|||||||
? Boolean(capabilityState.canShowPlusSettings)
|
? Boolean(capabilityState.canShowPlusSettings)
|
||||||
: true;
|
: true;
|
||||||
const enabled = supportsPlusMode && rawEnabled;
|
const enabled = supportsPlusMode && rawEnabled;
|
||||||
|
const canEditPlusAccountAccessStrategy = Boolean(capabilityState?.canEditPlusAccountAccessStrategy);
|
||||||
|
const effectivePlusAccountAccessStrategy = capabilityState?.effectivePlusAccountAccessStrategy
|
||||||
|
|| requestedPlusAccountAccessStrategy
|
||||||
|
|| oauthStrategyValue;
|
||||||
const method = enabled ? getSelectedPlusPaymentMethod() : defaultMethod;
|
const method = enabled ? getSelectedPlusPaymentMethod() : defaultMethod;
|
||||||
const gpcPhoneMode = normalizeGpcHelperPhoneModeValue(
|
const gpcPhoneMode = normalizeGpcHelperPhoneModeValue(
|
||||||
typeof selectGpcHelperPhoneMode !== 'undefined' && selectGpcHelperPhoneMode
|
typeof selectGpcHelperPhoneMode !== 'undefined' && selectGpcHelperPhoneMode
|
||||||
@@ -8990,6 +9094,33 @@ function updatePlusModeUI() {
|
|||||||
}
|
}
|
||||||
row.style.display = enabled ? '' : 'none';
|
row.style.display = enabled ? '' : 'none';
|
||||||
});
|
});
|
||||||
|
[
|
||||||
|
typeof rowPlusAccountAccessStrategy !== 'undefined' ? rowPlusAccountAccessStrategy : null,
|
||||||
|
].forEach((row) => {
|
||||||
|
if (!row) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
row.style.display = enabled ? '' : 'none';
|
||||||
|
});
|
||||||
|
if (typeof selectPlusAccountAccessStrategy !== 'undefined' && selectPlusAccountAccessStrategy) {
|
||||||
|
selectPlusAccountAccessStrategy.dataset.requestedValue = requestedPlusAccountAccessStrategy;
|
||||||
|
selectPlusAccountAccessStrategy.value = effectivePlusAccountAccessStrategy;
|
||||||
|
selectPlusAccountAccessStrategy.disabled = !enabled || !canEditPlusAccountAccessStrategy;
|
||||||
|
selectPlusAccountAccessStrategy.setAttribute('aria-disabled', String(selectPlusAccountAccessStrategy.disabled));
|
||||||
|
}
|
||||||
|
if (typeof plusAccountAccessStrategyCaption !== 'undefined' && plusAccountAccessStrategyCaption) {
|
||||||
|
if (!enabled) {
|
||||||
|
plusAccountAccessStrategyCaption.textContent = '当前来源仅支持 OAuth';
|
||||||
|
} else if (!canEditPlusAccountAccessStrategy) {
|
||||||
|
plusAccountAccessStrategyCaption.textContent = '当前来源仅支持 OAuth';
|
||||||
|
} else if (effectivePlusAccountAccessStrategy === sub2apiSessionStrategyValue) {
|
||||||
|
plusAccountAccessStrategyCaption.textContent = '复用当前 Plus 已登录会话,直接导入到 SUB2API';
|
||||||
|
} else if (effectivePlusAccountAccessStrategy === oauthStrategyValue) {
|
||||||
|
plusAccountAccessStrategyCaption.textContent = '通过 OAuth 回调创建 SUB2API 账号';
|
||||||
|
} else {
|
||||||
|
plusAccountAccessStrategyCaption.textContent = '当前来源仅支持 OAuth';
|
||||||
|
}
|
||||||
|
}
|
||||||
[
|
[
|
||||||
typeof rowPayPalAccount !== 'undefined' ? rowPayPalAccount : null,
|
typeof rowPayPalAccount !== 'undefined' ? rowPayPalAccount : null,
|
||||||
].forEach((row) => {
|
].forEach((row) => {
|
||||||
@@ -9362,6 +9493,19 @@ async function ensureGpcApiKeyReadyForStart(options = {}) {
|
|||||||
async function openPlusManualConfirmationDialog(options = {}) {
|
async function openPlusManualConfirmationDialog(options = {}) {
|
||||||
const method = String(options.method || '').trim().toLowerCase();
|
const method = String(options.method || '').trim().toLowerCase();
|
||||||
const gopayValue = typeof PLUS_PAYMENT_METHOD_GOPAY !== 'undefined' ? PLUS_PAYMENT_METHOD_GOPAY : 'gopay';
|
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 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'
|
||||||
|
&& signupMethod === 'email'
|
||||||
|
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||||
|
const continuationActionLabel = useSub2ApiSessionImport
|
||||||
|
? '导入当前 ChatGPT 会话到 SUB2API'
|
||||||
|
: 'OAuth 登录';
|
||||||
if (method === 'gopay-otp') {
|
if (method === 'gopay-otp') {
|
||||||
if (!sharedFormDialog?.open) {
|
if (!sharedFormDialog?.open) {
|
||||||
return null;
|
return null;
|
||||||
@@ -9405,7 +9549,7 @@ async function openPlusManualConfirmationDialog(options = {}) {
|
|||||||
{ id: 'confirm', label: '我已完成订阅', variant: 'btn-primary' },
|
{ id: 'confirm', label: '我已完成订阅', variant: 'btn-primary' },
|
||||||
],
|
],
|
||||||
alert: method === gopayValue
|
alert: method === gopayValue
|
||||||
? { text: '确认后流程会直接继续到 Plus 模式第 10 步 OAuth 登录。', tone: 'info' }
|
? { text: `确认后流程会直接继续到 Plus 模式后续的${continuationActionLabel}。`, tone: 'info' }
|
||||||
: null,
|
: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -9420,6 +9564,19 @@ async function syncPlusManualConfirmationDialog() {
|
|||||||
|
|
||||||
const step = Number(latestState?.plusManualConfirmationStep) || 0;
|
const step = Number(latestState?.plusManualConfirmationStep) || 0;
|
||||||
const method = String(latestState?.plusManualConfirmationMethod || '').trim().toLowerCase();
|
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 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'
|
||||||
|
&& signupMethod === 'email'
|
||||||
|
&& plusAccountAccessStrategy === 'sub2api_codex_session';
|
||||||
|
const continuationActionLabel = useSub2ApiSessionImport
|
||||||
|
? '导入当前 ChatGPT 会话到 SUB2API'
|
||||||
|
: 'OAuth 登录';
|
||||||
const title = latestState?.plusManualConfirmationTitle;
|
const title = latestState?.plusManualConfirmationTitle;
|
||||||
const message = latestState?.plusManualConfirmationMessage;
|
const message = latestState?.plusManualConfirmationMessage;
|
||||||
activePlusManualConfirmationRequestId = requestId;
|
activePlusManualConfirmationRequestId = requestId;
|
||||||
@@ -9461,7 +9618,7 @@ async function syncPlusManualConfirmationDialog() {
|
|||||||
showToast(
|
showToast(
|
||||||
method === 'gopay-otp'
|
method === 'gopay-otp'
|
||||||
? 'GPC OTP 已提交,正在继续验证...'
|
? 'GPC OTP 已提交,正在继续验证...'
|
||||||
: (method === gopayValue ? 'GoPay 订阅已确认,正在继续 OAuth 登录...' : '已确认,流程继续执行中...'),
|
: (method === gopayValue ? `GoPay 订阅已确认,正在继续${continuationActionLabel}...` : '已确认,流程继续执行中...'),
|
||||||
'info',
|
'info',
|
||||||
2200
|
2200
|
||||||
);
|
);
|
||||||
@@ -9776,6 +9933,7 @@ function renderStepsList() {
|
|||||||
|
|
||||||
function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOrOptions = {}, maybeOptions = {}) {
|
function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOrOptions = {}, maybeOptions = {}) {
|
||||||
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
const defaultFlowId = typeof DEFAULT_ACTIVE_FLOW_ID !== 'undefined' ? DEFAULT_ACTIVE_FLOW_ID : 'openai';
|
||||||
|
const defaultStrategy = typeof DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY !== 'undefined' ? DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY : 'oauth';
|
||||||
const nextPlusModeEnabled = Boolean(plusModeEnabled);
|
const nextPlusModeEnabled = Boolean(plusModeEnabled);
|
||||||
const options = typeof plusPaymentMethodOrOptions === 'string'
|
const options = typeof plusPaymentMethodOrOptions === 'string'
|
||||||
? maybeOptions
|
? maybeOptions
|
||||||
@@ -9783,6 +9941,11 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOr
|
|||||||
const rawPaymentMethod = typeof plusPaymentMethodOrOptions === 'string'
|
const rawPaymentMethod = typeof plusPaymentMethodOrOptions === 'string'
|
||||||
? plusPaymentMethodOrOptions
|
? plusPaymentMethodOrOptions
|
||||||
: (options.plusPaymentMethod || getSelectedPlusPaymentMethod(latestState));
|
: (options.plusPaymentMethod || getSelectedPlusPaymentMethod(latestState));
|
||||||
|
const nextPlusAccountAccessStrategy = normalizePlusAccountAccessStrategy(
|
||||||
|
options.plusAccountAccessStrategy
|
||||||
|
|| currentPlusAccountAccessStrategy
|
||||||
|
|| defaultStrategy
|
||||||
|
);
|
||||||
const nextSignupMethod = normalizeSignupMethod(options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
const nextSignupMethod = normalizeSignupMethod(options.signupMethod || currentSignupMethod || DEFAULT_SIGNUP_METHOD);
|
||||||
const nextPhoneSignupReloginAfterBindEmailEnabled = Boolean(
|
const nextPhoneSignupReloginAfterBindEmailEnabled = Boolean(
|
||||||
options.phoneSignupReloginAfterBindEmailEnabled
|
options.phoneSignupReloginAfterBindEmailEnabled
|
||||||
@@ -9805,6 +9968,7 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOr
|
|||||||
activeFlowId: nextActiveFlowId,
|
activeFlowId: nextActiveFlowId,
|
||||||
plusModeEnabled: nextPlusModeEnabled,
|
plusModeEnabled: nextPlusModeEnabled,
|
||||||
plusPaymentMethod: nextPaymentMethod,
|
plusPaymentMethod: nextPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: nextPlusAccountAccessStrategy,
|
||||||
signupMethod: nextSignupMethod,
|
signupMethod: nextSignupMethod,
|
||||||
phoneSignupReloginAfterBindEmailEnabled: nextPhoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled: nextPhoneSignupReloginAfterBindEmailEnabled,
|
||||||
});
|
});
|
||||||
@@ -9812,6 +9976,7 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOr
|
|||||||
const shouldRender = Boolean(options.render)
|
const shouldRender = Boolean(options.render)
|
||||||
|| nextPlusModeEnabled !== currentPlusModeEnabled
|
|| nextPlusModeEnabled !== currentPlusModeEnabled
|
||||||
|| nextPaymentMethod !== currentPlusPaymentMethod
|
|| nextPaymentMethod !== currentPlusPaymentMethod
|
||||||
|
|| nextPlusAccountAccessStrategy !== currentPlusAccountAccessStrategy
|
||||||
|| nextSignupMethod !== currentSignupMethod
|
|| nextSignupMethod !== currentSignupMethod
|
||||||
|| nextPhoneSignupReloginAfterBindEmailEnabled !== currentPhoneSignupReloginAfterBindEmailEnabled
|
|| nextPhoneSignupReloginAfterBindEmailEnabled !== currentPhoneSignupReloginAfterBindEmailEnabled
|
||||||
|| nextActiveFlowId !== currentFlowId
|
|| nextActiveFlowId !== currentFlowId
|
||||||
@@ -9823,6 +9988,7 @@ function syncStepDefinitionsForMode(plusModeEnabled = false, plusPaymentMethodOr
|
|||||||
rebuildStepDefinitionState(nextPlusModeEnabled, {
|
rebuildStepDefinitionState(nextPlusModeEnabled, {
|
||||||
activeFlowId: nextActiveFlowId,
|
activeFlowId: nextActiveFlowId,
|
||||||
plusPaymentMethod: nextPaymentMethod,
|
plusPaymentMethod: nextPaymentMethod,
|
||||||
|
plusAccountAccessStrategy: nextPlusAccountAccessStrategy,
|
||||||
signupMethod: nextSignupMethod,
|
signupMethod: nextSignupMethod,
|
||||||
phoneSignupReloginAfterBindEmailEnabled: nextPhoneSignupReloginAfterBindEmailEnabled,
|
phoneSignupReloginAfterBindEmailEnabled: nextPhoneSignupReloginAfterBindEmailEnabled,
|
||||||
});
|
});
|
||||||
@@ -9848,6 +10014,7 @@ function syncStepDefinitionsFromUiState(stateOverrides = {}) {
|
|||||||
syncStepDefinitionsForMode(stepDefinitionState.plusModeEnabled, {
|
syncStepDefinitionsForMode(stepDefinitionState.plusModeEnabled, {
|
||||||
activeFlowId: nextState?.activeFlowId || nextState?.flowId || DEFAULT_ACTIVE_FLOW_ID,
|
activeFlowId: nextState?.activeFlowId || nextState?.flowId || DEFAULT_ACTIVE_FLOW_ID,
|
||||||
plusPaymentMethod: getSelectedPlusPaymentMethod(nextState),
|
plusPaymentMethod: getSelectedPlusPaymentMethod(nextState),
|
||||||
|
plusAccountAccessStrategy: stepDefinitionState.plusAccountAccessStrategy,
|
||||||
signupMethod: stepDefinitionState.signupMethod,
|
signupMethod: stepDefinitionState.signupMethod,
|
||||||
phoneSignupReloginAfterBindEmailEnabled: Boolean(nextState?.phoneSignupReloginAfterBindEmailEnabled),
|
phoneSignupReloginAfterBindEmailEnabled: Boolean(nextState?.phoneSignupReloginAfterBindEmailEnabled),
|
||||||
});
|
});
|
||||||
@@ -9949,6 +10116,13 @@ function applySettingsState(state) {
|
|||||||
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod) {
|
if (typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod) {
|
||||||
selectPlusPaymentMethod.value = normalizePlusPaymentMethod(state?.plusPaymentMethod);
|
selectPlusPaymentMethod.value = normalizePlusPaymentMethod(state?.plusPaymentMethod);
|
||||||
}
|
}
|
||||||
|
currentPlusAccountAccessStrategy = normalizePlusAccountAccessStrategy(
|
||||||
|
state?.plusAccountAccessStrategy || DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY
|
||||||
|
);
|
||||||
|
if (typeof selectPlusAccountAccessStrategy !== 'undefined' && selectPlusAccountAccessStrategy) {
|
||||||
|
selectPlusAccountAccessStrategy.dataset.requestedValue = currentPlusAccountAccessStrategy;
|
||||||
|
selectPlusAccountAccessStrategy.value = currentPlusAccountAccessStrategy;
|
||||||
|
}
|
||||||
if (typeof inputGpcHelperApi !== 'undefined' && inputGpcHelperApi) {
|
if (typeof inputGpcHelperApi !== 'undefined' && inputGpcHelperApi) {
|
||||||
const defaultGpcHelperApiUrl = typeof DEFAULT_GPC_HELPER_API_URL !== 'undefined'
|
const defaultGpcHelperApiUrl = typeof DEFAULT_GPC_HELPER_API_URL !== 'undefined'
|
||||||
? DEFAULT_GPC_HELPER_API_URL
|
? DEFAULT_GPC_HELPER_API_URL
|
||||||
@@ -14213,6 +14387,13 @@ selectPanelMode.addEventListener('change', async () => {
|
|||||||
saveSettings({ silent: true }).catch(() => { });
|
saveSettings({ silent: true }).catch(() => { });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
selectPlusAccountAccessStrategy?.addEventListener('change', () => {
|
||||||
|
selectPlusAccountAccessStrategy.value = normalizePlusAccountAccessStrategy(selectPlusAccountAccessStrategy.value);
|
||||||
|
updatePlusModeUI();
|
||||||
|
markSettingsDirty(true);
|
||||||
|
saveSettings({ silent: true }).catch(() => { });
|
||||||
|
});
|
||||||
|
|
||||||
[inputKiroRsUrl, inputKiroRsKey].forEach((input) => {
|
[inputKiroRsUrl, inputKiroRsKey].forEach((input) => {
|
||||||
input?.addEventListener('input', () => {
|
input?.addEventListener('input', () => {
|
||||||
markSettingsDirty(true);
|
markSettingsDirty(true);
|
||||||
@@ -16157,6 +16338,13 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
if (message.payload.plusPaymentMethod !== undefined && selectPlusPaymentMethod) {
|
if (message.payload.plusPaymentMethod !== undefined && selectPlusPaymentMethod) {
|
||||||
selectPlusPaymentMethod.value = normalizePlusPaymentMethod(message.payload.plusPaymentMethod);
|
selectPlusPaymentMethod.value = normalizePlusPaymentMethod(message.payload.plusPaymentMethod);
|
||||||
}
|
}
|
||||||
|
if (message.payload.plusAccountAccessStrategy !== undefined && selectPlusAccountAccessStrategy) {
|
||||||
|
currentPlusAccountAccessStrategy = normalizePlusAccountAccessStrategy(message.payload.plusAccountAccessStrategy);
|
||||||
|
selectPlusAccountAccessStrategy.dataset.requestedValue = currentPlusAccountAccessStrategy;
|
||||||
|
if (!selectPlusAccountAccessStrategy.disabled) {
|
||||||
|
selectPlusAccountAccessStrategy.value = currentPlusAccountAccessStrategy;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (message.payload.gopayHelperPhoneMode !== undefined && selectGpcHelperPhoneMode) {
|
if (message.payload.gopayHelperPhoneMode !== undefined && selectGpcHelperPhoneMode) {
|
||||||
selectGpcHelperPhoneMode.value = normalizeGpcHelperPhoneModeValue(message.payload.gopayHelperPhoneMode);
|
selectGpcHelperPhoneMode.value = normalizeGpcHelperPhoneModeValue(message.payload.gopayHelperPhoneMode);
|
||||||
}
|
}
|
||||||
@@ -16181,6 +16369,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
|||||||
if (
|
if (
|
||||||
message.payload.plusModeEnabled !== undefined
|
message.payload.plusModeEnabled !== undefined
|
||||||
|| message.payload.plusPaymentMethod !== undefined
|
|| message.payload.plusPaymentMethod !== undefined
|
||||||
|
|| message.payload.plusAccountAccessStrategy !== undefined
|
||||||
|| message.payload.gopayHelperPhoneMode !== undefined
|
|| message.payload.gopayHelperPhoneMode !== undefined
|
||||||
|| message.payload.gopayHelperAutoModeEnabled !== undefined
|
|| message.payload.gopayHelperAutoModeEnabled !== undefined
|
||||||
|| message.payload.gopayHelperOtpChannel !== undefined
|
|| message.payload.gopayHelperOtpChannel !== undefined
|
||||||
|
|||||||
@@ -173,8 +173,8 @@ const defaultStepDefinitions = {
|
|||||||
4: { key: 'verify-email' },
|
4: { key: 'verify-email' },
|
||||||
5: { key: 'profile-basic' },
|
5: { key: 'profile-basic' },
|
||||||
6: { key: 'profile-finish' },
|
6: { key: 'profile-finish' },
|
||||||
7: { key: 'auth-login' },
|
7: { key: 'oauth-login' },
|
||||||
8: { key: 'auth-email-code' },
|
8: { key: 'fetch-login-code' },
|
||||||
9: { key: 'confirm-oauth' },
|
9: { key: 'confirm-oauth' },
|
||||||
10: { key: 'platform-verify' },
|
10: { key: 'platform-verify' },
|
||||||
};
|
};
|
||||||
@@ -407,7 +407,7 @@ test('auto-run keeps restarting from step 7 after post-login failures without a
|
|||||||
7, 8, 9, 10,
|
7, 8, 9, 10,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
assert.ok(events.logs.some(({ message }) => /回到节点 auth-login 重新开始授权流程/.test(message)));
|
assert.ok(events.logs.some(({ message }) => /回到节点 oauth-login 重新开始授权流程/.test(message)));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('auto-run restarts the current step after five minutes without new logs', async () => {
|
test('auto-run restarts the current step after five minutes without new logs', async () => {
|
||||||
@@ -964,3 +964,42 @@ test('auto-run does not restart GPC checkout when account already has a ChatGPT
|
|||||||
assert.equal(result.events.invalidations.length, 0);
|
assert.equal(result.events.invalidations.length, 0);
|
||||||
assert.ok(!result.events.logs.some(({ message }) => /回到步骤 6 重新创建 GPC 任务/.test(message)));
|
assert.ok(!result.events.logs.some(({ message }) => /回到步骤 6 重新创建 GPC 任务/.test(message)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('auto-run does not reroute SUB2API session import failures into OAuth restarts', async () => {
|
||||||
|
const plusSessionSteps = {
|
||||||
|
6: { key: 'plus-checkout-create' },
|
||||||
|
7: { key: 'plus-checkout-billing' },
|
||||||
|
8: { key: 'paypal-approve' },
|
||||||
|
9: { key: 'plus-checkout-return' },
|
||||||
|
10: { key: 'sub2api-session-import' },
|
||||||
|
};
|
||||||
|
const harness = createHarness({
|
||||||
|
startStep: 10,
|
||||||
|
failureStep: 10,
|
||||||
|
failureBudget: 1,
|
||||||
|
failureMessage: '步骤 10:当前页面未读取到有效的 ChatGPT session。',
|
||||||
|
stepDefinitions: plusSessionSteps,
|
||||||
|
finalOAuthChainStartStep: 10,
|
||||||
|
customState: {
|
||||||
|
stepStatuses: {
|
||||||
|
3: 'completed',
|
||||||
|
6: 'completed',
|
||||||
|
7: 'completed',
|
||||||
|
8: 'completed',
|
||||||
|
9: 'completed',
|
||||||
|
},
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
panelMode: 'sub2api',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await harness.runAndCaptureError();
|
||||||
|
|
||||||
|
assert.ok(result?.error);
|
||||||
|
assert.match(result.error.message, /未读取到有效的 ChatGPT session/);
|
||||||
|
assert.deepStrictEqual(result.events.steps, [10]);
|
||||||
|
assert.equal(result.events.invalidations.length, 0);
|
||||||
|
assert.ok(!result.events.logs.some(({ message }) => /回到节点 oauth-login|回到节点 confirm-oauth|重新开始授权流程/.test(message)));
|
||||||
|
});
|
||||||
|
|||||||
@@ -227,6 +227,8 @@ return {
|
|||||||
assert.equal(api.normalizePersistentSettingValue('plusPaymentMethod', 'gpc-helper'), 'gpc-helper');
|
assert.equal(api.normalizePersistentSettingValue('plusPaymentMethod', 'gpc-helper'), 'gpc-helper');
|
||||||
assert.equal(api.normalizePersistentSettingValue('plusPaymentMethod', 'paypal'), 'paypal');
|
assert.equal(api.normalizePersistentSettingValue('plusPaymentMethod', 'paypal'), 'paypal');
|
||||||
assert.equal(api.normalizePersistentSettingValue('plusPaymentMethod', 'unknown'), 'paypal');
|
assert.equal(api.normalizePersistentSettingValue('plusPaymentMethod', 'unknown'), 'paypal');
|
||||||
|
assert.equal(api.normalizePersistentSettingValue('plusAccountAccessStrategy', 'sub2api_codex_session'), 'sub2api_codex_session');
|
||||||
|
assert.equal(api.normalizePersistentSettingValue('plusAccountAccessStrategy', 'unknown'), 'oauth');
|
||||||
assert.equal(
|
assert.equal(
|
||||||
api.normalizePersistentSettingValue('gopayHelperApiUrl', ' https://gpc.qlhazycoder.top/api/checkout/start '),
|
api.normalizePersistentSettingValue('gopayHelperApiUrl', ' https://gpc.qlhazycoder.top/api/checkout/start '),
|
||||||
'https://gpc.qlhazycoder.top'
|
'https://gpc.qlhazycoder.top'
|
||||||
|
|||||||
@@ -48,6 +48,15 @@ function extractFunction(name) {
|
|||||||
return source.slice(start, end);
|
return source.slice(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test('background auth chain set does not include SUB2API session import node', () => {
|
||||||
|
const authChainStart = source.indexOf('const AUTH_CHAIN_NODE_IDS = new Set([');
|
||||||
|
const authChainEnd = source.indexOf(']);', authChainStart);
|
||||||
|
const authChainBlock = source.slice(authChainStart, authChainEnd);
|
||||||
|
|
||||||
|
assert.ok(authChainStart >= 0, 'expected AUTH_CHAIN_NODE_IDS block to exist');
|
||||||
|
assert.doesNotMatch(authChainBlock, /sub2api-session-import/);
|
||||||
|
});
|
||||||
|
|
||||||
const NODE_EXECUTE_COMPAT_HELPERS = `
|
const NODE_EXECUTE_COMPAT_HELPERS = `
|
||||||
const AUTH_CHAIN_NODE_IDS = new Set(['oauth-login', 'fetch-login-code', 'confirm-oauth', 'platform-verify']);
|
const AUTH_CHAIN_NODE_IDS = new Set(['oauth-login', 'fetch-login-code', 'confirm-oauth', 'platform-verify']);
|
||||||
const STEP_NODE_IDS = {
|
const STEP_NODE_IDS = {
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
const source = fs.readFileSync('background.js', 'utf8');
|
||||||
|
|
||||||
|
function extractFunction(name) {
|
||||||
|
const markers = [`async function ${name}(`, `function ${name}(`];
|
||||||
|
const start = markers
|
||||||
|
.map((marker) => source.indexOf(marker))
|
||||||
|
.find((index) => index >= 0);
|
||||||
|
if (start < 0) {
|
||||||
|
throw new Error(`missing function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let parenDepth = 0;
|
||||||
|
let signatureEnded = false;
|
||||||
|
let braceStart = -1;
|
||||||
|
for (let i = start; i < source.length; i += 1) {
|
||||||
|
const ch = source[i];
|
||||||
|
if (ch === '(') {
|
||||||
|
parenDepth += 1;
|
||||||
|
} else if (ch === ')') {
|
||||||
|
parenDepth -= 1;
|
||||||
|
if (parenDepth === 0) {
|
||||||
|
signatureEnded = true;
|
||||||
|
}
|
||||||
|
} else if (ch === '{' && signatureEnded) {
|
||||||
|
braceStart = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (braceStart < 0) {
|
||||||
|
throw new Error(`missing body for function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let depth = 0;
|
||||||
|
let end = braceStart;
|
||||||
|
for (; end < source.length; end += 1) {
|
||||||
|
const ch = source[end];
|
||||||
|
if (ch === '{') depth += 1;
|
||||||
|
if (ch === '}') {
|
||||||
|
depth -= 1;
|
||||||
|
if (depth === 0) {
|
||||||
|
end += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return source.slice(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createHarness() {
|
||||||
|
return new Function(`
|
||||||
|
const DEFAULT_ACTIVE_FLOW_ID = 'openai';
|
||||||
|
const workflowEngine = null;
|
||||||
|
const self = {
|
||||||
|
MultiPageStepDefinitions: {
|
||||||
|
getSteps(options = {}) {
|
||||||
|
return String(options.plusAccountAccessStrategy || '').trim() === 'sub2api_codex_session'
|
||||||
|
? [
|
||||||
|
{ id: 1, key: 'open-chatgpt' },
|
||||||
|
{ id: 2, key: 'plus-checkout-create' },
|
||||||
|
{ id: 3, key: 'plus-checkout-billing' },
|
||||||
|
{ id: 4, key: 'paypal-approve' },
|
||||||
|
{ id: 5, key: 'plus-checkout-return' },
|
||||||
|
{ id: 6, key: 'sub2api-session-import' },
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{ id: 1, key: 'open-chatgpt' },
|
||||||
|
{ id: 2, key: 'plus-checkout-create' },
|
||||||
|
{ id: 3, key: 'plus-checkout-billing' },
|
||||||
|
{ id: 4, key: 'paypal-approve' },
|
||||||
|
{ id: 5, key: 'plus-checkout-return' },
|
||||||
|
{ id: 6, key: 'oauth-login' },
|
||||||
|
{ id: 7, key: 'fetch-login-code' },
|
||||||
|
{ id: 8, key: 'confirm-oauth' },
|
||||||
|
{ id: 9, key: 'platform-verify' },
|
||||||
|
];
|
||||||
|
},
|
||||||
|
getNodes(options = {}) {
|
||||||
|
return this.getSteps(options).map((definition) => ({
|
||||||
|
nodeId: String(definition.key || '').trim(),
|
||||||
|
displayOrder: Number(definition.id) || 0,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
function normalizeSignupMethod(value = '') {
|
||||||
|
return String(value || '').trim().toLowerCase() === 'phone' ? 'phone' : 'email';
|
||||||
|
}
|
||||||
|
function normalizePlusPaymentMethod(value = '') {
|
||||||
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
|
return normalized === 'gopay' || normalized === 'gpc-helper' ? normalized : 'paypal';
|
||||||
|
}
|
||||||
|
function normalizePlusAccountAccessStrategy(value = '') {
|
||||||
|
return String(value || '').trim().toLowerCase() === 'sub2api_codex_session'
|
||||||
|
? 'sub2api_codex_session'
|
||||||
|
: 'oauth';
|
||||||
|
}
|
||||||
|
function isPlusModeState(state = {}) {
|
||||||
|
return Boolean(state?.plusModeEnabled);
|
||||||
|
}
|
||||||
|
function resolveCurrentFlowCapabilities(state = {}, options = {}) {
|
||||||
|
const effectiveStrategy = String(options.panelMode || '').trim().toLowerCase() === 'sub2api'
|
||||||
|
? normalizePlusAccountAccessStrategy(state.plusAccountAccessStrategy)
|
||||||
|
: 'oauth';
|
||||||
|
return {
|
||||||
|
effectivePanelMode: options.panelMode,
|
||||||
|
effectivePlusAccountAccessStrategy: effectiveStrategy,
|
||||||
|
effectiveSignupMethod: 'email',
|
||||||
|
stepDefinitionOptions: {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
panelMode: options.panelMode,
|
||||||
|
plusModeEnabled: Boolean(state.plusModeEnabled),
|
||||||
|
plusPaymentMethod: normalizePlusPaymentMethod(state.plusPaymentMethod),
|
||||||
|
plusAccountAccessStrategy: effectiveStrategy,
|
||||||
|
signupMethod: 'email',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
${extractFunction('getSignupMethodForStepDefinitions')}
|
||||||
|
${extractFunction('buildResolvedStepDefinitionState')}
|
||||||
|
${extractFunction('getStepDefinitionsForState')}
|
||||||
|
${extractFunction('getNodeDefinitionsForState')}
|
||||||
|
${extractFunction('getNodeIdsForState')}
|
||||||
|
return {
|
||||||
|
buildResolvedStepDefinitionState,
|
||||||
|
getNodeIdsForState,
|
||||||
|
};
|
||||||
|
`)();
|
||||||
|
}
|
||||||
|
|
||||||
|
test('background step resolution keeps SUB2API session tail only when the effective Plus target supports it', () => {
|
||||||
|
const api = createHarness();
|
||||||
|
const state = {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
flowId: 'openai',
|
||||||
|
panelMode: 'sub2api',
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
signupMethod: 'email',
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolvedState = api.buildResolvedStepDefinitionState(state);
|
||||||
|
const nodeIds = api.getNodeIdsForState(state);
|
||||||
|
|
||||||
|
assert.equal(resolvedState.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
assert.deepStrictEqual(nodeIds, [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'paypal-approve',
|
||||||
|
'plus-checkout-return',
|
||||||
|
'sub2api-session-import',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('background step resolution falls back to OAuth tail when the requested session strategy is not effective for the current panel mode', () => {
|
||||||
|
const api = createHarness();
|
||||||
|
const state = {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
flowId: 'openai',
|
||||||
|
panelMode: 'cpa',
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
signupMethod: 'email',
|
||||||
|
};
|
||||||
|
|
||||||
|
const resolvedState = api.buildResolvedStepDefinitionState(state);
|
||||||
|
const nodeIds = api.getNodeIdsForState(state);
|
||||||
|
|
||||||
|
assert.equal(resolvedState.plusAccountAccessStrategy, 'oauth');
|
||||||
|
assert.equal(nodeIds.includes('sub2api-session-import'), false);
|
||||||
|
assert.deepStrictEqual(nodeIds.slice(-4), [
|
||||||
|
'oauth-login',
|
||||||
|
'fetch-login-code',
|
||||||
|
'confirm-oauth',
|
||||||
|
'platform-verify',
|
||||||
|
]);
|
||||||
|
});
|
||||||
@@ -297,6 +297,299 @@ test('SAVE_SETTING broadcasts operation delay setting without background success
|
|||||||
assert.equal(logs.length, 0);
|
assert.equal(logs.length, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('SAVE_SETTING rebuilds Plus node statuses when the account access strategy changes', async () => {
|
||||||
|
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||||
|
const globalScope = { console };
|
||||||
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||||
|
const broadcasts = [];
|
||||||
|
let state = {
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'oauth',
|
||||||
|
oauthUrl: 'https://oauth.example/current',
|
||||||
|
localhostUrl: 'http://localhost:38080/callback',
|
||||||
|
oauthFlowDeadlineAt: Date.now() + 60000,
|
||||||
|
oauthFlowDeadlineSourceUrl: 'https://oauth.example/current',
|
||||||
|
cpaOAuthState: 'cpa-state',
|
||||||
|
cpaManagementOrigin: 'https://cpa.example.com',
|
||||||
|
sub2apiSessionId: 'sub-session',
|
||||||
|
sub2apiOAuthState: 'sub-oauth-state',
|
||||||
|
sub2apiGroupId: 'group-id',
|
||||||
|
sub2apiGroupIds: ['group-id'],
|
||||||
|
sub2apiDraftName: 'draft-name',
|
||||||
|
sub2apiProxyId: 'proxy-id',
|
||||||
|
codex2apiSessionId: 'codex-session',
|
||||||
|
codex2apiOAuthState: 'codex-oauth-state',
|
||||||
|
plusManualConfirmationPending: true,
|
||||||
|
plusManualConfirmationRequestId: 'gopay-req',
|
||||||
|
plusManualConfirmationStep: 9,
|
||||||
|
plusManualConfirmationMethod: 'gopay',
|
||||||
|
plusManualConfirmationTitle: 'GoPay 订阅确认',
|
||||||
|
plusManualConfirmationMessage: '完成后继续 OAuth 登录。',
|
||||||
|
currentNodeId: 'confirm-oauth',
|
||||||
|
nodeStatuses: {
|
||||||
|
'open-chatgpt': 'completed',
|
||||||
|
'plus-checkout-create': 'completed',
|
||||||
|
'plus-checkout-billing': 'completed',
|
||||||
|
'paypal-approve': 'completed',
|
||||||
|
'plus-checkout-return': 'completed',
|
||||||
|
'oauth-login': 'completed',
|
||||||
|
'fetch-login-code': 'completed',
|
||||||
|
'post-login-phone-verification': 'completed',
|
||||||
|
'confirm-oauth': 'running',
|
||||||
|
'platform-verify': 'pending',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = api.createMessageRouter({
|
||||||
|
addLog: async () => {},
|
||||||
|
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||||
|
buildPersistentSettingsPayload: (input = {}) => Object.prototype.hasOwnProperty.call(input, 'plusAccountAccessStrategy')
|
||||||
|
? { plusAccountAccessStrategy: input.plusAccountAccessStrategy }
|
||||||
|
: {},
|
||||||
|
broadcastDataUpdate: (payload) => broadcasts.push(payload),
|
||||||
|
getNodeIdsForState: (nextState = {}) => (
|
||||||
|
String(nextState.plusAccountAccessStrategy || '').trim() === 'sub2api_codex_session'
|
||||||
|
? [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'paypal-approve',
|
||||||
|
'plus-checkout-return',
|
||||||
|
'sub2api-session-import',
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'paypal-approve',
|
||||||
|
'plus-checkout-return',
|
||||||
|
'oauth-login',
|
||||||
|
'fetch-login-code',
|
||||||
|
'post-login-phone-verification',
|
||||||
|
'confirm-oauth',
|
||||||
|
'platform-verify',
|
||||||
|
]
|
||||||
|
),
|
||||||
|
getState: async () => ({ ...state }),
|
||||||
|
getStepIdsForState: () => [],
|
||||||
|
setPersistentSettings: async (updates) => ({ ...updates }),
|
||||||
|
setState: async (updates) => {
|
||||||
|
state = { ...state, ...updates };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await router.handleMessage({
|
||||||
|
type: 'SAVE_SETTING',
|
||||||
|
payload: {
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(response.ok, true);
|
||||||
|
assert.equal(state.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
assert.equal(state.currentNodeId, '');
|
||||||
|
assert.equal(state.oauthUrl, null);
|
||||||
|
assert.equal(state.localhostUrl, null);
|
||||||
|
assert.equal(state.oauthFlowDeadlineAt, null);
|
||||||
|
assert.equal(state.oauthFlowDeadlineSourceUrl, null);
|
||||||
|
assert.equal(state.cpaOAuthState, null);
|
||||||
|
assert.equal(state.cpaManagementOrigin, null);
|
||||||
|
assert.equal(state.sub2apiSessionId, null);
|
||||||
|
assert.equal(state.sub2apiOAuthState, null);
|
||||||
|
assert.equal(state.sub2apiGroupId, null);
|
||||||
|
assert.deepStrictEqual(state.sub2apiGroupIds, []);
|
||||||
|
assert.equal(state.sub2apiDraftName, null);
|
||||||
|
assert.equal(state.sub2apiProxyId, null);
|
||||||
|
assert.equal(state.codex2apiSessionId, null);
|
||||||
|
assert.equal(state.codex2apiOAuthState, null);
|
||||||
|
assert.equal(state.plusManualConfirmationPending, false);
|
||||||
|
assert.equal(state.plusManualConfirmationRequestId, '');
|
||||||
|
assert.equal(state.plusManualConfirmationStep, 0);
|
||||||
|
assert.equal(state.plusManualConfirmationMethod, '');
|
||||||
|
assert.equal(state.plusManualConfirmationTitle, '');
|
||||||
|
assert.equal(state.plusManualConfirmationMessage, '');
|
||||||
|
assert.deepStrictEqual(state.nodeStatuses, {
|
||||||
|
'open-chatgpt': 'pending',
|
||||||
|
'plus-checkout-create': 'pending',
|
||||||
|
'plus-checkout-billing': 'pending',
|
||||||
|
'paypal-approve': 'pending',
|
||||||
|
'plus-checkout-return': 'pending',
|
||||||
|
'sub2api-session-import': 'pending',
|
||||||
|
});
|
||||||
|
assert.equal(Object.prototype.hasOwnProperty.call(state.nodeStatuses, 'oauth-login'), false);
|
||||||
|
assert.equal(Object.prototype.hasOwnProperty.call(state.nodeStatuses, 'platform-verify'), false);
|
||||||
|
assert.deepStrictEqual(broadcasts.at(-1), {
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
oauthUrl: null,
|
||||||
|
localhostUrl: null,
|
||||||
|
oauthFlowDeadlineAt: null,
|
||||||
|
oauthFlowDeadlineSourceUrl: null,
|
||||||
|
cpaOAuthState: null,
|
||||||
|
cpaManagementOrigin: null,
|
||||||
|
sub2apiSessionId: null,
|
||||||
|
sub2apiOAuthState: null,
|
||||||
|
sub2apiGroupId: null,
|
||||||
|
sub2apiGroupIds: [],
|
||||||
|
sub2apiDraftName: null,
|
||||||
|
sub2apiProxyId: null,
|
||||||
|
codex2apiSessionId: null,
|
||||||
|
codex2apiOAuthState: null,
|
||||||
|
plusManualConfirmationPending: false,
|
||||||
|
plusManualConfirmationRequestId: '',
|
||||||
|
plusManualConfirmationStep: 0,
|
||||||
|
plusManualConfirmationMethod: '',
|
||||||
|
plusManualConfirmationTitle: '',
|
||||||
|
plusManualConfirmationMessage: '',
|
||||||
|
nodeStatuses: {
|
||||||
|
'open-chatgpt': 'pending',
|
||||||
|
'plus-checkout-create': 'pending',
|
||||||
|
'plus-checkout-billing': 'pending',
|
||||||
|
'paypal-approve': 'pending',
|
||||||
|
'plus-checkout-return': 'pending',
|
||||||
|
'sub2api-session-import': 'pending',
|
||||||
|
},
|
||||||
|
currentNodeId: '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('SAVE_SETTING rebuilds Plus node statuses when panel mode forces the effective strategy back to OAuth', async () => {
|
||||||
|
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||||
|
const globalScope = { console };
|
||||||
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||||
|
const broadcasts = [];
|
||||||
|
let state = {
|
||||||
|
panelMode: 'sub2api',
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
oauthUrl: 'https://oauth.example/current',
|
||||||
|
localhostUrl: 'http://localhost:38080/callback',
|
||||||
|
sub2apiSessionId: 'sub-session',
|
||||||
|
plusManualConfirmationPending: true,
|
||||||
|
plusManualConfirmationRequestId: 'gopay-req',
|
||||||
|
plusManualConfirmationStep: 9,
|
||||||
|
plusManualConfirmationMethod: 'gopay',
|
||||||
|
plusManualConfirmationTitle: 'GoPay 订阅确认',
|
||||||
|
plusManualConfirmationMessage: '完成后继续导入当前 ChatGPT 会话到 SUB2API。',
|
||||||
|
currentNodeId: 'sub2api-session-import',
|
||||||
|
nodeStatuses: {
|
||||||
|
'open-chatgpt': 'completed',
|
||||||
|
'plus-checkout-create': 'completed',
|
||||||
|
'plus-checkout-billing': 'completed',
|
||||||
|
'paypal-approve': 'completed',
|
||||||
|
'plus-checkout-return': 'completed',
|
||||||
|
'sub2api-session-import': 'running',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const router = api.createMessageRouter({
|
||||||
|
addLog: async () => {},
|
||||||
|
buildLuckmailSessionSettingsPayload: () => ({}),
|
||||||
|
buildPersistentSettingsPayload: (input = {}) => Object.prototype.hasOwnProperty.call(input, 'panelMode')
|
||||||
|
? { panelMode: input.panelMode }
|
||||||
|
: {},
|
||||||
|
broadcastDataUpdate: (payload) => broadcasts.push(payload),
|
||||||
|
getNodeIdsForState: (nextState = {}) => (
|
||||||
|
String(nextState.panelMode || '').trim() === 'sub2api'
|
||||||
|
&& String(nextState.plusAccountAccessStrategy || '').trim() === 'sub2api_codex_session'
|
||||||
|
? [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'paypal-approve',
|
||||||
|
'plus-checkout-return',
|
||||||
|
'sub2api-session-import',
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'paypal-approve',
|
||||||
|
'plus-checkout-return',
|
||||||
|
'oauth-login',
|
||||||
|
'fetch-login-code',
|
||||||
|
'post-login-phone-verification',
|
||||||
|
'confirm-oauth',
|
||||||
|
'platform-verify',
|
||||||
|
]
|
||||||
|
),
|
||||||
|
getState: async () => ({ ...state }),
|
||||||
|
getStepIdsForState: () => [],
|
||||||
|
setPersistentSettings: async (updates) => ({ ...updates }),
|
||||||
|
setState: async (updates) => {
|
||||||
|
state = { ...state, ...updates };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = await router.handleMessage({
|
||||||
|
type: 'SAVE_SETTING',
|
||||||
|
payload: {
|
||||||
|
panelMode: 'cpa',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(response.ok, true);
|
||||||
|
assert.equal(state.panelMode, 'cpa');
|
||||||
|
assert.equal(state.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
assert.equal(state.currentNodeId, '');
|
||||||
|
assert.equal(state.oauthUrl, null);
|
||||||
|
assert.equal(state.localhostUrl, null);
|
||||||
|
assert.equal(state.sub2apiSessionId, null);
|
||||||
|
assert.equal(state.plusManualConfirmationPending, false);
|
||||||
|
assert.equal(state.plusManualConfirmationMessage, '');
|
||||||
|
assert.deepStrictEqual(state.nodeStatuses, {
|
||||||
|
'open-chatgpt': 'pending',
|
||||||
|
'plus-checkout-create': 'pending',
|
||||||
|
'plus-checkout-billing': 'pending',
|
||||||
|
'paypal-approve': 'pending',
|
||||||
|
'plus-checkout-return': 'pending',
|
||||||
|
'oauth-login': 'pending',
|
||||||
|
'fetch-login-code': 'pending',
|
||||||
|
'post-login-phone-verification': 'pending',
|
||||||
|
'confirm-oauth': 'pending',
|
||||||
|
'platform-verify': 'pending',
|
||||||
|
});
|
||||||
|
assert.equal(Object.prototype.hasOwnProperty.call(state.nodeStatuses, 'sub2api-session-import'), false);
|
||||||
|
assert.deepStrictEqual(broadcasts.at(-1), {
|
||||||
|
panelMode: 'cpa',
|
||||||
|
signupMethod: 'email',
|
||||||
|
oauthUrl: null,
|
||||||
|
localhostUrl: null,
|
||||||
|
oauthFlowDeadlineAt: null,
|
||||||
|
oauthFlowDeadlineSourceUrl: null,
|
||||||
|
cpaOAuthState: null,
|
||||||
|
cpaManagementOrigin: null,
|
||||||
|
sub2apiSessionId: null,
|
||||||
|
sub2apiOAuthState: null,
|
||||||
|
sub2apiGroupId: null,
|
||||||
|
sub2apiGroupIds: [],
|
||||||
|
sub2apiDraftName: null,
|
||||||
|
sub2apiProxyId: null,
|
||||||
|
codex2apiSessionId: null,
|
||||||
|
codex2apiOAuthState: null,
|
||||||
|
plusManualConfirmationPending: false,
|
||||||
|
plusManualConfirmationRequestId: '',
|
||||||
|
plusManualConfirmationStep: 0,
|
||||||
|
plusManualConfirmationMethod: '',
|
||||||
|
plusManualConfirmationTitle: '',
|
||||||
|
plusManualConfirmationMessage: '',
|
||||||
|
nodeStatuses: {
|
||||||
|
'open-chatgpt': 'pending',
|
||||||
|
'plus-checkout-create': 'pending',
|
||||||
|
'plus-checkout-billing': 'pending',
|
||||||
|
'paypal-approve': 'pending',
|
||||||
|
'plus-checkout-return': 'pending',
|
||||||
|
'oauth-login': 'pending',
|
||||||
|
'fetch-login-code': 'pending',
|
||||||
|
'post-login-phone-verification': 'pending',
|
||||||
|
'confirm-oauth': 'pending',
|
||||||
|
'platform-verify': 'pending',
|
||||||
|
},
|
||||||
|
currentNodeId: '',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('SAVE_SETTING mirrors activeFlowId into flowId when switching to kiro flow', async () => {
|
test('SAVE_SETTING mirrors activeFlowId into flowId when switching to kiro flow', async () => {
|
||||||
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
const source = fs.readFileSync('background/message-router.js', 'utf8');
|
||||||
const globalScope = { console };
|
const globalScope = { console };
|
||||||
|
|||||||
@@ -6,8 +6,25 @@ const source = fs.readFileSync('background/message-router.js', 'utf8');
|
|||||||
const globalScope = {};
|
const globalScope = {};
|
||||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundMessageRouter;`)(globalScope);
|
||||||
|
|
||||||
test('message router appends success record on Plus final step instead of hard-coded step 10', async () => {
|
function createRouterWithFinalNode(options = {}) {
|
||||||
|
const finalNodeId = String(options.finalNodeId || 'platform-verify').trim();
|
||||||
|
const nodeIds = Array.isArray(options.nodeIds) ? options.nodeIds.slice() : [
|
||||||
|
'open-chatgpt',
|
||||||
|
'oauth-login',
|
||||||
|
'fetch-login-code',
|
||||||
|
'confirm-oauth',
|
||||||
|
finalNodeId,
|
||||||
|
];
|
||||||
|
const nodeStepMap = {
|
||||||
|
'oauth-login': 10,
|
||||||
|
'fetch-login-code': 11,
|
||||||
|
'confirm-oauth': 12,
|
||||||
|
'platform-verify': 13,
|
||||||
|
'sub2api-session-import': 10,
|
||||||
|
...(options.nodeStepMap || {}),
|
||||||
|
};
|
||||||
const appendCalls = [];
|
const appendCalls = [];
|
||||||
|
|
||||||
const router = api.createMessageRouter({
|
const router = api.createMessageRouter({
|
||||||
addLog: async () => {},
|
addLog: async () => {},
|
||||||
appendAccountRunRecord: async (...args) => {
|
appendAccountRunRecord: async (...args) => {
|
||||||
@@ -43,12 +60,15 @@ test('message router appends success record on Plus final step instead of hard-c
|
|||||||
getCurrentLuckmailPurchase: () => null,
|
getCurrentLuckmailPurchase: () => null,
|
||||||
getPendingAutoRunTimerPlan: () => null,
|
getPendingAutoRunTimerPlan: () => null,
|
||||||
getSourceLabel: () => '',
|
getSourceLabel: () => '',
|
||||||
getState: async () => ({ plusModeEnabled: true, nodeStatuses: { 'platform-verify': 'pending' } }),
|
getState: async () => ({ plusModeEnabled: true, nodeStatuses: { [finalNodeId]: 'pending' } }),
|
||||||
getNodeIdsForState: () => ['open-chatgpt', 'oauth-login', 'fetch-login-code', 'confirm-oauth', 'platform-verify'],
|
getNodeIdsForState: () => nodeIds.slice(),
|
||||||
getStepIdByNodeIdForState: (nodeId) => ({ 'oauth-login': 10, 'fetch-login-code': 11, 'confirm-oauth': 12, 'platform-verify': 13 }[nodeId] || 0),
|
getStepIdByNodeIdForState: (nodeId) => nodeStepMap[nodeId] || 0,
|
||||||
getLastStepIdForState: () => 13,
|
getLastStepIdForState: () => Math.max(...Object.values(nodeStepMap)),
|
||||||
getStepDefinitionForState: (step) => ({ id: step, key: step === 10 ? 'oauth-login' : 'platform-verify' }),
|
getStepDefinitionForState: (step) => ({
|
||||||
getStepIdsForState: () => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
|
id: step,
|
||||||
|
key: Object.entries(nodeStepMap).find(([, mappedStep]) => mappedStep === step)?.[0] || finalNodeId,
|
||||||
|
}),
|
||||||
|
getStepIdsForState: () => Object.values(nodeStepMap),
|
||||||
getTabId: async () => null,
|
getTabId: async () => null,
|
||||||
getStopRequested: () => false,
|
getStopRequested: () => false,
|
||||||
handleAutoRunLoopUnhandledError: async () => {},
|
handleAutoRunLoopUnhandledError: async () => {},
|
||||||
@@ -100,8 +120,56 @@ test('message router appends success record on Plus final step instead of hard-c
|
|||||||
verifyHotmailAccount: async () => {},
|
verifyHotmailAccount: async () => {},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
appendCalls,
|
||||||
|
router,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test('message router appends success record on Plus final step instead of hard-coded step 10', async () => {
|
||||||
|
const { appendCalls, router } = createRouterWithFinalNode({
|
||||||
|
finalNodeId: 'platform-verify',
|
||||||
|
nodeIds: ['open-chatgpt', 'oauth-login', 'fetch-login-code', 'confirm-oauth', 'platform-verify'],
|
||||||
|
nodeStepMap: {
|
||||||
|
'oauth-login': 10,
|
||||||
|
'fetch-login-code': 11,
|
||||||
|
'confirm-oauth': 12,
|
||||||
|
'platform-verify': 13,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await router.handleMessage({ type: 'NODE_COMPLETE', nodeId: 'platform-verify', payload: { nodeId: 'platform-verify' } }, {});
|
await router.handleMessage({ type: 'NODE_COMPLETE', nodeId: 'platform-verify', payload: { nodeId: 'platform-verify' } }, {});
|
||||||
|
|
||||||
assert.equal(appendCalls.length, 1);
|
assert.equal(appendCalls.length, 1);
|
||||||
assert.equal(appendCalls[0][0], 'success');
|
assert.equal(appendCalls[0][0], 'success');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('message router appends success record when SUB2API session import is the final Plus node', async () => {
|
||||||
|
const { appendCalls, router } = createRouterWithFinalNode({
|
||||||
|
finalNodeId: 'sub2api-session-import',
|
||||||
|
nodeIds: [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'paypal-approve',
|
||||||
|
'plus-checkout-return',
|
||||||
|
'sub2api-session-import',
|
||||||
|
],
|
||||||
|
nodeStepMap: {
|
||||||
|
'plus-checkout-create': 6,
|
||||||
|
'plus-checkout-billing': 7,
|
||||||
|
'paypal-approve': 8,
|
||||||
|
'plus-checkout-return': 9,
|
||||||
|
'sub2api-session-import': 10,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await router.handleMessage({
|
||||||
|
type: 'NODE_COMPLETE',
|
||||||
|
nodeId: 'sub2api-session-import',
|
||||||
|
payload: { nodeId: 'sub2api-session-import' },
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
assert.equal(appendCalls.length, 1);
|
||||||
|
assert.equal(appendCalls[0][0], 'success');
|
||||||
|
});
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ const SETTINGS_SCHEMA_VIEW_KEYS = Object.freeze([
|
|||||||
'phoneSignupReloginAfterBindEmailEnabled',
|
'phoneSignupReloginAfterBindEmailEnabled',
|
||||||
'plusModeEnabled',
|
'plusModeEnabled',
|
||||||
'plusPaymentMethod',
|
'plusPaymentMethod',
|
||||||
|
'plusAccountAccessStrategy',
|
||||||
'mailProvider',
|
'mailProvider',
|
||||||
'ipProxyEnabled',
|
'ipProxyEnabled',
|
||||||
'ipProxyService',
|
'ipProxyService',
|
||||||
@@ -95,6 +96,7 @@ const PERSISTED_SETTING_DEFAULTS = {
|
|||||||
signupMethod: 'email',
|
signupMethod: 'email',
|
||||||
plusModeEnabled: false,
|
plusModeEnabled: false,
|
||||||
plusPaymentMethod: 'paypal',
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'oauth',
|
||||||
phoneVerificationEnabled: false,
|
phoneVerificationEnabled: false,
|
||||||
mailProvider: '163',
|
mailProvider: '163',
|
||||||
ipProxyEnabled: false,
|
ipProxyEnabled: false,
|
||||||
@@ -249,6 +251,7 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
|
|||||||
plus: {
|
plus: {
|
||||||
plusModeEnabled: false,
|
plusModeEnabled: false,
|
||||||
plusPaymentMethod: 'paypal',
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'oauth',
|
||||||
},
|
},
|
||||||
autoRun: {
|
autoRun: {
|
||||||
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 11 },
|
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 11 },
|
||||||
@@ -276,6 +279,7 @@ test('buildPersistentSettingsPayload accepts schema-only input when requireKnown
|
|||||||
assert.equal(payload.kiroRsKey, 'schema-only-key');
|
assert.equal(payload.kiroRsKey, 'schema-only-key');
|
||||||
assert.equal(Object.prototype.hasOwnProperty.call(payload, 'kiroRegion'), false);
|
assert.equal(Object.prototype.hasOwnProperty.call(payload, 'kiroRegion'), false);
|
||||||
assert.equal(payload.settingsSchemaVersion, 4);
|
assert.equal(payload.settingsSchemaVersion, 4);
|
||||||
|
assert.equal(payload.settingsState.flows.openai.plus.plusAccountAccessStrategy, 'oauth');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getPersistedSettings reads schema keys alongside legacy flat settings keys', async () => {
|
test('getPersistedSettings reads schema keys alongside legacy flat settings keys', async () => {
|
||||||
@@ -300,6 +304,7 @@ function getRequestedKeys() {
|
|||||||
|
|
||||||
assert.ok(api.getRequestedKeys().includes('settingsSchemaVersion'));
|
assert.ok(api.getRequestedKeys().includes('settingsSchemaVersion'));
|
||||||
assert.ok(api.getRequestedKeys().includes('settingsState'));
|
assert.ok(api.getRequestedKeys().includes('settingsState'));
|
||||||
|
assert.ok(api.getRequestedKeys().includes('plusAccountAccessStrategy'));
|
||||||
assert.equal(state.settingsSchemaVersion, 4);
|
assert.equal(state.settingsSchemaVersion, 4);
|
||||||
assert.equal(state.settingsState.activeFlowId, 'openai');
|
assert.equal(state.settingsState.activeFlowId, 'openai');
|
||||||
});
|
});
|
||||||
@@ -350,6 +355,7 @@ const chrome = {
|
|||||||
plus: {
|
plus: {
|
||||||
plusModeEnabled: false,
|
plusModeEnabled: false,
|
||||||
plusPaymentMethod: 'paypal',
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
},
|
},
|
||||||
autoRun: {
|
autoRun: {
|
||||||
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 11 },
|
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 11 },
|
||||||
@@ -384,6 +390,7 @@ const chrome = {
|
|||||||
assert.equal(state.ipProxyEnabled, true);
|
assert.equal(state.ipProxyEnabled, true);
|
||||||
assert.equal(state.kiroRsUrl, 'https://kiro.example.com/admin');
|
assert.equal(state.kiroRsUrl, 'https://kiro.example.com/admin');
|
||||||
assert.equal(state.kiroRsKey, 'stored-key');
|
assert.equal(state.kiroRsKey, 'stored-key');
|
||||||
|
assert.equal(state.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
assert.equal(Object.prototype.hasOwnProperty.call(state, 'kiroRegion'), false);
|
assert.equal(Object.prototype.hasOwnProperty.call(state, 'kiroRegion'), false);
|
||||||
assert.deepEqual(state.stepExecutionRangeByFlow.kiro, {
|
assert.deepEqual(state.stepExecutionRangeByFlow.kiro, {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -459,6 +466,7 @@ function getRemovedKeys() {
|
|||||||
plus: {
|
plus: {
|
||||||
plusModeEnabled: false,
|
plusModeEnabled: false,
|
||||||
plusPaymentMethod: 'paypal',
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
},
|
},
|
||||||
autoRun: {
|
autoRun: {
|
||||||
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 11 },
|
stepExecutionRange: { enabled: false, fromStep: 1, toStep: 11 },
|
||||||
@@ -486,6 +494,7 @@ function getRemovedKeys() {
|
|||||||
assert.equal(persisted.kiroTargetId, 'kiro-rs');
|
assert.equal(persisted.kiroTargetId, 'kiro-rs');
|
||||||
assert.equal(persisted.kiroRsUrl, 'https://kiro.example.com/admin');
|
assert.equal(persisted.kiroRsUrl, 'https://kiro.example.com/admin');
|
||||||
assert.equal(persisted.kiroRsKey, 'nested-only-key');
|
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(Object.prototype.hasOwnProperty.call(persisted, 'kiroRegion'), false);
|
||||||
assert.equal(persisted.settingsSchemaVersion, 4);
|
assert.equal(persisted.settingsSchemaVersion, 4);
|
||||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'activeFlowId'), false);
|
assert.equal(Object.prototype.hasOwnProperty.call(write, 'activeFlowId'), false);
|
||||||
@@ -494,6 +503,7 @@ function getRemovedKeys() {
|
|||||||
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRegion'), false);
|
assert.equal(Object.prototype.hasOwnProperty.call(write, 'kiroRegion'), false);
|
||||||
assert.equal(write.settingsSchemaVersion, 4);
|
assert.equal(write.settingsSchemaVersion, 4);
|
||||||
assert.equal(write.settingsState.activeFlowId, 'kiro');
|
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.equal(write.settingsState.flows.kiro.targetId, 'kiro-rs');
|
||||||
assert.ok(api.getRemovedKeys().includes('panelMode'));
|
assert.ok(api.getRemovedKeys().includes('panelMode'));
|
||||||
assert.ok(api.getRemovedKeys().includes('kiroRsUrl'));
|
assert.ok(api.getRemovedKeys().includes('kiroRsUrl'));
|
||||||
|
|||||||
@@ -0,0 +1,289 @@
|
|||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const test = require('node:test');
|
||||||
|
|
||||||
|
function createJsonResponse(payload, status = 200) {
|
||||||
|
return {
|
||||||
|
ok: status >= 200 && status < 300,
|
||||||
|
status,
|
||||||
|
text: async () => JSON.stringify(payload),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSub2ApiApiModule() {
|
||||||
|
const source = fs.readFileSync('background/sub2api-api.js', 'utf8');
|
||||||
|
return new Function('self', `${source}; return self.MultiPageBackgroundSub2ApiApi;`)({});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSub2ApiSessionImportModule() {
|
||||||
|
const source = fs.readFileSync('background/steps/sub2api-session-import.js', 'utf8');
|
||||||
|
return new Function('self', `${source}; return self.MultiPageBackgroundSub2ApiSessionImport;`)({});
|
||||||
|
}
|
||||||
|
|
||||||
|
test('sub2api api imports current ChatGPT session through codex-session endpoint', async () => {
|
||||||
|
const apiModule = loadSub2ApiApiModule();
|
||||||
|
const fetchCalls = [];
|
||||||
|
const logs = [];
|
||||||
|
const importExpiresAt = Math.floor(Date.parse('2026-05-20T12:34:56.000Z') / 1000);
|
||||||
|
|
||||||
|
const api = apiModule.createSub2ApiApi({
|
||||||
|
addLog: async (message, level = 'info', options = {}) => {
|
||||||
|
logs.push({ message, level, step: options.step, stepKey: options.stepKey });
|
||||||
|
},
|
||||||
|
normalizeSub2ApiUrl: (value) => value,
|
||||||
|
DEFAULT_SUB2API_GROUP_NAME: 'codex',
|
||||||
|
fetchImpl: async (url, options = {}) => {
|
||||||
|
const parsed = new URL(url);
|
||||||
|
const body = options.body ? JSON.parse(options.body) : null;
|
||||||
|
fetchCalls.push({ path: parsed.pathname, search: parsed.search, method: options.method || 'GET', body });
|
||||||
|
|
||||||
|
if (parsed.pathname === '/api/v1/auth/login') {
|
||||||
|
return createJsonResponse({
|
||||||
|
code: 0,
|
||||||
|
data: {
|
||||||
|
access_token: 'admin-token',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (parsed.pathname === '/api/v1/admin/groups/all') {
|
||||||
|
return createJsonResponse({
|
||||||
|
code: 0,
|
||||||
|
data: [
|
||||||
|
{ id: 5, name: 'codex', platform: 'openai' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (parsed.pathname === '/api/v1/admin/proxies/all') {
|
||||||
|
return createJsonResponse({
|
||||||
|
code: 0,
|
||||||
|
data: [{
|
||||||
|
id: 7,
|
||||||
|
name: 'shadowrocket',
|
||||||
|
protocol: 'socks5',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 1080,
|
||||||
|
status: 'active',
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (parsed.pathname === '/api/v1/admin/accounts/import/codex-session') {
|
||||||
|
const parsedContent = JSON.parse(body.content);
|
||||||
|
assert.equal(parsedContent.accessToken, 'access-token-from-state');
|
||||||
|
assert.equal(parsedContent.user?.email, 'flow@example.com');
|
||||||
|
assert.equal(body.priority, 3);
|
||||||
|
assert.equal(body.proxy_id, 7);
|
||||||
|
assert.deepStrictEqual(body.group_ids, [5]);
|
||||||
|
assert.equal(body.auto_pause_on_expired, true);
|
||||||
|
assert.equal(body.update_existing, true);
|
||||||
|
assert.equal(body.expires_at, importExpiresAt);
|
||||||
|
return createJsonResponse({
|
||||||
|
code: 0,
|
||||||
|
data: {
|
||||||
|
total: 1,
|
||||||
|
created: 0,
|
||||||
|
updated: 1,
|
||||||
|
skipped: 0,
|
||||||
|
failed: 0,
|
||||||
|
warnings: [{
|
||||||
|
index: 1,
|
||||||
|
message: '未包含 refresh_token,accessToken 过期后无法自动续期',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return createJsonResponse({ code: 1, message: `unexpected path ${parsed.pathname}` }, 404);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await api.importCurrentChatGptSession({
|
||||||
|
sub2apiUrl: 'https://sub.example/admin/accounts',
|
||||||
|
sub2apiEmail: 'admin@example.com',
|
||||||
|
sub2apiPassword: 'secret',
|
||||||
|
sub2apiGroupName: 'codex',
|
||||||
|
sub2apiDefaultProxyName: 'shadowrocket',
|
||||||
|
sub2apiAccountPriority: 3,
|
||||||
|
session: {
|
||||||
|
accessToken: 'access-token-from-session',
|
||||||
|
expires: '2026-05-20T12:34:56.000Z',
|
||||||
|
user: {
|
||||||
|
email: 'flow@example.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
accessToken: 'access-token-from-state',
|
||||||
|
}, {
|
||||||
|
logLabel: '步骤 10',
|
||||||
|
logOptions: { step: 10, stepKey: 'sub2api-session-import' },
|
||||||
|
timeoutMs: 120000,
|
||||||
|
});
|
||||||
|
|
||||||
|
const importCall = fetchCalls.find((call) => call.path === '/api/v1/admin/accounts/import/codex-session');
|
||||||
|
assert.ok(importCall, 'expected codex-session import call');
|
||||||
|
assert.equal(result.verifiedStatus, 'SUB2API 会话导入完成:新建 0,更新 1,跳过 0,失败 0');
|
||||||
|
assert.equal(result.sub2apiImportUpdated, 1);
|
||||||
|
assert.equal(
|
||||||
|
logs.some((entry) => entry.level === 'warn' && /refresh_token/.test(entry.message)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('session import step reads current ChatGPT session and completes node', async () => {
|
||||||
|
const moduleApi = loadSub2ApiSessionImportModule();
|
||||||
|
const completed = [];
|
||||||
|
const logs = [];
|
||||||
|
const ensureCalls = [];
|
||||||
|
const sentMessages = [];
|
||||||
|
const importedPayloads = [];
|
||||||
|
|
||||||
|
const executor = moduleApi.createSub2ApiSessionImportExecutor({
|
||||||
|
addLog: async (message, level = 'info', options = {}) => {
|
||||||
|
logs.push({ message, level, step: options.step, stepKey: options.stepKey });
|
||||||
|
},
|
||||||
|
chrome: {
|
||||||
|
tabs: {
|
||||||
|
get: async (tabId) => ({
|
||||||
|
id: tabId,
|
||||||
|
url: 'https://chatgpt.com/?model=gpt-4o',
|
||||||
|
}),
|
||||||
|
update: async () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
completeNodeFromBackground: async (nodeId, payload) => {
|
||||||
|
completed.push({ nodeId, payload });
|
||||||
|
},
|
||||||
|
createSub2ApiApi: () => ({
|
||||||
|
importCurrentChatGptSession: async (state, options) => {
|
||||||
|
importedPayloads.push({ state, options });
|
||||||
|
return {
|
||||||
|
verifiedStatus: 'SUB2API 会话导入完成:新建 1,更新 0,跳过 0,失败 0',
|
||||||
|
sub2apiImportCreated: 1,
|
||||||
|
sub2apiImportUpdated: 0,
|
||||||
|
sub2apiImportSkipped: 0,
|
||||||
|
sub2apiImportFailed: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
ensureContentScriptReadyOnTabUntilStopped: async (source, tabId, options = {}) => {
|
||||||
|
ensureCalls.push({ source, tabId, options });
|
||||||
|
},
|
||||||
|
getTabId: async () => null,
|
||||||
|
isTabAlive: async () => false,
|
||||||
|
normalizeSub2ApiUrl: (value) => value,
|
||||||
|
registerTab: async () => {},
|
||||||
|
sendTabMessageUntilStopped: async (tabId, source, message) => {
|
||||||
|
sentMessages.push({ tabId, source, message });
|
||||||
|
return {
|
||||||
|
session: {
|
||||||
|
accessToken: 'session-access-token',
|
||||||
|
expires: '2026-05-20T12:34:56.000Z',
|
||||||
|
user: {
|
||||||
|
email: 'flow@example.com',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
accessToken: 'session-access-token',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
waitForTabCompleteUntilStopped: async () => {},
|
||||||
|
DEFAULT_SUB2API_GROUP_NAME: 'codex',
|
||||||
|
});
|
||||||
|
|
||||||
|
await executor.executeSub2ApiSessionImport({
|
||||||
|
nodeId: 'sub2api-session-import',
|
||||||
|
visibleStep: 10,
|
||||||
|
plusCheckoutTabId: 91,
|
||||||
|
sub2apiUrl: 'https://sub.example/admin/accounts',
|
||||||
|
sub2apiEmail: 'admin@example.com',
|
||||||
|
sub2apiPassword: 'secret',
|
||||||
|
sub2apiGroupName: 'codex',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(ensureCalls.length, 1);
|
||||||
|
assert.equal(ensureCalls[0].source, 'plus-checkout');
|
||||||
|
assert.deepStrictEqual(ensureCalls[0].options.inject, [
|
||||||
|
'content/utils.js',
|
||||||
|
'content/operation-delay.js',
|
||||||
|
'content/plus-checkout.js',
|
||||||
|
]);
|
||||||
|
assert.deepStrictEqual(sentMessages, [{
|
||||||
|
tabId: 91,
|
||||||
|
source: 'plus-checkout',
|
||||||
|
message: {
|
||||||
|
type: 'PLUS_CHECKOUT_GET_STATE',
|
||||||
|
source: 'background',
|
||||||
|
payload: {
|
||||||
|
includeSession: true,
|
||||||
|
includeAccessToken: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}]);
|
||||||
|
assert.equal(importedPayloads.length, 1);
|
||||||
|
assert.equal(importedPayloads[0].state.accessToken, 'session-access-token');
|
||||||
|
assert.equal(importedPayloads[0].state.session.user.email, 'flow@example.com');
|
||||||
|
assert.equal(completed.length, 1);
|
||||||
|
assert.deepStrictEqual(completed[0], {
|
||||||
|
nodeId: 'sub2api-session-import',
|
||||||
|
payload: {
|
||||||
|
verifiedStatus: 'SUB2API 会话导入完成:新建 1,更新 0,跳过 0,失败 0',
|
||||||
|
sub2apiImportCreated: 1,
|
||||||
|
sub2apiImportUpdated: 0,
|
||||||
|
sub2apiImportSkipped: 0,
|
||||||
|
sub2apiImportFailed: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.equal(
|
||||||
|
logs.some((entry) => entry.stepKey === 'sub2api-session-import' && /读取当前 ChatGPT 登录会话/.test(entry.message)),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('session import step rejects unsupported non-chatgpt tabs before reading session', async () => {
|
||||||
|
const moduleApi = loadSub2ApiSessionImportModule();
|
||||||
|
let sendCalled = false;
|
||||||
|
|
||||||
|
const executor = moduleApi.createSub2ApiSessionImportExecutor({
|
||||||
|
addLog: async () => {},
|
||||||
|
chrome: {
|
||||||
|
tabs: {
|
||||||
|
get: async (tabId) => ({
|
||||||
|
id: tabId,
|
||||||
|
url: 'https://example.com/not-chatgpt',
|
||||||
|
}),
|
||||||
|
update: async () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
completeNodeFromBackground: async () => {},
|
||||||
|
createSub2ApiApi: () => ({
|
||||||
|
importCurrentChatGptSession: async () => ({}),
|
||||||
|
}),
|
||||||
|
ensureContentScriptReadyOnTabUntilStopped: async () => {},
|
||||||
|
getTabId: async () => 91,
|
||||||
|
isTabAlive: async () => true,
|
||||||
|
normalizeSub2ApiUrl: (value) => value,
|
||||||
|
sendTabMessageUntilStopped: async () => {
|
||||||
|
sendCalled = true;
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
sleepWithStop: async () => {},
|
||||||
|
throwIfStopped: () => {},
|
||||||
|
waitForTabCompleteUntilStopped: async () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
await assert.rejects(
|
||||||
|
() => executor.executeSub2ApiSessionImport({
|
||||||
|
nodeId: 'sub2api-session-import',
|
||||||
|
visibleStep: 10,
|
||||||
|
}),
|
||||||
|
/当前标签页不在 ChatGPT \/ OpenAI 页面/
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(sendCalled, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('background wires sub2api session import executor into the workflow runtime', () => {
|
||||||
|
const source = fs.readFileSync('background.js', 'utf8');
|
||||||
|
assert.match(source, /background\/steps\/sub2api-session-import\.js/);
|
||||||
|
assert.match(source, /'sub2api-session-import': \(state\) => sub2ApiSessionImportExecutor\.executeSub2ApiSessionImport\(state\)/);
|
||||||
|
assert.match(source, /'sub2api-session-import',\s*\n\s*'oauth-login'/);
|
||||||
|
});
|
||||||
@@ -191,3 +191,48 @@ test('flow capability registry normalizes unsupported mode switches back to the
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('flow capability registry exposes editable Plus account access strategies for SUB2API', () => {
|
||||||
|
const api = loadApi();
|
||||||
|
const registry = api.createFlowCapabilityRegistry();
|
||||||
|
|
||||||
|
const capabilityState = registry.resolveSidepanelCapabilities({
|
||||||
|
state: {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
openaiIntegrationTargetId: 'sub2api',
|
||||||
|
signupMethod: 'email',
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
capabilityState.availablePlusAccountAccessStrategies,
|
||||||
|
['oauth', 'sub2api_codex_session']
|
||||||
|
);
|
||||||
|
assert.equal(capabilityState.requestedPlusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
assert.equal(capabilityState.effectivePlusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
assert.equal(capabilityState.canEditPlusAccountAccessStrategy, true);
|
||||||
|
assert.equal(capabilityState.stepDefinitionOptions.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('flow capability registry preserves requested Plus account strategy while forcing OAuth on unsupported targets', () => {
|
||||||
|
const api = loadApi();
|
||||||
|
const registry = api.createFlowCapabilityRegistry();
|
||||||
|
|
||||||
|
const capabilityState = registry.resolveSidepanelCapabilities({
|
||||||
|
state: {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
openaiIntegrationTargetId: 'cpa',
|
||||||
|
signupMethod: 'email',
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(capabilityState.availablePlusAccountAccessStrategies, ['oauth']);
|
||||||
|
assert.equal(capabilityState.requestedPlusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
assert.equal(capabilityState.effectivePlusAccountAccessStrategy, 'oauth');
|
||||||
|
assert.equal(capabilityState.canEditPlusAccountAccessStrategy, false);
|
||||||
|
assert.equal(capabilityState.stepDefinitionOptions.plusAccountAccessStrategy, 'oauth');
|
||||||
|
});
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ test('flow registry exposes canonical flow and target metadata', () => {
|
|||||||
flowRegistry.getTargetOptions('openai').map((entry) => entry.id),
|
flowRegistry.getTargetOptions('openai').map((entry) => entry.id),
|
||||||
['cpa', 'sub2api', 'codex2api']
|
['cpa', 'sub2api', 'codex2api']
|
||||||
);
|
);
|
||||||
|
assert.deepEqual(
|
||||||
|
flowRegistry.getSettingsGroupDefinition('openai-plus')?.rowIds,
|
||||||
|
['row-plus-mode', 'row-plus-payment-method', 'row-plus-account-access-strategy']
|
||||||
|
);
|
||||||
assert.equal(flowRegistry.getPublicationTargetDefinition('kiro', 'kiro-rs')?.label, 'kiro.rs');
|
assert.equal(flowRegistry.getPublicationTargetDefinition('kiro', 'kiro-rs')?.label, 'kiro.rs');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,6 +52,7 @@ test('settings schema normalizes view input into canonical nested namespaces', (
|
|||||||
ipProxyEnabled: true,
|
ipProxyEnabled: true,
|
||||||
ipProxyService: '711proxy',
|
ipProxyService: '711proxy',
|
||||||
customPassword: 'SharedSecret123!',
|
customPassword: 'SharedSecret123!',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
kiroRsUrl: 'https://kiro.example.com/admin',
|
kiroRsUrl: 'https://kiro.example.com/admin',
|
||||||
kiroRsKey: 'secret-key',
|
kiroRsKey: 'secret-key',
|
||||||
stepExecutionRangeByFlow: {
|
stepExecutionRangeByFlow: {
|
||||||
@@ -61,6 +66,7 @@ test('settings schema normalizes view input into canonical nested namespaces', (
|
|||||||
assert.equal(normalized.services.proxy.enabled, true);
|
assert.equal(normalized.services.proxy.enabled, true);
|
||||||
assert.equal(normalized.services.account.customPassword, 'SharedSecret123!');
|
assert.equal(normalized.services.account.customPassword, 'SharedSecret123!');
|
||||||
assert.equal(normalized.flows.openai.integrationTargetId, 'sub2api');
|
assert.equal(normalized.flows.openai.integrationTargetId, 'sub2api');
|
||||||
|
assert.equal(normalized.flows.openai.plus.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
assert.equal(normalized.flows.kiro.targetId, 'kiro-rs');
|
assert.equal(normalized.flows.kiro.targetId, 'kiro-rs');
|
||||||
assert.equal(normalized.flows.kiro.targets['kiro-rs'].baseUrl, 'https://kiro.example.com/admin');
|
assert.equal(normalized.flows.kiro.targets['kiro-rs'].baseUrl, 'https://kiro.example.com/admin');
|
||||||
assert.equal(normalized.flows.kiro.targets['kiro-rs'].apiKey, 'secret-key');
|
assert.equal(normalized.flows.kiro.targets['kiro-rs'].apiKey, 'secret-key');
|
||||||
@@ -79,6 +85,7 @@ test('settings schema can project canonical state into a read view without legac
|
|||||||
kiroTargetId: 'kiro-rs',
|
kiroTargetId: 'kiro-rs',
|
||||||
kiroRsUrl: 'https://kiro.example.com/admin',
|
kiroRsUrl: 'https://kiro.example.com/admin',
|
||||||
kiroRsKey: 'key-123',
|
kiroRsKey: 'key-123',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
});
|
});
|
||||||
const view = schema.buildSettingsView(normalized);
|
const view = schema.buildSettingsView(normalized);
|
||||||
|
|
||||||
@@ -88,6 +95,7 @@ test('settings schema can project canonical state into a read view without legac
|
|||||||
assert.equal(view.panelMode, 'cpa');
|
assert.equal(view.panelMode, 'cpa');
|
||||||
assert.equal(view.kiroRsUrl, 'https://kiro.example.com/admin');
|
assert.equal(view.kiroRsUrl, 'https://kiro.example.com/admin');
|
||||||
assert.equal(view.kiroRsKey, 'key-123');
|
assert.equal(view.kiroRsKey, 'key-123');
|
||||||
|
assert.equal(view.plusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
assert.equal(view.settingsSchemaVersion, 4);
|
assert.equal(view.settingsSchemaVersion, 4);
|
||||||
assert.equal(view.settingsState.activeFlowId, 'kiro');
|
assert.equal(view.settingsState.activeFlowId, 'kiro');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const source = fs.readFileSync('background/steps/gopay-manual-confirm.js', 'utf8
|
|||||||
const globalScope = {};
|
const globalScope = {};
|
||||||
const api = new Function('self', `${source}; return self.MultiPageBackgroundGoPayManualConfirm;`)(globalScope);
|
const api = new Function('self', `${source}; return self.MultiPageBackgroundGoPayManualConfirm;`)(globalScope);
|
||||||
|
|
||||||
test('GoPay manual confirm executor publishes pending manual confirmation state for step 7', async () => {
|
test('GoPay manual confirm executor publishes pending manual confirmation state for OAuth continuation', async () => {
|
||||||
const stateUpdates = [];
|
const stateUpdates = [];
|
||||||
const broadcasts = [];
|
const broadcasts = [];
|
||||||
const events = [];
|
const events = [];
|
||||||
@@ -24,6 +24,13 @@ test('GoPay manual confirm executor publishes pending manual confirmation state
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
getNodeIdsForState: () => [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'gopay-subscription-confirm',
|
||||||
|
'oauth-login',
|
||||||
|
],
|
||||||
getTabId: async () => 42,
|
getTabId: async () => 42,
|
||||||
isTabAlive: async () => true,
|
isTabAlive: async () => true,
|
||||||
registerTab: async () => {},
|
registerTab: async () => {},
|
||||||
@@ -32,17 +39,70 @@ test('GoPay manual confirm executor publishes pending manual confirmation state
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await executor.executeGoPayManualConfirm({ plusCheckoutTabId: 42, plusCheckoutUrl: 'https://chatgpt.com/checkout/openai_llc/session' });
|
await executor.executeGoPayManualConfirm({
|
||||||
|
nodeId: 'gopay-subscription-confirm',
|
||||||
|
plusCheckoutTabId: 42,
|
||||||
|
plusCheckoutUrl: 'https://chatgpt.com/checkout/openai_llc/session',
|
||||||
|
});
|
||||||
|
|
||||||
assert.equal(stateUpdates.length, 1);
|
assert.equal(stateUpdates.length, 1);
|
||||||
assert.equal(stateUpdates[0].plusManualConfirmationPending, true);
|
assert.equal(stateUpdates[0].plusManualConfirmationPending, true);
|
||||||
assert.equal(stateUpdates[0].plusManualConfirmationMethod, 'gopay');
|
assert.equal(stateUpdates[0].plusManualConfirmationMethod, 'gopay');
|
||||||
assert.equal(stateUpdates[0].plusManualConfirmationStep, 7);
|
assert.equal(stateUpdates[0].plusManualConfirmationStep, 7);
|
||||||
assert.match(String(stateUpdates[0].plusManualConfirmationRequestId || ''), /^gopay-/);
|
assert.match(String(stateUpdates[0].plusManualConfirmationRequestId || ''), /^gopay-/);
|
||||||
|
assert.match(stateUpdates[0].plusManualConfirmationMessage, /OAuth 登录/);
|
||||||
assert.equal(broadcasts.length, 1);
|
assert.equal(broadcasts.length, 1);
|
||||||
assert.equal(broadcasts[0].plusManualConfirmationPending, true);
|
assert.equal(broadcasts[0].plusManualConfirmationPending, true);
|
||||||
assert.deepStrictEqual(
|
assert.deepStrictEqual(
|
||||||
events.find((event) => event.type === 'tab-update'),
|
events.find((event) => event.type === 'tab-update'),
|
||||||
{ type: 'tab-update', tabId: 42, payload: { active: true } }
|
{ type: 'tab-update', tabId: 42, payload: { active: true } }
|
||||||
);
|
);
|
||||||
|
assert.match(
|
||||||
|
events.find((event) => event.type === 'log')?.message || '',
|
||||||
|
/确认后继续OAuth 登录/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('GoPay manual confirm executor switches continuation copy to SUB2API session import when the effective tail is session-based', async () => {
|
||||||
|
const stateUpdates = [];
|
||||||
|
const events = [];
|
||||||
|
const executor = api.createGoPayManualConfirmExecutor({
|
||||||
|
addLog: async (message, level = 'info') => {
|
||||||
|
events.push({ type: 'log', message, level });
|
||||||
|
},
|
||||||
|
broadcastDataUpdate: () => {},
|
||||||
|
chrome: {
|
||||||
|
tabs: {
|
||||||
|
update: async () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
getNodeIdsForState: () => [
|
||||||
|
'open-chatgpt',
|
||||||
|
'plus-checkout-create',
|
||||||
|
'plus-checkout-billing',
|
||||||
|
'gopay-subscription-confirm',
|
||||||
|
'sub2api-session-import',
|
||||||
|
],
|
||||||
|
getTabId: async () => 42,
|
||||||
|
isTabAlive: async () => true,
|
||||||
|
registerTab: async () => {},
|
||||||
|
setState: async (payload) => {
|
||||||
|
stateUpdates.push(payload);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await executor.executeGoPayManualConfirm({
|
||||||
|
nodeId: 'gopay-subscription-confirm',
|
||||||
|
visibleStep: 9,
|
||||||
|
plusCheckoutTabId: 42,
|
||||||
|
plusCheckoutUrl: 'https://chatgpt.com/checkout/openai_llc/session',
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(stateUpdates.length, 1);
|
||||||
|
assert.equal(stateUpdates[0].plusManualConfirmationStep, 9);
|
||||||
|
assert.match(stateUpdates[0].plusManualConfirmationMessage, /导入当前 ChatGPT 会话到 SUB2API/);
|
||||||
|
assert.match(
|
||||||
|
events.find((event) => event.type === 'log')?.message || '',
|
||||||
|
/确认后继续导入当前 ChatGPT 会话到 SUB2API/
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,270 @@
|
|||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
|
||||||
|
const sidepanelSource = fs.readFileSync('sidepanel/sidepanel.js', 'utf8');
|
||||||
|
|
||||||
|
function extractFunction(name) {
|
||||||
|
const markers = [`async function ${name}(`, `function ${name}(`];
|
||||||
|
const start = markers
|
||||||
|
.map((marker) => sidepanelSource.indexOf(marker))
|
||||||
|
.find((index) => index >= 0);
|
||||||
|
if (start < 0) {
|
||||||
|
throw new Error(`missing function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let parenDepth = 0;
|
||||||
|
let signatureEnded = false;
|
||||||
|
let braceStart = -1;
|
||||||
|
for (let i = start; i < sidepanelSource.length; i += 1) {
|
||||||
|
const ch = sidepanelSource[i];
|
||||||
|
if (ch === '(') parenDepth += 1;
|
||||||
|
if (ch === ')') {
|
||||||
|
parenDepth -= 1;
|
||||||
|
if (parenDepth === 0) signatureEnded = true;
|
||||||
|
}
|
||||||
|
if (ch === '{' && signatureEnded) {
|
||||||
|
braceStart = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (braceStart < 0) {
|
||||||
|
throw new Error(`missing body for function ${name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let depth = 0;
|
||||||
|
let end = braceStart;
|
||||||
|
for (; end < sidepanelSource.length; end += 1) {
|
||||||
|
const ch = sidepanelSource[end];
|
||||||
|
if (ch === '{') depth += 1;
|
||||||
|
if (ch === '}') {
|
||||||
|
depth -= 1;
|
||||||
|
if (depth === 0) {
|
||||||
|
end += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sidepanelSource.slice(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildHarness(capabilityStateSource, stateSource) {
|
||||||
|
return new Function(`
|
||||||
|
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
||||||
|
const PLUS_PAYMENT_METHOD_GOPAY = 'gopay';
|
||||||
|
const PLUS_PAYMENT_METHOD_GPC_HELPER = 'gpc-helper';
|
||||||
|
const DEFAULT_PLUS_PAYMENT_METHOD = 'paypal';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = 'oauth';
|
||||||
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
|
${extractFunction('normalizePlusAccountAccessStrategy')}
|
||||||
|
${extractFunction('getRequestedPlusAccountAccessStrategy')}
|
||||||
|
${extractFunction('updatePlusModeUI')}
|
||||||
|
function normalizePlusPaymentMethod(value = '') {
|
||||||
|
const normalized = String(value || '').trim().toLowerCase();
|
||||||
|
return normalized === 'gopay' || normalized === 'gpc-helper' ? normalized : 'paypal';
|
||||||
|
}
|
||||||
|
function getSelectedPlusPaymentMethod() {
|
||||||
|
return normalizePlusPaymentMethod(selectPlusPaymentMethod.value || latestState?.plusPaymentMethod || currentPlusPaymentMethod || 'paypal');
|
||||||
|
}
|
||||||
|
function normalizeGpcHelperPhoneModeValue(value = '') {
|
||||||
|
return String(value || '').trim().toLowerCase() === 'auto' ? 'auto' : 'manual';
|
||||||
|
}
|
||||||
|
function normalizeGpcOtpChannelValue(value = '') {
|
||||||
|
return String(value || '').trim().toLowerCase() === 'sms' ? 'sms' : 'whatsapp';
|
||||||
|
}
|
||||||
|
function isGpcAutoModePermissionDenied() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function getSelectedPanelMode() {
|
||||||
|
return latestState?.panelMode || 'cpa';
|
||||||
|
}
|
||||||
|
function resolveCurrentSidepanelCapabilities() {
|
||||||
|
return ${capabilityStateSource};
|
||||||
|
}
|
||||||
|
let latestState = ${stateSource};
|
||||||
|
let currentPlusPaymentMethod = 'paypal';
|
||||||
|
let currentPlusAccountAccessStrategy = latestState.plusAccountAccessStrategy || 'oauth';
|
||||||
|
const inputPlusModeEnabled = { checked: true };
|
||||||
|
const rowPlusMode = { style: { display: '' } };
|
||||||
|
const rowPlusPaymentMethod = { style: { display: 'none' } };
|
||||||
|
const rowPlusAccountAccessStrategy = { style: { display: 'none' } };
|
||||||
|
const rowPayPalAccount = { style: { display: 'none' } };
|
||||||
|
const selectPlusPaymentMethod = { value: latestState.plusPaymentMethod || 'paypal', style: { display: 'none' } };
|
||||||
|
const selectPlusAccountAccessStrategy = {
|
||||||
|
value: latestState.plusAccountAccessStrategy || 'oauth',
|
||||||
|
disabled: false,
|
||||||
|
dataset: { requestedValue: latestState.plusAccountAccessStrategy || 'oauth' },
|
||||||
|
setAttribute(name, value) {
|
||||||
|
this[name] = value;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const plusPaymentMethodCaption = { textContent: '' };
|
||||||
|
const plusAccountAccessStrategyCaption = { textContent: '' };
|
||||||
|
return {
|
||||||
|
getRequestedPlusAccountAccessStrategy,
|
||||||
|
plusAccountAccessStrategyCaption,
|
||||||
|
rowPlusAccountAccessStrategy,
|
||||||
|
selectPlusAccountAccessStrategy,
|
||||||
|
updatePlusModeUI,
|
||||||
|
};
|
||||||
|
`)();
|
||||||
|
}
|
||||||
|
|
||||||
|
test('sidepanel keeps requested Plus account strategy while OAuth-only targets force the effective value', () => {
|
||||||
|
const api = buildHarness(
|
||||||
|
`{
|
||||||
|
canShowPlusSettings: true,
|
||||||
|
runtimeLocks: { plusModeEnabled: true },
|
||||||
|
canEditPlusAccountAccessStrategy: false,
|
||||||
|
effectivePlusAccountAccessStrategy: 'oauth',
|
||||||
|
}`,
|
||||||
|
`{
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
panelMode: 'cpa',
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
|
||||||
|
api.updatePlusModeUI();
|
||||||
|
|
||||||
|
assert.equal(api.rowPlusAccountAccessStrategy.style.display, '');
|
||||||
|
assert.equal(api.selectPlusAccountAccessStrategy.disabled, true);
|
||||||
|
assert.equal(api.selectPlusAccountAccessStrategy.dataset.requestedValue, 'sub2api_codex_session');
|
||||||
|
assert.equal(api.selectPlusAccountAccessStrategy.value, 'oauth');
|
||||||
|
assert.equal(api.getRequestedPlusAccountAccessStrategy(), 'sub2api_codex_session');
|
||||||
|
assert.match(api.plusAccountAccessStrategyCaption.textContent, /OAuth/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sidepanel enables SUB2API session strategy selection when the current Plus target supports it', () => {
|
||||||
|
const api = buildHarness(
|
||||||
|
`{
|
||||||
|
canShowPlusSettings: true,
|
||||||
|
runtimeLocks: { plusModeEnabled: true },
|
||||||
|
canEditPlusAccountAccessStrategy: true,
|
||||||
|
effectivePlusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
}`,
|
||||||
|
`{
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
panelMode: 'sub2api',
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
|
||||||
|
api.updatePlusModeUI();
|
||||||
|
|
||||||
|
assert.equal(api.rowPlusAccountAccessStrategy.style.display, '');
|
||||||
|
assert.equal(api.selectPlusAccountAccessStrategy.disabled, false);
|
||||||
|
assert.equal(api.selectPlusAccountAccessStrategy.value, 'sub2api_codex_session');
|
||||||
|
assert.equal(api.getRequestedPlusAccountAccessStrategy(), 'sub2api_codex_session');
|
||||||
|
assert.match(api.plusAccountAccessStrategyCaption.textContent, /SUB2API/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sidepanel rebuilds step definitions and workflow nodes with the effective Plus account strategy', () => {
|
||||||
|
const bundle = [
|
||||||
|
extractFunction('normalizeSignupMethod'),
|
||||||
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
|
extractFunction('getStepDefinitionsForMode'),
|
||||||
|
extractFunction('getWorkflowNodesForMode'),
|
||||||
|
extractFunction('rebuildStepDefinitionState'),
|
||||||
|
extractFunction('syncStepDefinitionsForMode'),
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
const api = new Function(`
|
||||||
|
const calls = [];
|
||||||
|
const window = {
|
||||||
|
MultiPageStepDefinitions: {
|
||||||
|
getSteps(options) {
|
||||||
|
calls.push({ type: 'getSteps', options });
|
||||||
|
return [{ id: 10, order: 100, key: 'sub2api-session-import', title: 'session-import' }];
|
||||||
|
},
|
||||||
|
getNodes(options) {
|
||||||
|
calls.push({ type: 'getNodes', options });
|
||||||
|
return [{ nodeId: 'sub2api-session-import', displayOrder: 10, next: [] }];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let latestState = { activeFlowId: 'openai' };
|
||||||
|
let currentPlusModeEnabled = false;
|
||||||
|
let currentPlusPaymentMethod = 'paypal';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
let currentPlusAccountAccessStrategy = 'oauth';
|
||||||
|
let currentSignupMethod = 'email';
|
||||||
|
let currentPhoneSignupReloginAfterBindEmailEnabled = false;
|
||||||
|
let currentStepDefinitionFlowId = 'openai';
|
||||||
|
const DEFAULT_ACTIVE_FLOW_ID = 'openai';
|
||||||
|
const DEFAULT_PLUS_PAYMENT_METHOD = 'paypal';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = 'oauth';
|
||||||
|
const DEFAULT_SIGNUP_METHOD = 'email';
|
||||||
|
let stepDefinitions = [];
|
||||||
|
let workflowNodes = [];
|
||||||
|
let STEP_IDS = [];
|
||||||
|
let STEP_DEFAULT_STATUSES = {};
|
||||||
|
let SKIPPABLE_STEPS = new Set();
|
||||||
|
let NODE_IDS = [];
|
||||||
|
let NODE_DEFAULT_STATUSES = {};
|
||||||
|
function getSelectedPlusPaymentMethod() {
|
||||||
|
return currentPlusPaymentMethod;
|
||||||
|
}
|
||||||
|
function renderStepsList() {}
|
||||||
|
${bundle}
|
||||||
|
return {
|
||||||
|
calls,
|
||||||
|
syncStepDefinitionsForMode,
|
||||||
|
snapshot() {
|
||||||
|
return {
|
||||||
|
currentPlusAccountAccessStrategy,
|
||||||
|
workflowNodes,
|
||||||
|
stepDefinitions,
|
||||||
|
STEP_IDS,
|
||||||
|
NODE_IDS,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
`)();
|
||||||
|
|
||||||
|
api.syncStepDefinitionsForMode(true, {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
signupMethod: 'email',
|
||||||
|
render: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const snapshot = api.snapshot();
|
||||||
|
assert.equal(snapshot.currentPlusAccountAccessStrategy, 'sub2api_codex_session');
|
||||||
|
assert.deepStrictEqual(snapshot.STEP_IDS, [10]);
|
||||||
|
assert.deepStrictEqual(snapshot.NODE_IDS, ['sub2api-session-import']);
|
||||||
|
assert.equal(snapshot.stepDefinitions[0]?.key, 'sub2api-session-import');
|
||||||
|
assert.equal(snapshot.workflowNodes[0]?.nodeId, 'sub2api-session-import');
|
||||||
|
assert.deepStrictEqual(api.calls, [
|
||||||
|
{
|
||||||
|
type: 'getSteps',
|
||||||
|
options: {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
signupMethod: 'email',
|
||||||
|
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'getNodes',
|
||||||
|
options: {
|
||||||
|
activeFlowId: 'openai',
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
signupMethod: 'email',
|
||||||
|
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
@@ -65,6 +65,7 @@ test('sidepanel step definitions keep the selected Plus payment method', () => {
|
|||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizeSignupMethod'),
|
extractFunction('normalizeSignupMethod'),
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getStepDefinitionsForMode'),
|
extractFunction('getStepDefinitionsForMode'),
|
||||||
extractFunction('rebuildStepDefinitionState'),
|
extractFunction('rebuildStepDefinitionState'),
|
||||||
extractFunction('syncStepDefinitionsForMode'),
|
extractFunction('syncStepDefinitionsForMode'),
|
||||||
@@ -82,6 +83,10 @@ const window = {
|
|||||||
};
|
};
|
||||||
let currentPlusModeEnabled = false;
|
let currentPlusModeEnabled = false;
|
||||||
let currentPlusPaymentMethod = 'paypal';
|
let currentPlusPaymentMethod = 'paypal';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
|
let currentPlusAccountAccessStrategy = DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY;
|
||||||
let currentSignupMethod = 'email';
|
let currentSignupMethod = 'email';
|
||||||
let currentPhoneSignupReloginAfterBindEmailEnabled = false;
|
let currentPhoneSignupReloginAfterBindEmailEnabled = false;
|
||||||
const DEFAULT_SIGNUP_METHOD = 'email';
|
const DEFAULT_SIGNUP_METHOD = 'email';
|
||||||
@@ -107,7 +112,7 @@ return {
|
|||||||
assert.deepEqual(api.getStepIds(), [7]);
|
assert.deepEqual(api.getStepIds(), [7]);
|
||||||
assert.deepEqual(api.calls[0], {
|
assert.deepEqual(api.calls[0], {
|
||||||
type: 'getSteps',
|
type: 'getSteps',
|
||||||
options: { activeFlowId: 'openai', plusModeEnabled: true, plusPaymentMethod: 'gopay', signupMethod: 'email', phoneSignupReloginAfterBindEmailEnabled: false },
|
options: { activeFlowId: 'openai', plusModeEnabled: true, plusPaymentMethod: 'gopay', plusAccountAccessStrategy: 'oauth', signupMethod: 'email', phoneSignupReloginAfterBindEmailEnabled: false },
|
||||||
});
|
});
|
||||||
assert.deepEqual(api.calls[1], { type: 'render', stepIds: [7] });
|
assert.deepEqual(api.calls[1], { type: 'render', stepIds: [7] });
|
||||||
});
|
});
|
||||||
@@ -141,7 +146,9 @@ test('sidepanel applies restored signup method when rebuilding shared step defin
|
|||||||
test('sidepanel Plus UI hides PayPal account selector while GoPay is selected', () => {
|
test('sidepanel Plus UI hides PayPal account selector while GoPay is selected', () => {
|
||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getSelectedPlusPaymentMethod'),
|
extractFunction('getSelectedPlusPaymentMethod'),
|
||||||
|
extractFunction('getRequestedPlusAccountAccessStrategy'),
|
||||||
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
||||||
extractFunction('getGpcHelperAutoModeEnabled'),
|
extractFunction('getGpcHelperAutoModeEnabled'),
|
||||||
extractFunction('normalizeGpcAutoModePermissionValue'),
|
extractFunction('normalizeGpcAutoModePermissionValue'),
|
||||||
@@ -156,10 +163,14 @@ test('sidepanel Plus UI hides PayPal account selector while GoPay is selected',
|
|||||||
const api = new Function(`
|
const api = new Function(`
|
||||||
let latestState = { plusPaymentMethod: 'gopay' };
|
let latestState = { plusPaymentMethod: 'gopay' };
|
||||||
let currentPlusPaymentMethod = 'paypal';
|
let currentPlusPaymentMethod = 'paypal';
|
||||||
|
let currentPlusAccountAccessStrategy = 'oauth';
|
||||||
const inputPlusModeEnabled = { checked: true };
|
const inputPlusModeEnabled = { checked: true };
|
||||||
const selectPlusPaymentMethod = { value: 'gopay', style: { display: 'none' } };
|
const selectPlusPaymentMethod = { value: 'gopay', style: { display: 'none' } };
|
||||||
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
const rowPayPalAccount = { style: { display: '' } };
|
const rowPayPalAccount = { style: { display: '' } };
|
||||||
${bundle}
|
${bundle}
|
||||||
return { updatePlusModeUI, selectPlusPaymentMethod, rowPayPalAccount };
|
return { updatePlusModeUI, selectPlusPaymentMethod, rowPayPalAccount };
|
||||||
@@ -178,7 +189,9 @@ return { updatePlusModeUI, selectPlusPaymentMethod, rowPayPalAccount };
|
|||||||
test('sidepanel Plus UI can hide Plus controls when the shared flow capability registry disables them', () => {
|
test('sidepanel Plus UI can hide Plus controls when the shared flow capability registry disables them', () => {
|
||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getSelectedPlusPaymentMethod'),
|
extractFunction('getSelectedPlusPaymentMethod'),
|
||||||
|
extractFunction('getRequestedPlusAccountAccessStrategy'),
|
||||||
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
||||||
extractFunction('getGpcHelperAutoModeEnabled'),
|
extractFunction('getGpcHelperAutoModeEnabled'),
|
||||||
extractFunction('normalizeGpcAutoModePermissionValue'),
|
extractFunction('normalizeGpcAutoModePermissionValue'),
|
||||||
@@ -206,6 +219,7 @@ const window = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let latestState = { plusPaymentMethod: 'paypal' };
|
let latestState = { plusPaymentMethod: 'paypal' };
|
||||||
|
let currentPlusAccountAccessStrategy = 'oauth';
|
||||||
const inputPlusModeEnabled = { checked: true };
|
const inputPlusModeEnabled = { checked: true };
|
||||||
const rowPlusMode = { style: { display: '' } };
|
const rowPlusMode = { style: { display: '' } };
|
||||||
const selectPlusPaymentMethod = { value: 'paypal', style: { display: '' } };
|
const selectPlusPaymentMethod = { value: 'paypal', style: { display: '' } };
|
||||||
@@ -213,6 +227,9 @@ const rowPlusPaymentMethod = { style: { display: '' } };
|
|||||||
const rowPayPalAccount = { style: { display: '' } };
|
const rowPayPalAccount = { style: { display: '' } };
|
||||||
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
${bundle}
|
${bundle}
|
||||||
return {
|
return {
|
||||||
rowPlusMode,
|
rowPlusMode,
|
||||||
@@ -235,6 +252,7 @@ test('sidepanel step definitions keep GPC helper mode distinct', () => {
|
|||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizeSignupMethod'),
|
extractFunction('normalizeSignupMethod'),
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getStepDefinitionsForMode'),
|
extractFunction('getStepDefinitionsForMode'),
|
||||||
extractFunction('rebuildStepDefinitionState'),
|
extractFunction('rebuildStepDefinitionState'),
|
||||||
extractFunction('syncStepDefinitionsForMode'),
|
extractFunction('syncStepDefinitionsForMode'),
|
||||||
@@ -252,6 +270,10 @@ const window = {
|
|||||||
};
|
};
|
||||||
let currentPlusModeEnabled = false;
|
let currentPlusModeEnabled = false;
|
||||||
let currentPlusPaymentMethod = 'paypal';
|
let currentPlusPaymentMethod = 'paypal';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
|
let currentPlusAccountAccessStrategy = DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY;
|
||||||
let currentSignupMethod = 'email';
|
let currentSignupMethod = 'email';
|
||||||
let currentPhoneSignupReloginAfterBindEmailEnabled = false;
|
let currentPhoneSignupReloginAfterBindEmailEnabled = false;
|
||||||
const DEFAULT_SIGNUP_METHOD = 'email';
|
const DEFAULT_SIGNUP_METHOD = 'email';
|
||||||
@@ -277,14 +299,16 @@ return {
|
|||||||
assert.deepEqual(api.getStepIds(), [13]);
|
assert.deepEqual(api.getStepIds(), [13]);
|
||||||
assert.deepEqual(api.calls[0], {
|
assert.deepEqual(api.calls[0], {
|
||||||
type: 'getSteps',
|
type: 'getSteps',
|
||||||
options: { activeFlowId: 'openai', plusModeEnabled: true, plusPaymentMethod: 'gpc-helper', signupMethod: 'email', phoneSignupReloginAfterBindEmailEnabled: false },
|
options: { activeFlowId: 'openai', plusModeEnabled: true, plusPaymentMethod: 'gpc-helper', plusAccountAccessStrategy: 'oauth', signupMethod: 'email', phoneSignupReloginAfterBindEmailEnabled: false },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sidepanel Plus UI shows GPC fields and purchase button only for GPC', () => {
|
test('sidepanel Plus UI shows GPC fields and purchase button only for GPC', () => {
|
||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getSelectedPlusPaymentMethod'),
|
extractFunction('getSelectedPlusPaymentMethod'),
|
||||||
|
extractFunction('getRequestedPlusAccountAccessStrategy'),
|
||||||
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
||||||
extractFunction('getGpcHelperAutoModeEnabled'),
|
extractFunction('getGpcHelperAutoModeEnabled'),
|
||||||
extractFunction('normalizeGpcAutoModePermissionValue'),
|
extractFunction('normalizeGpcAutoModePermissionValue'),
|
||||||
@@ -299,10 +323,14 @@ test('sidepanel Plus UI shows GPC fields and purchase button only for GPC', () =
|
|||||||
const api = new Function(`
|
const api = new Function(`
|
||||||
let latestState = { plusPaymentMethod: 'gpc-helper', gopayHelperAutoModeEnabled: true };
|
let latestState = { plusPaymentMethod: 'gpc-helper', gopayHelperAutoModeEnabled: true };
|
||||||
let currentPlusPaymentMethod = 'paypal';
|
let currentPlusPaymentMethod = 'paypal';
|
||||||
|
let currentPlusAccountAccessStrategy = 'oauth';
|
||||||
const inputPlusModeEnabled = { checked: true };
|
const inputPlusModeEnabled = { checked: true };
|
||||||
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
||||||
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
const plusPaymentMethodCaption = { textContent: '' };
|
const plusPaymentMethodCaption = { textContent: '' };
|
||||||
const btnGpcCardKeyPurchase = { style: { display: 'none' } };
|
const btnGpcCardKeyPurchase = { style: { display: 'none' } };
|
||||||
const rowPayPalAccount = { style: { display: '' } };
|
const rowPayPalAccount = { style: { display: '' } };
|
||||||
@@ -380,7 +408,9 @@ return {
|
|||||||
test('sidepanel keeps selected GPC auto mode when API Key has no auto permission', () => {
|
test('sidepanel keeps selected GPC auto mode when API Key has no auto permission', () => {
|
||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getSelectedPlusPaymentMethod'),
|
extractFunction('getSelectedPlusPaymentMethod'),
|
||||||
|
extractFunction('getRequestedPlusAccountAccessStrategy'),
|
||||||
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
||||||
extractFunction('getGpcHelperAutoModeEnabled'),
|
extractFunction('getGpcHelperAutoModeEnabled'),
|
||||||
extractFunction('normalizeGpcAutoModePermissionValue'),
|
extractFunction('normalizeGpcAutoModePermissionValue'),
|
||||||
@@ -395,10 +425,14 @@ test('sidepanel keeps selected GPC auto mode when API Key has no auto permission
|
|||||||
const api = new Function(`
|
const api = new Function(`
|
||||||
let latestState = { plusPaymentMethod: 'gpc-helper', gopayHelperPhoneMode: 'auto', gopayHelperAutoModeEnabled: false, gopayHelperBalancePayload: { auto_mode_enabled: false } };
|
let latestState = { plusPaymentMethod: 'gpc-helper', gopayHelperPhoneMode: 'auto', gopayHelperAutoModeEnabled: false, gopayHelperBalancePayload: { auto_mode_enabled: false } };
|
||||||
let currentPlusPaymentMethod = 'gpc-helper';
|
let currentPlusPaymentMethod = 'gpc-helper';
|
||||||
|
let currentPlusAccountAccessStrategy = 'oauth';
|
||||||
const inputPlusModeEnabled = { checked: true };
|
const inputPlusModeEnabled = { checked: true };
|
||||||
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
||||||
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
const plusPaymentMethodCaption = { textContent: '' };
|
const plusPaymentMethodCaption = { textContent: '' };
|
||||||
const btnGpcCardKeyPurchase = { style: { display: 'none' } };
|
const btnGpcCardKeyPurchase = { style: { display: 'none' } };
|
||||||
const rowPayPalAccount = { style: { display: '' } };
|
const rowPayPalAccount = { style: { display: '' } };
|
||||||
@@ -432,7 +466,9 @@ return { updatePlusModeUI, selectGpcHelperPhoneMode, plusPaymentMethodCaption, r
|
|||||||
test('sidepanel keeps selected GPC auto mode when persisted permission survives stop refresh', () => {
|
test('sidepanel keeps selected GPC auto mode when persisted permission survives stop refresh', () => {
|
||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getSelectedPlusPaymentMethod'),
|
extractFunction('getSelectedPlusPaymentMethod'),
|
||||||
|
extractFunction('getRequestedPlusAccountAccessStrategy'),
|
||||||
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
||||||
extractFunction('getGpcHelperAutoModeEnabled'),
|
extractFunction('getGpcHelperAutoModeEnabled'),
|
||||||
extractFunction('normalizeGpcAutoModePermissionValue'),
|
extractFunction('normalizeGpcAutoModePermissionValue'),
|
||||||
@@ -452,10 +488,14 @@ let latestState = {
|
|||||||
gopayHelperBalancePayload: { auto_mode_enabled: true },
|
gopayHelperBalancePayload: { auto_mode_enabled: true },
|
||||||
};
|
};
|
||||||
let currentPlusPaymentMethod = 'gpc-helper';
|
let currentPlusPaymentMethod = 'gpc-helper';
|
||||||
|
let currentPlusAccountAccessStrategy = 'oauth';
|
||||||
const inputPlusModeEnabled = { checked: true };
|
const inputPlusModeEnabled = { checked: true };
|
||||||
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
||||||
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
const plusPaymentMethodCaption = { textContent: '' };
|
const plusPaymentMethodCaption = { textContent: '' };
|
||||||
const rowPayPalAccount = { style: { display: '' } };
|
const rowPayPalAccount = { style: { display: '' } };
|
||||||
const rowPlusPaymentMethod = { style: { display: 'none' } };
|
const rowPlusPaymentMethod = { style: { display: 'none' } };
|
||||||
@@ -513,7 +553,9 @@ return {
|
|||||||
test('sidepanel keeps selected GPC auto mode before permission has been queried', () => {
|
test('sidepanel keeps selected GPC auto mode before permission has been queried', () => {
|
||||||
const bundle = [
|
const bundle = [
|
||||||
extractFunction('normalizePlusPaymentMethod'),
|
extractFunction('normalizePlusPaymentMethod'),
|
||||||
|
extractFunction('normalizePlusAccountAccessStrategy'),
|
||||||
extractFunction('getSelectedPlusPaymentMethod'),
|
extractFunction('getSelectedPlusPaymentMethod'),
|
||||||
|
extractFunction('getRequestedPlusAccountAccessStrategy'),
|
||||||
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
extractFunction('normalizeGpcHelperPhoneModeValue'),
|
||||||
extractFunction('getGpcHelperAutoModeEnabled'),
|
extractFunction('getGpcHelperAutoModeEnabled'),
|
||||||
extractFunction('normalizeGpcAutoModePermissionValue'),
|
extractFunction('normalizeGpcAutoModePermissionValue'),
|
||||||
@@ -528,10 +570,14 @@ test('sidepanel keeps selected GPC auto mode before permission has been queried'
|
|||||||
const api = new Function(`
|
const api = new Function(`
|
||||||
let latestState = { plusPaymentMethod: 'gpc-helper', gopayHelperPhoneMode: 'auto', gopayHelperAutoModeEnabled: false, gopayHelperBalancePayload: null };
|
let latestState = { plusPaymentMethod: 'gpc-helper', gopayHelperPhoneMode: 'auto', gopayHelperAutoModeEnabled: false, gopayHelperBalancePayload: null };
|
||||||
let currentPlusPaymentMethod = 'gpc-helper';
|
let currentPlusPaymentMethod = 'gpc-helper';
|
||||||
|
let currentPlusAccountAccessStrategy = 'oauth';
|
||||||
const inputPlusModeEnabled = { checked: true };
|
const inputPlusModeEnabled = { checked: true };
|
||||||
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
const selectPlusPaymentMethod = { value: 'gpc-helper', style: { display: 'none' } };
|
||||||
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
const GPC_HELPER_PHONE_MODE_AUTO = 'auto';
|
||||||
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
const GPC_HELPER_PHONE_MODE_MANUAL = 'manual';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH = 'oauth';
|
||||||
|
const PLUS_ACCOUNT_ACCESS_STRATEGY_SUB2API_CODEX_SESSION = 'sub2api_codex_session';
|
||||||
|
const DEFAULT_PLUS_ACCOUNT_ACCESS_STRATEGY = PLUS_ACCOUNT_ACCESS_STRATEGY_OAUTH;
|
||||||
const plusPaymentMethodCaption = { textContent: '' };
|
const plusPaymentMethodCaption = { textContent: '' };
|
||||||
const rowPayPalAccount = { style: { display: '' } };
|
const rowPayPalAccount = { style: { display: '' } };
|
||||||
const rowPlusPaymentMethod = { style: { display: 'none' } };
|
const rowPlusPaymentMethod = { style: { display: 'none' } };
|
||||||
|
|||||||
@@ -254,6 +254,87 @@ test('step definitions module exposes ordered normal and Plus step metadata', ()
|
|||||||
assert.equal(gpcSteps[6].title, '等待 GPC 任务完成');
|
assert.equal(gpcSteps[6].title, '等待 GPC 任务完成');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Plus session strategy swaps the OAuth tail for a single SUB2API import node', () => {
|
||||||
|
const source = fs.readFileSync('data/step-definitions.js', 'utf8');
|
||||||
|
const globalScope = {};
|
||||||
|
const api = new Function('self', `${source}; return self.MultiPageStepDefinitions;`)(globalScope);
|
||||||
|
const forbiddenTailKeys = [
|
||||||
|
'oauth-login',
|
||||||
|
'fetch-login-code',
|
||||||
|
'post-login-phone-verification',
|
||||||
|
'confirm-oauth',
|
||||||
|
'platform-verify',
|
||||||
|
];
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
label: 'paypal',
|
||||||
|
options: {
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
},
|
||||||
|
previousNodeId: 'plus-checkout-return',
|
||||||
|
expectedStepIds: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'gopay',
|
||||||
|
options: {
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'gopay',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
},
|
||||||
|
previousNodeId: 'gopay-subscription-confirm',
|
||||||
|
expectedStepIds: [1, 2, 3, 4, 5, 6, 7, 10],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'gpc-helper',
|
||||||
|
options: {
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'gpc-helper',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
},
|
||||||
|
previousNodeId: 'plus-checkout-billing',
|
||||||
|
expectedStepIds: [1, 2, 3, 4, 5, 6, 7, 10],
|
||||||
|
},
|
||||||
|
].forEach(({ label, options, previousNodeId, expectedStepIds }) => {
|
||||||
|
const steps = api.getSteps(options);
|
||||||
|
const nodes = api.getNodes(options);
|
||||||
|
const stepKeys = steps.map((step) => step.key);
|
||||||
|
const nodeIds = nodes.map((node) => node.nodeId);
|
||||||
|
const previousNode = nodes.find((node) => node.nodeId === previousNodeId);
|
||||||
|
const sessionImportNode = nodes.find((node) => node.nodeId === 'sub2api-session-import');
|
||||||
|
|
||||||
|
assert.equal(stepKeys.at(-1), 'sub2api-session-import', `${label} should end with session import`);
|
||||||
|
assert.equal(nodeIds.at(-1), 'sub2api-session-import', `${label} node order should end with session import`);
|
||||||
|
forbiddenTailKeys.forEach((key) => {
|
||||||
|
assert.equal(stepKeys.includes(key), false, `${label} should not keep ${key} in session mode`);
|
||||||
|
assert.equal(nodeIds.includes(key), false, `${label} nodes should not keep ${key} in session mode`);
|
||||||
|
});
|
||||||
|
assert.deepStrictEqual(api.getStepIds(options), expectedStepIds, `${label} step ids should follow the new tail`);
|
||||||
|
assert.equal(api.getLastStepId(options), expectedStepIds.at(-1), `${label} last step id should match session import`);
|
||||||
|
assert.deepStrictEqual(previousNode?.next, ['sub2api-session-import'], `${label} previous node should link to session import`);
|
||||||
|
assert.deepStrictEqual(sessionImportNode?.next, [], `${label} session import should be terminal`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Plus phone signup never switches to SUB2API session tail even if the requested strategy is session import', () => {
|
||||||
|
const source = fs.readFileSync('data/step-definitions.js', 'utf8');
|
||||||
|
const globalScope = {};
|
||||||
|
const api = new Function('self', `${source}; return self.MultiPageStepDefinitions;`)(globalScope);
|
||||||
|
const steps = api.getSteps({
|
||||||
|
plusModeEnabled: true,
|
||||||
|
plusPaymentMethod: 'paypal',
|
||||||
|
signupMethod: 'phone',
|
||||||
|
plusAccountAccessStrategy: 'sub2api_codex_session',
|
||||||
|
});
|
||||||
|
const stepKeys = steps.map((step) => step.key);
|
||||||
|
|
||||||
|
assert.equal(stepKeys.includes('sub2api-session-import'), false);
|
||||||
|
assert.equal(stepKeys.includes('oauth-login'), true);
|
||||||
|
assert.equal(stepKeys.includes('platform-verify'), true);
|
||||||
|
});
|
||||||
|
|
||||||
test('sidepanel html loads shared step definitions before sidepanel bootstrap', () => {
|
test('sidepanel html loads shared step definitions before sidepanel bootstrap', () => {
|
||||||
const html = fs.readFileSync('sidepanel/sidepanel.html', 'utf8');
|
const html = fs.readFileSync('sidepanel/sidepanel.html', 'utf8');
|
||||||
const definitionsIndex = html.indexOf('<script src="../data/step-definitions.js"></script>');
|
const definitionsIndex = html.indexOf('<script src="../data/step-definitions.js"></script>');
|
||||||
|
|||||||
Reference in New Issue
Block a user