重构多 flow 邮件轮询并接入 Grok SSO
This commit is contained in:
+441
-335
@@ -17,6 +17,23 @@
|
||||
return value;
|
||||
}
|
||||
|
||||
function mergePlainObjects(baseValue = {}, patchValue = {}) {
|
||||
if (Array.isArray(patchValue)) {
|
||||
return patchValue.map((entry) => cloneValue(entry));
|
||||
}
|
||||
if (!isPlainObject(patchValue)) {
|
||||
return patchValue === undefined ? cloneValue(baseValue) : patchValue;
|
||||
}
|
||||
const baseObject = isPlainObject(baseValue) ? baseValue : {};
|
||||
const next = {
|
||||
...cloneValue(baseObject),
|
||||
};
|
||||
Object.entries(patchValue).forEach(([key, value]) => {
|
||||
next[key] = mergePlainObjects(baseObject[key], value);
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
function normalizeStepExecutionRangeEntry(value = {}, fallback = {}) {
|
||||
const source = isPlainObject(value) ? value : {};
|
||||
const fallbackSource = isPlainObject(fallback) ? fallback : {};
|
||||
@@ -47,6 +64,19 @@
|
||||
const normalizeTargetId = typeof flowRegistry.normalizeTargetId === 'function'
|
||||
? flowRegistry.normalizeTargetId
|
||||
: ((_flowId, value = '', fallback = '') => String(value || fallback || '').trim().toLowerCase());
|
||||
const getRegisteredFlowIds = typeof flowRegistry.getRegisteredFlowIds === 'function'
|
||||
? flowRegistry.getRegisteredFlowIds
|
||||
: (() => ['openai', 'kiro']);
|
||||
const getFlowDefinition = typeof flowRegistry.getFlowDefinition === 'function'
|
||||
? flowRegistry.getFlowDefinition
|
||||
: (() => null);
|
||||
const getDefaultTargetId = typeof flowRegistry.getDefaultTargetId === 'function'
|
||||
? flowRegistry.getDefaultTargetId
|
||||
: ((flowId) => (flowId === 'kiro' ? defaultKiroTargetId : defaultOpenAiTargetId));
|
||||
const getTargetDefinitions = typeof flowRegistry.getTargetDefinitions === 'function'
|
||||
? flowRegistry.getTargetDefinitions
|
||||
: (() => ({}));
|
||||
|
||||
const normalizePlusAccountAccessStrategy = (value = '') => {
|
||||
const normalized = String(value || '').trim().toLowerCase();
|
||||
if (normalized === 'sub2api_codex_session') {
|
||||
@@ -58,6 +88,146 @@
|
||||
return 'oauth';
|
||||
};
|
||||
|
||||
function getCanonicalFlowIds() {
|
||||
const ids = Array.isArray(getRegisteredFlowIds())
|
||||
? getRegisteredFlowIds()
|
||||
: [];
|
||||
const seen = new Set();
|
||||
return ids
|
||||
.map((flowId) => normalizeFlowId(flowId, defaultFlowId))
|
||||
.filter((flowId) => {
|
||||
if (!flowId || seen.has(flowId)) {
|
||||
return false;
|
||||
}
|
||||
seen.add(flowId);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function getFlowSettingsDefaults(flowId) {
|
||||
const definition = getFlowDefinition(flowId) || {};
|
||||
return isPlainObject(definition.settingsDefaults) ? definition.settingsDefaults : {};
|
||||
}
|
||||
|
||||
function getDefaultStepExecutionRange(flowId) {
|
||||
const flowDefaults = getFlowSettingsDefaults(flowId);
|
||||
const range = flowDefaults?.autoRun?.stepExecutionRange;
|
||||
if (isPlainObject(range)) {
|
||||
return normalizeStepExecutionRangeEntry(range, { enabled: false, fromStep: 1, toStep: 1 });
|
||||
}
|
||||
if (flowId === 'openai') {
|
||||
return { enabled: false, fromStep: 1, toStep: 11 };
|
||||
}
|
||||
if (flowId === 'kiro') {
|
||||
return { enabled: false, fromStep: 1, toStep: 9 };
|
||||
}
|
||||
const lastStep = Math.max(1, Number(getFlowDefinition(flowId)?.workflowStepCount) || 1);
|
||||
return { enabled: false, fromStep: 1, toStep: lastStep };
|
||||
}
|
||||
|
||||
function buildDefaultTargetState(flowId, targetId) {
|
||||
if (flowId === 'openai' && targetId === 'cpa') {
|
||||
return {
|
||||
vpsUrl: '',
|
||||
vpsPassword: '',
|
||||
localCpaStep9Mode: 'submit',
|
||||
};
|
||||
}
|
||||
if (flowId === 'openai' && targetId === 'sub2api') {
|
||||
return {
|
||||
sub2apiUrl: '',
|
||||
sub2apiEmail: '',
|
||||
sub2apiPassword: '',
|
||||
sub2apiGroupName: 'codex',
|
||||
sub2apiGroupNames: ['codex', 'openai-plus'],
|
||||
sub2apiAccountPriority: 1,
|
||||
sub2apiDefaultProxyName: '',
|
||||
};
|
||||
}
|
||||
if (flowId === 'openai' && targetId === 'codex2api') {
|
||||
return {
|
||||
codex2apiUrl: '',
|
||||
codex2apiAdminKey: '',
|
||||
};
|
||||
}
|
||||
if (flowId === 'kiro' && targetId === 'kiro-rs') {
|
||||
return {
|
||||
baseUrl: defaultKiroRsUrl,
|
||||
apiKey: '',
|
||||
};
|
||||
}
|
||||
|
||||
const definition = getFlowDefinition(flowId) || {};
|
||||
const flowDefaults = getFlowSettingsDefaults(flowId);
|
||||
const targetDefaults = isPlainObject(flowDefaults?.targets?.[targetId])
|
||||
? flowDefaults.targets[targetId]
|
||||
: {};
|
||||
const sharedTargetDefaults = isPlainObject(definition.defaultTargetState)
|
||||
? definition.defaultTargetState
|
||||
: {};
|
||||
const targetDefinition = isPlainObject(getTargetDefinitions(flowId)?.[targetId])
|
||||
? getTargetDefinitions(flowId)[targetId]
|
||||
: {};
|
||||
const targetDefinitionDefaults = isPlainObject(targetDefinition.defaultState)
|
||||
? targetDefinition.defaultState
|
||||
: {};
|
||||
return mergePlainObjects(
|
||||
mergePlainObjects(sharedTargetDefaults, targetDefinitionDefaults),
|
||||
targetDefaults
|
||||
);
|
||||
}
|
||||
|
||||
function buildDefaultTargets(flowId) {
|
||||
const targetDefinitions = getTargetDefinitions(flowId) || {};
|
||||
const targetIds = Object.keys(targetDefinitions);
|
||||
const defaults = {};
|
||||
targetIds.forEach((targetId) => {
|
||||
defaults[targetId] = buildDefaultTargetState(flowId, targetId);
|
||||
});
|
||||
return defaults;
|
||||
}
|
||||
|
||||
function buildDefaultFlowSettings(flowId) {
|
||||
const defaultTargetId = normalizeTargetId(
|
||||
flowId,
|
||||
getDefaultTargetId(flowId),
|
||||
flowId === 'kiro' ? defaultKiroTargetId : defaultOpenAiTargetId
|
||||
);
|
||||
const base = {
|
||||
selectedTargetId: defaultTargetId,
|
||||
targets: buildDefaultTargets(flowId),
|
||||
autoRun: {
|
||||
stepExecutionRange: getDefaultStepExecutionRange(flowId),
|
||||
},
|
||||
};
|
||||
if (flowId === 'openai') {
|
||||
return mergePlainObjects(base, {
|
||||
signup: {
|
||||
signupMethod: 'email',
|
||||
phoneVerificationEnabled: false,
|
||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||
},
|
||||
plus: {
|
||||
plusModeEnabled: false,
|
||||
plusPaymentMethod: 'paypal-hosted',
|
||||
plusAccountAccessStrategy: 'oauth',
|
||||
hostedCheckoutVerificationUrl: '',
|
||||
hostedCheckoutPhoneNumber: '',
|
||||
plusHostedCheckoutOauthDelaySeconds: 3,
|
||||
},
|
||||
});
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
function buildDefaultFlows() {
|
||||
const flows = {};
|
||||
getCanonicalFlowIds().forEach((flowId) => {
|
||||
flows[flowId] = buildDefaultFlowSettings(flowId);
|
||||
});
|
||||
return flows;
|
||||
}
|
||||
|
||||
function buildDefaultSettingsState() {
|
||||
return {
|
||||
schemaVersion: 5,
|
||||
@@ -75,67 +245,7 @@
|
||||
mode: 'account',
|
||||
},
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
selectedTargetId: defaultOpenAiTargetId,
|
||||
targets: {
|
||||
cpa: {
|
||||
vpsUrl: '',
|
||||
vpsPassword: '',
|
||||
localCpaStep9Mode: 'submit',
|
||||
},
|
||||
sub2api: {
|
||||
sub2apiUrl: '',
|
||||
sub2apiEmail: '',
|
||||
sub2apiPassword: '',
|
||||
sub2apiGroupName: 'codex',
|
||||
sub2apiGroupNames: ['codex', 'openai-plus'],
|
||||
sub2apiAccountPriority: 1,
|
||||
sub2apiDefaultProxyName: '',
|
||||
},
|
||||
codex2api: {
|
||||
codex2apiUrl: '',
|
||||
codex2apiAdminKey: '',
|
||||
},
|
||||
},
|
||||
signup: {
|
||||
signupMethod: 'email',
|
||||
phoneVerificationEnabled: false,
|
||||
phoneSignupReloginAfterBindEmailEnabled: false,
|
||||
},
|
||||
plus: {
|
||||
plusModeEnabled: false,
|
||||
plusPaymentMethod: 'paypal-hosted',
|
||||
plusAccountAccessStrategy: 'oauth',
|
||||
hostedCheckoutVerificationUrl: '',
|
||||
hostedCheckoutPhoneNumber: '',
|
||||
plusHostedCheckoutOauthDelaySeconds: 3,
|
||||
},
|
||||
autoRun: {
|
||||
stepExecutionRange: {
|
||||
enabled: false,
|
||||
fromStep: 1,
|
||||
toStep: 11,
|
||||
},
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
selectedTargetId: defaultKiroTargetId,
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
baseUrl: defaultKiroRsUrl,
|
||||
apiKey: '',
|
||||
},
|
||||
},
|
||||
autoRun: {
|
||||
stepExecutionRange: {
|
||||
enabled: false,
|
||||
fromStep: 1,
|
||||
toStep: 9,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
flows: buildDefaultFlows(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -147,6 +257,223 @@
|
||||
return cloneValue(resolvedValue);
|
||||
}
|
||||
|
||||
function normalizeFlowTargetState(flowId, targetId, nested = {}, defaults = {}) {
|
||||
const targetState = mergePlainObjects(defaults, nested);
|
||||
if (flowId === 'openai' && targetId === 'cpa') {
|
||||
return {
|
||||
...targetState,
|
||||
vpsUrl: String(targetState.vpsUrl ?? '').trim(),
|
||||
vpsPassword: String(targetState.vpsPassword ?? ''),
|
||||
localCpaStep9Mode: String(targetState.localCpaStep9Mode ?? 'submit').trim() || 'submit',
|
||||
};
|
||||
}
|
||||
if (flowId === 'openai' && targetId === 'sub2api') {
|
||||
return {
|
||||
...targetState,
|
||||
sub2apiUrl: String(targetState.sub2apiUrl ?? '').trim(),
|
||||
sub2apiEmail: String(targetState.sub2apiEmail ?? '').trim(),
|
||||
sub2apiPassword: String(targetState.sub2apiPassword ?? ''),
|
||||
sub2apiGroupName: String(targetState.sub2apiGroupName ?? 'codex').trim() || 'codex',
|
||||
sub2apiGroupNames: Array.isArray(targetState.sub2apiGroupNames)
|
||||
? targetState.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: ['codex', 'openai-plus'],
|
||||
sub2apiAccountPriority: Math.max(1, Number(targetState.sub2apiAccountPriority) || 1),
|
||||
sub2apiDefaultProxyName: String(targetState.sub2apiDefaultProxyName ?? '').trim(),
|
||||
};
|
||||
}
|
||||
if (flowId === 'openai' && targetId === 'codex2api') {
|
||||
return {
|
||||
...targetState,
|
||||
codex2apiUrl: String(targetState.codex2apiUrl ?? '').trim(),
|
||||
codex2apiAdminKey: String(targetState.codex2apiAdminKey ?? '').trim(),
|
||||
};
|
||||
}
|
||||
if (flowId === 'kiro' && targetId === 'kiro-rs') {
|
||||
return {
|
||||
...targetState,
|
||||
baseUrl: String(targetState.baseUrl ?? defaultKiroRsUrl).trim() || defaultKiroRsUrl,
|
||||
apiKey: String(targetState.apiKey ?? ''),
|
||||
};
|
||||
}
|
||||
return targetState;
|
||||
}
|
||||
|
||||
function buildNormalizedTargets(flowId, nestedFlow = {}, defaultFlow = {}) {
|
||||
const targetIds = Array.from(new Set([
|
||||
...Object.keys(defaultFlow.targets || {}),
|
||||
...Object.keys(isPlainObject(nestedFlow.targets) ? nestedFlow.targets : {}),
|
||||
...Object.keys(getTargetDefinitions(flowId) || {}),
|
||||
]));
|
||||
const targets = {};
|
||||
targetIds.forEach((targetId) => {
|
||||
targets[targetId] = normalizeFlowTargetState(
|
||||
flowId,
|
||||
targetId,
|
||||
isPlainObject(nestedFlow.targets?.[targetId]) ? nestedFlow.targets[targetId] : {},
|
||||
defaultFlow.targets?.[targetId] || buildDefaultTargetState(flowId, targetId)
|
||||
);
|
||||
});
|
||||
return targets;
|
||||
}
|
||||
|
||||
function normalizeFlowSettings(flowId, input = {}, nested = {}, defaults = {}) {
|
||||
const nestedFlow = isPlainObject(nested?.flows?.[flowId]) ? nested.flows[flowId] : {};
|
||||
const activeFlowId = normalizeFlowId(
|
||||
input?.activeFlowId
|
||||
?? nested?.activeFlowId
|
||||
?? defaults.activeFlowId,
|
||||
defaults.activeFlowId
|
||||
);
|
||||
const mergedFlow = mergePlainObjects(defaults.flows?.[flowId] || buildDefaultFlowSettings(flowId), nestedFlow);
|
||||
const defaultTargetId = defaults.flows?.[flowId]?.selectedTargetId || getDefaultTargetId(flowId);
|
||||
const selectedTargetId = normalizeTargetId(
|
||||
flowId,
|
||||
nestedFlow?.selectedTargetId
|
||||
?? nestedFlow?.targetId
|
||||
?? (flowId === 'openai' ? nestedFlow?.integrationTargetId : undefined)
|
||||
?? (activeFlowId === flowId ? (input?.selectedTargetId ?? input?.targetId) : undefined)
|
||||
?? defaultTargetId,
|
||||
defaultTargetId
|
||||
);
|
||||
const stepExecutionRangeByFlow = isPlainObject(input?.stepExecutionRangeByFlow)
|
||||
? input.stepExecutionRangeByFlow
|
||||
: {};
|
||||
const autoRun = {
|
||||
...(isPlainObject(mergedFlow.autoRun) ? mergedFlow.autoRun : {}),
|
||||
stepExecutionRange: normalizeStepExecutionRangeEntry(
|
||||
stepExecutionRangeByFlow[flowId]
|
||||
?? nestedFlow?.autoRun?.stepExecutionRange
|
||||
?? {},
|
||||
defaults.flows?.[flowId]?.autoRun?.stepExecutionRange || getDefaultStepExecutionRange(flowId)
|
||||
),
|
||||
};
|
||||
|
||||
return {
|
||||
...mergedFlow,
|
||||
selectedTargetId,
|
||||
targets: buildNormalizedTargets(flowId, nestedFlow, defaults.flows?.[flowId] || {}),
|
||||
autoRun,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeOpenAiSettings(input = {}, nested = {}, defaults = {}, currentFlow = {}) {
|
||||
const cpaSource = {
|
||||
...currentFlow.targets.cpa,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.integrationTargets?.cpa,
|
||||
null,
|
||||
{}
|
||||
),
|
||||
vpsUrl: input?.vpsUrl ?? currentFlow.targets.cpa.vpsUrl,
|
||||
vpsPassword: input?.vpsPassword ?? currentFlow.targets.cpa.vpsPassword,
|
||||
localCpaStep9Mode: input?.localCpaStep9Mode ?? currentFlow.targets.cpa.localCpaStep9Mode,
|
||||
};
|
||||
const sub2apiSource = {
|
||||
...currentFlow.targets.sub2api,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.integrationTargets?.sub2api,
|
||||
null,
|
||||
{}
|
||||
),
|
||||
sub2apiUrl: input?.sub2apiUrl ?? currentFlow.targets.sub2api.sub2apiUrl,
|
||||
sub2apiEmail: input?.sub2apiEmail ?? currentFlow.targets.sub2api.sub2apiEmail,
|
||||
sub2apiPassword: input?.sub2apiPassword ?? currentFlow.targets.sub2api.sub2apiPassword,
|
||||
sub2apiGroupName: input?.sub2apiGroupName ?? currentFlow.targets.sub2api.sub2apiGroupName,
|
||||
sub2apiGroupNames: input?.sub2apiGroupNames ?? currentFlow.targets.sub2api.sub2apiGroupNames,
|
||||
sub2apiAccountPriority: input?.sub2apiAccountPriority ?? currentFlow.targets.sub2api.sub2apiAccountPriority,
|
||||
sub2apiDefaultProxyName: input?.sub2apiDefaultProxyName ?? currentFlow.targets.sub2api.sub2apiDefaultProxyName,
|
||||
};
|
||||
const codex2apiSource = {
|
||||
...currentFlow.targets.codex2api,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.integrationTargets?.codex2api,
|
||||
null,
|
||||
{}
|
||||
),
|
||||
codex2apiUrl: input?.codex2apiUrl ?? currentFlow.targets.codex2api.codex2apiUrl,
|
||||
codex2apiAdminKey: input?.codex2apiAdminKey ?? currentFlow.targets.codex2api.codex2apiAdminKey,
|
||||
};
|
||||
return {
|
||||
...currentFlow,
|
||||
targets: {
|
||||
...currentFlow.targets,
|
||||
cpa: normalizeFlowTargetState('openai', 'cpa', cpaSource, defaults.flows.openai.targets.cpa),
|
||||
sub2api: normalizeFlowTargetState('openai', 'sub2api', sub2apiSource, defaults.flows.openai.targets.sub2api),
|
||||
codex2api: normalizeFlowTargetState('openai', 'codex2api', codex2apiSource, defaults.flows.openai.targets.codex2api),
|
||||
},
|
||||
signup: {
|
||||
signupMethod: String(
|
||||
input?.signupMethod
|
||||
?? currentFlow.signup?.signupMethod
|
||||
?? defaults.flows.openai.signup.signupMethod
|
||||
).trim().toLowerCase() === 'phone' ? 'phone' : 'email',
|
||||
phoneVerificationEnabled: Boolean(
|
||||
input?.phoneVerificationEnabled
|
||||
?? currentFlow.signup?.phoneVerificationEnabled
|
||||
?? defaults.flows.openai.signup.phoneVerificationEnabled
|
||||
),
|
||||
phoneSignupReloginAfterBindEmailEnabled: Boolean(
|
||||
input?.phoneSignupReloginAfterBindEmailEnabled
|
||||
?? currentFlow.signup?.phoneSignupReloginAfterBindEmailEnabled
|
||||
?? defaults.flows.openai.signup.phoneSignupReloginAfterBindEmailEnabled
|
||||
),
|
||||
},
|
||||
plus: {
|
||||
plusModeEnabled: Boolean(
|
||||
input?.plusModeEnabled
|
||||
?? currentFlow.plus?.plusModeEnabled
|
||||
?? defaults.flows.openai.plus.plusModeEnabled
|
||||
),
|
||||
plusPaymentMethod: String(
|
||||
input?.plusPaymentMethod
|
||||
?? currentFlow.plus?.plusPaymentMethod
|
||||
?? defaults.flows.openai.plus.plusPaymentMethod
|
||||
).trim() || defaults.flows.openai.plus.plusPaymentMethod,
|
||||
plusAccountAccessStrategy: normalizePlusAccountAccessStrategy(
|
||||
input?.plusAccountAccessStrategy
|
||||
?? currentFlow.plus?.plusAccountAccessStrategy
|
||||
?? defaults.flows.openai.plus.plusAccountAccessStrategy
|
||||
),
|
||||
hostedCheckoutVerificationUrl: String(
|
||||
input?.hostedCheckoutVerificationUrl
|
||||
?? currentFlow.plus?.hostedCheckoutVerificationUrl
|
||||
?? defaults.flows.openai.plus.hostedCheckoutVerificationUrl
|
||||
).trim(),
|
||||
hostedCheckoutPhoneNumber: String(
|
||||
input?.hostedCheckoutPhoneNumber
|
||||
?? currentFlow.plus?.hostedCheckoutPhoneNumber
|
||||
?? defaults.flows.openai.plus.hostedCheckoutPhoneNumber
|
||||
).trim(),
|
||||
plusHostedCheckoutOauthDelaySeconds: (() => {
|
||||
const numeric = Number(
|
||||
input?.plusHostedCheckoutOauthDelaySeconds
|
||||
?? currentFlow.plus?.plusHostedCheckoutOauthDelaySeconds
|
||||
?? defaults.flows.openai.plus.plusHostedCheckoutOauthDelaySeconds
|
||||
);
|
||||
return Math.min(120, Math.max(0, Math.floor(Number.isFinite(numeric) ? numeric : defaults.flows.openai.plus.plusHostedCheckoutOauthDelaySeconds)));
|
||||
})(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeKiroSettings(input = {}, defaults = {}, currentFlow = {}) {
|
||||
const targetSource = {
|
||||
...currentFlow.targets['kiro-rs'],
|
||||
baseUrl: input?.kiroRsUrl ?? input?.kiroRsBaseUrl ?? currentFlow.targets['kiro-rs'].baseUrl,
|
||||
apiKey: input?.kiroRsKey ?? input?.kiroRsApiKey ?? currentFlow.targets['kiro-rs'].apiKey,
|
||||
};
|
||||
return {
|
||||
...currentFlow,
|
||||
targets: {
|
||||
...currentFlow.targets,
|
||||
'kiro-rs': normalizeFlowTargetState('kiro', 'kiro-rs', targetSource, defaults.flows.kiro.targets['kiro-rs']),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSettingsState(input = {}, options = {}) {
|
||||
const defaults = buildDefaultSettingsState();
|
||||
const nested = isPlainObject(input?.settingsState)
|
||||
@@ -159,31 +486,7 @@
|
||||
?? defaults.activeFlowId,
|
||||
defaults.activeFlowId
|
||||
);
|
||||
const openaiSelectedTargetId = normalizeTargetId(
|
||||
'openai',
|
||||
nested?.flows?.openai?.selectedTargetId
|
||||
?? nested?.flows?.openai?.integrationTargetId
|
||||
?? (activeFlowId === 'openai'
|
||||
? (input?.selectedTargetId ?? input?.targetId)
|
||||
: undefined)
|
||||
?? defaults.flows.openai.selectedTargetId,
|
||||
defaults.flows.openai.selectedTargetId
|
||||
);
|
||||
const kiroSelectedTargetId = normalizeTargetId(
|
||||
'kiro',
|
||||
nested?.flows?.kiro?.selectedTargetId
|
||||
?? nested?.flows?.kiro?.targetId
|
||||
?? (activeFlowId === 'kiro'
|
||||
? (input?.selectedTargetId ?? input?.targetId)
|
||||
: undefined)
|
||||
?? defaults.flows.kiro.selectedTargetId,
|
||||
defaults.flows.kiro.selectedTargetId
|
||||
);
|
||||
const stepExecutionRangeByFlow = isPlainObject(input?.stepExecutionRangeByFlow)
|
||||
? input.stepExecutionRangeByFlow
|
||||
: {};
|
||||
|
||||
return {
|
||||
const normalized = {
|
||||
schemaVersion: Number(input?.settingsSchemaVersion || nested?.schemaVersion || defaults.schemaVersion) || defaults.schemaVersion,
|
||||
activeFlowId,
|
||||
services: {
|
||||
@@ -219,203 +522,22 @@
|
||||
).trim(),
|
||||
},
|
||||
},
|
||||
flows: {
|
||||
openai: {
|
||||
selectedTargetId: openaiSelectedTargetId,
|
||||
targets: {
|
||||
cpa: {
|
||||
...defaults.flows.openai.targets.cpa,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.targets?.cpa,
|
||||
(state) => state.flows?.openai?.integrationTargets?.cpa
|
||||
),
|
||||
vpsUrl: String(
|
||||
input?.vpsUrl
|
||||
?? nested?.flows?.openai?.targets?.cpa?.vpsUrl
|
||||
?? nested?.flows?.openai?.integrationTargets?.cpa?.vpsUrl
|
||||
?? ''
|
||||
).trim(),
|
||||
vpsPassword: String(
|
||||
input?.vpsPassword
|
||||
?? nested?.flows?.openai?.targets?.cpa?.vpsPassword
|
||||
?? nested?.flows?.openai?.integrationTargets?.cpa?.vpsPassword
|
||||
?? ''
|
||||
),
|
||||
localCpaStep9Mode: String(
|
||||
input?.localCpaStep9Mode
|
||||
?? nested?.flows?.openai?.targets?.cpa?.localCpaStep9Mode
|
||||
?? nested?.flows?.openai?.integrationTargets?.cpa?.localCpaStep9Mode
|
||||
?? defaults.flows.openai.targets.cpa.localCpaStep9Mode
|
||||
).trim() || defaults.flows.openai.targets.cpa.localCpaStep9Mode,
|
||||
},
|
||||
sub2api: {
|
||||
...defaults.flows.openai.targets.sub2api,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.targets?.sub2api,
|
||||
(state) => state.flows?.openai?.integrationTargets?.sub2api
|
||||
),
|
||||
sub2apiUrl: String(
|
||||
input?.sub2apiUrl
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiUrl
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiUrl
|
||||
?? ''
|
||||
).trim(),
|
||||
sub2apiEmail: String(
|
||||
input?.sub2apiEmail
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiEmail
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiEmail
|
||||
?? ''
|
||||
).trim(),
|
||||
sub2apiPassword: String(
|
||||
input?.sub2apiPassword
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiPassword
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiPassword
|
||||
?? ''
|
||||
),
|
||||
sub2apiGroupName: String(
|
||||
input?.sub2apiGroupName
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiGroupName
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiGroupName
|
||||
?? defaults.flows.openai.targets.sub2api.sub2apiGroupName
|
||||
).trim() || defaults.flows.openai.targets.sub2api.sub2apiGroupName,
|
||||
sub2apiGroupNames: Array.isArray(input?.sub2apiGroupNames)
|
||||
? input.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: (Array.isArray(nested?.flows?.openai?.targets?.sub2api?.sub2apiGroupNames)
|
||||
? nested.flows.openai.targets.sub2api.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: (Array.isArray(nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiGroupNames)
|
||||
? nested.flows.openai.integrationTargets.sub2api.sub2apiGroupNames.map((entry) => String(entry || '').trim()).filter(Boolean)
|
||||
: [...defaults.flows.openai.targets.sub2api.sub2apiGroupNames])),
|
||||
sub2apiAccountPriority: Math.max(1, Number(
|
||||
input?.sub2apiAccountPriority
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiAccountPriority
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiAccountPriority
|
||||
?? defaults.flows.openai.targets.sub2api.sub2apiAccountPriority
|
||||
) || defaults.flows.openai.targets.sub2api.sub2apiAccountPriority),
|
||||
sub2apiDefaultProxyName: String(
|
||||
input?.sub2apiDefaultProxyName
|
||||
?? nested?.flows?.openai?.targets?.sub2api?.sub2apiDefaultProxyName
|
||||
?? nested?.flows?.openai?.integrationTargets?.sub2api?.sub2apiDefaultProxyName
|
||||
?? ''
|
||||
).trim(),
|
||||
},
|
||||
codex2api: {
|
||||
...defaults.flows.openai.targets.codex2api,
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.openai?.targets?.codex2api,
|
||||
(state) => state.flows?.openai?.integrationTargets?.codex2api
|
||||
),
|
||||
codex2apiUrl: String(
|
||||
input?.codex2apiUrl
|
||||
?? nested?.flows?.openai?.targets?.codex2api?.codex2apiUrl
|
||||
?? nested?.flows?.openai?.integrationTargets?.codex2api?.codex2apiUrl
|
||||
?? ''
|
||||
).trim(),
|
||||
codex2apiAdminKey: String(
|
||||
input?.codex2apiAdminKey
|
||||
?? nested?.flows?.openai?.targets?.codex2api?.codex2apiAdminKey
|
||||
?? nested?.flows?.openai?.integrationTargets?.codex2api?.codex2apiAdminKey
|
||||
?? ''
|
||||
).trim(),
|
||||
},
|
||||
},
|
||||
signup: {
|
||||
signupMethod: String(
|
||||
input?.signupMethod
|
||||
?? nested?.flows?.openai?.signup?.signupMethod
|
||||
?? defaults.flows.openai.signup.signupMethod
|
||||
).trim().toLowerCase() === 'phone' ? 'phone' : 'email',
|
||||
phoneVerificationEnabled: Boolean(
|
||||
input?.phoneVerificationEnabled
|
||||
?? nested?.flows?.openai?.signup?.phoneVerificationEnabled
|
||||
?? defaults.flows.openai.signup.phoneVerificationEnabled
|
||||
),
|
||||
phoneSignupReloginAfterBindEmailEnabled: Boolean(
|
||||
input?.phoneSignupReloginAfterBindEmailEnabled
|
||||
?? nested?.flows?.openai?.signup?.phoneSignupReloginAfterBindEmailEnabled
|
||||
?? defaults.flows.openai.signup.phoneSignupReloginAfterBindEmailEnabled
|
||||
),
|
||||
},
|
||||
plus: {
|
||||
plusModeEnabled: Boolean(
|
||||
input?.plusModeEnabled
|
||||
?? nested?.flows?.openai?.plus?.plusModeEnabled
|
||||
?? defaults.flows.openai.plus.plusModeEnabled
|
||||
),
|
||||
plusPaymentMethod: String(
|
||||
input?.plusPaymentMethod
|
||||
?? nested?.flows?.openai?.plus?.plusPaymentMethod
|
||||
?? 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
|
||||
),
|
||||
hostedCheckoutVerificationUrl: String(
|
||||
input?.hostedCheckoutVerificationUrl
|
||||
?? nested?.flows?.openai?.plus?.hostedCheckoutVerificationUrl
|
||||
?? defaults.flows.openai.plus.hostedCheckoutVerificationUrl
|
||||
).trim(),
|
||||
hostedCheckoutPhoneNumber: String(
|
||||
input?.hostedCheckoutPhoneNumber
|
||||
?? nested?.flows?.openai?.plus?.hostedCheckoutPhoneNumber
|
||||
?? defaults.flows.openai.plus.hostedCheckoutPhoneNumber
|
||||
).trim(),
|
||||
plusHostedCheckoutOauthDelaySeconds: (() => {
|
||||
const numeric = Number(
|
||||
input?.plusHostedCheckoutOauthDelaySeconds
|
||||
?? nested?.flows?.openai?.plus?.plusHostedCheckoutOauthDelaySeconds
|
||||
?? defaults.flows.openai.plus.plusHostedCheckoutOauthDelaySeconds
|
||||
);
|
||||
return Math.min(120, Math.max(0, Math.floor(Number.isFinite(numeric) ? numeric : defaults.flows.openai.plus.plusHostedCheckoutOauthDelaySeconds)));
|
||||
})(),
|
||||
},
|
||||
autoRun: {
|
||||
stepExecutionRange: normalizeStepExecutionRangeEntry(
|
||||
stepExecutionRangeByFlow.openai
|
||||
?? nested?.flows?.openai?.autoRun?.stepExecutionRange
|
||||
?? {},
|
||||
defaults.flows.openai.autoRun.stepExecutionRange
|
||||
),
|
||||
},
|
||||
},
|
||||
kiro: {
|
||||
selectedTargetId: kiroSelectedTargetId,
|
||||
targets: {
|
||||
'kiro-rs': {
|
||||
...defaults.flows.kiro.targets['kiro-rs'],
|
||||
...getTargetValue(
|
||||
nested,
|
||||
(state) => state.flows?.kiro?.targets?.['kiro-rs']
|
||||
),
|
||||
baseUrl: String(
|
||||
input?.kiroRsUrl
|
||||
?? input?.kiroRsBaseUrl
|
||||
?? nested?.flows?.kiro?.targets?.['kiro-rs']?.baseUrl
|
||||
?? defaults.flows.kiro.targets['kiro-rs'].baseUrl
|
||||
).trim() || defaults.flows.kiro.targets['kiro-rs'].baseUrl,
|
||||
apiKey: String(
|
||||
input?.kiroRsKey
|
||||
?? input?.kiroRsApiKey
|
||||
?? nested?.flows?.kiro?.targets?.['kiro-rs']?.apiKey
|
||||
?? defaults.flows.kiro.targets['kiro-rs'].apiKey
|
||||
),
|
||||
},
|
||||
},
|
||||
autoRun: {
|
||||
stepExecutionRange: normalizeStepExecutionRangeEntry(
|
||||
stepExecutionRangeByFlow.kiro
|
||||
?? nested?.flows?.kiro?.autoRun?.stepExecutionRange
|
||||
?? {},
|
||||
defaults.flows.kiro.autoRun.stepExecutionRange
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
flows: {},
|
||||
};
|
||||
|
||||
getCanonicalFlowIds().forEach((flowId) => {
|
||||
normalized.flows[flowId] = normalizeFlowSettings(flowId, {
|
||||
...input,
|
||||
activeFlowId,
|
||||
}, nested, defaults);
|
||||
});
|
||||
if (normalized.flows.openai) {
|
||||
normalized.flows.openai = normalizeOpenAiSettings(input, nested, defaults, normalized.flows.openai);
|
||||
}
|
||||
if (normalized.flows.kiro) {
|
||||
normalized.flows.kiro = normalizeKiroSettings(input, defaults, normalized.flows.kiro);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function mergeSettingsState(baseValue = {}, patchValue = {}) {
|
||||
@@ -425,24 +547,8 @@
|
||||
activeFlowId: patchValue?.activeFlowId ?? baseSettingsState.activeFlowId,
|
||||
});
|
||||
|
||||
function mergeRecursive(baseNode, patchNode) {
|
||||
if (Array.isArray(patchNode)) {
|
||||
return patchNode.map((entry) => cloneValue(entry));
|
||||
}
|
||||
if (!isPlainObject(patchNode)) {
|
||||
return patchNode === undefined ? cloneValue(baseNode) : patchNode;
|
||||
}
|
||||
const next = {
|
||||
...cloneValue(isPlainObject(baseNode) ? baseNode : {}),
|
||||
};
|
||||
Object.entries(patchNode).forEach(([key, value]) => {
|
||||
next[key] = mergeRecursive(baseNode?.[key], value);
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
return normalizeSettingsState({
|
||||
settingsState: mergeRecursive(baseSettingsState, patchSettingsState),
|
||||
settingsState: mergePlainObjects(baseSettingsState, patchSettingsState),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -459,7 +565,7 @@
|
||||
return normalizeTargetId(
|
||||
normalizedFlowId,
|
||||
flowSettings?.selectedTargetId,
|
||||
normalizedFlowId === 'kiro' ? defaultKiroTargetId : defaultOpenAiTargetId
|
||||
getDefaultTargetId(normalizedFlowId)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -476,16 +582,16 @@
|
||||
|
||||
function buildStepExecutionRangeByFlow(settingsState = {}) {
|
||||
const normalizedState = normalizeSettingsState(settingsState);
|
||||
return {
|
||||
openai: normalizeStepExecutionRangeEntry(
|
||||
normalizedState?.flows?.openai?.autoRun?.stepExecutionRange,
|
||||
buildDefaultSettingsState().flows.openai.autoRun.stepExecutionRange
|
||||
),
|
||||
kiro: normalizeStepExecutionRangeEntry(
|
||||
normalizedState?.flows?.kiro?.autoRun?.stepExecutionRange,
|
||||
buildDefaultSettingsState().flows.kiro.autoRun.stepExecutionRange
|
||||
),
|
||||
};
|
||||
const defaults = buildDefaultSettingsState();
|
||||
return Object.fromEntries(
|
||||
Object.entries(normalizedState.flows || {}).map(([flowId, flowSettings]) => [
|
||||
flowId,
|
||||
normalizeStepExecutionRangeEntry(
|
||||
flowSettings?.autoRun?.stepExecutionRange,
|
||||
defaults.flows?.[flowId]?.autoRun?.stepExecutionRange || getDefaultStepExecutionRange(flowId)
|
||||
),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
function buildSettingsView(settingsState = {}, baseInput = {}) {
|
||||
@@ -493,38 +599,38 @@
|
||||
const next = {
|
||||
...(isPlainObject(baseInput) ? cloneValue(baseInput) : {}),
|
||||
};
|
||||
const openaiState = normalizedState.flows.openai;
|
||||
const kiroState = normalizedState.flows.kiro;
|
||||
const openaiState = normalizedState.flows.openai || buildDefaultFlowSettings('openai');
|
||||
const kiroState = normalizedState.flows.kiro || buildDefaultFlowSettings('kiro');
|
||||
next.activeFlowId = normalizedState.activeFlowId;
|
||||
next.targetId = getSelectedTargetId(normalizedState, normalizedState.activeFlowId);
|
||||
next.vpsUrl = openaiState.targets.cpa.vpsUrl;
|
||||
next.vpsPassword = openaiState.targets.cpa.vpsPassword;
|
||||
next.localCpaStep9Mode = openaiState.targets.cpa.localCpaStep9Mode;
|
||||
next.sub2apiUrl = openaiState.targets.sub2api.sub2apiUrl;
|
||||
next.sub2apiEmail = openaiState.targets.sub2api.sub2apiEmail;
|
||||
next.sub2apiPassword = openaiState.targets.sub2api.sub2apiPassword;
|
||||
next.sub2apiGroupName = openaiState.targets.sub2api.sub2apiGroupName;
|
||||
next.sub2apiGroupNames = cloneValue(openaiState.targets.sub2api.sub2apiGroupNames);
|
||||
next.sub2apiAccountPriority = openaiState.targets.sub2api.sub2apiAccountPriority;
|
||||
next.sub2apiDefaultProxyName = openaiState.targets.sub2api.sub2apiDefaultProxyName;
|
||||
next.codex2apiUrl = openaiState.targets.codex2api.codex2apiUrl;
|
||||
next.codex2apiAdminKey = openaiState.targets.codex2api.codex2apiAdminKey;
|
||||
next.vpsUrl = openaiState.targets.cpa?.vpsUrl || '';
|
||||
next.vpsPassword = openaiState.targets.cpa?.vpsPassword || '';
|
||||
next.localCpaStep9Mode = openaiState.targets.cpa?.localCpaStep9Mode || 'submit';
|
||||
next.sub2apiUrl = openaiState.targets.sub2api?.sub2apiUrl || '';
|
||||
next.sub2apiEmail = openaiState.targets.sub2api?.sub2apiEmail || '';
|
||||
next.sub2apiPassword = openaiState.targets.sub2api?.sub2apiPassword || '';
|
||||
next.sub2apiGroupName = openaiState.targets.sub2api?.sub2apiGroupName || 'codex';
|
||||
next.sub2apiGroupNames = cloneValue(openaiState.targets.sub2api?.sub2apiGroupNames || ['codex', 'openai-plus']);
|
||||
next.sub2apiAccountPriority = openaiState.targets.sub2api?.sub2apiAccountPriority || 1;
|
||||
next.sub2apiDefaultProxyName = openaiState.targets.sub2api?.sub2apiDefaultProxyName || '';
|
||||
next.codex2apiUrl = openaiState.targets.codex2api?.codex2apiUrl || '';
|
||||
next.codex2apiAdminKey = openaiState.targets.codex2api?.codex2apiAdminKey || '';
|
||||
next.customPassword = normalizedState.services.account.customPassword;
|
||||
next.signupMethod = openaiState.signup.signupMethod;
|
||||
next.phoneVerificationEnabled = openaiState.signup.phoneVerificationEnabled;
|
||||
next.phoneSignupReloginAfterBindEmailEnabled = openaiState.signup.phoneSignupReloginAfterBindEmailEnabled;
|
||||
next.plusModeEnabled = openaiState.plus.plusModeEnabled;
|
||||
next.plusPaymentMethod = openaiState.plus.plusPaymentMethod;
|
||||
next.plusAccountAccessStrategy = openaiState.plus.plusAccountAccessStrategy;
|
||||
next.hostedCheckoutVerificationUrl = openaiState.plus.hostedCheckoutVerificationUrl;
|
||||
next.hostedCheckoutPhoneNumber = openaiState.plus.hostedCheckoutPhoneNumber;
|
||||
next.plusHostedCheckoutOauthDelaySeconds = openaiState.plus.plusHostedCheckoutOauthDelaySeconds;
|
||||
next.signupMethod = openaiState.signup?.signupMethod || 'email';
|
||||
next.phoneVerificationEnabled = Boolean(openaiState.signup?.phoneVerificationEnabled);
|
||||
next.phoneSignupReloginAfterBindEmailEnabled = Boolean(openaiState.signup?.phoneSignupReloginAfterBindEmailEnabled);
|
||||
next.plusModeEnabled = Boolean(openaiState.plus?.plusModeEnabled);
|
||||
next.plusPaymentMethod = openaiState.plus?.plusPaymentMethod || 'paypal-hosted';
|
||||
next.plusAccountAccessStrategy = openaiState.plus?.plusAccountAccessStrategy || 'oauth';
|
||||
next.hostedCheckoutVerificationUrl = openaiState.plus?.hostedCheckoutVerificationUrl || '';
|
||||
next.hostedCheckoutPhoneNumber = openaiState.plus?.hostedCheckoutPhoneNumber || '';
|
||||
next.plusHostedCheckoutOauthDelaySeconds = openaiState.plus?.plusHostedCheckoutOauthDelaySeconds ?? 3;
|
||||
next.mailProvider = normalizedState.services.email.provider;
|
||||
next.ipProxyEnabled = normalizedState.services.proxy.enabled;
|
||||
next.ipProxyService = normalizedState.services.proxy.provider;
|
||||
next.ipProxyMode = normalizedState.services.proxy.mode;
|
||||
next.kiroRsUrl = kiroState.targets['kiro-rs'].baseUrl;
|
||||
next.kiroRsKey = kiroState.targets['kiro-rs'].apiKey;
|
||||
next.kiroRsUrl = kiroState.targets['kiro-rs']?.baseUrl || '';
|
||||
next.kiroRsKey = kiroState.targets['kiro-rs']?.apiKey || '';
|
||||
next.stepExecutionRangeByFlow = buildStepExecutionRangeByFlow(normalizedState);
|
||||
next.settingsSchemaVersion = normalizedState.schemaVersion;
|
||||
next.settingsState = cloneValue(normalizedState);
|
||||
|
||||
Reference in New Issue
Block a user