Files
2026-05-29 10:09:26 +08:00

555 lines
18 KiB
JavaScript

(function attachBackgroundRuntimeState(root, factory) {
root.MultiPageBackgroundRuntimeState = factory();
})(typeof self !== 'undefined' ? self : globalThis, function createBackgroundRuntimeStateModule() {
function createRuntimeStateHelpers(deps = {}) {
const {
DEFAULT_ACTIVE_FLOW_ID = 'openai',
defaultNodeStatuses = {},
} = deps;
const RUNTIME_SHARED_FIELDS = Object.freeze([
'automationWindowId',
'tabRegistry',
'sourceLastUrls',
'flowStartTime',
]);
const RUNTIME_PROXY_FIELDS = Object.freeze([
'ipProxyApiPool',
'ipProxyApiCurrentIndex',
'ipProxyApiCurrent',
'ipProxyAccountPool',
'ipProxyAccountCurrentIndex',
'ipProxyAccountCurrent',
'ipProxyPool',
'ipProxyCurrentIndex',
'ipProxyCurrent',
]);
const OPENAI_FLOW_FIELD_GROUPS = Object.freeze({
auth: Object.freeze([
'oauthUrl',
'localhostUrl',
]),
platformBinding: Object.freeze([
'cpaOAuthState',
'cpaManagementOrigin',
'sub2apiSessionId',
'sub2apiOAuthState',
'sub2apiGroupId',
'sub2apiDraftName',
'sub2apiProxyId',
'sub2apiGroupIds',
'codex2apiSessionId',
'codex2apiOAuthState',
]),
plus: Object.freeze([
'plusCheckoutTabId',
'plusCheckoutUrl',
'plusCheckoutCountry',
'plusCheckoutCurrency',
'plusCheckoutSource',
'plusBillingCountryText',
'plusBillingAddress',
'plusPaypalApprovedAt',
'plusGoPayApprovedAt',
'plusReturnUrl',
'plusManualConfirmationPending',
'plusManualConfirmationRequestId',
'plusManualConfirmationStep',
'plusManualConfirmationMethod',
'plusManualConfirmationTitle',
'plusManualConfirmationMessage',
'gpcPageStatus',
'gpcPageStatusText',
]),
phoneVerification: Object.freeze([
'currentPhoneActivation',
'phoneNumber',
'currentPhoneVerificationCode',
'currentPhoneVerificationCountdownEndsAt',
'currentPhoneVerificationCountdownWindowIndex',
'currentPhoneVerificationCountdownWindowTotal',
'reusablePhoneActivation',
'freeReusablePhoneActivation',
'phoneReusableActivationPool',
'signupPhoneNumber',
'signupPhoneActivation',
'signupPhoneCompletedActivation',
'signupPhoneVerificationRequestedAt',
'signupPhoneVerificationPurpose',
]),
luckmail: Object.freeze([
'currentLuckmailPurchase',
'currentLuckmailMailCursor',
'currentYydsMailInbox',
]),
identity: Object.freeze([
'resolvedSignupMethod',
'accountIdentifierType',
'accountIdentifier',
'registrationEmailState',
'email',
'password',
'lastEmailTimestamp',
'lastSignupCode',
'lastLoginCode',
'step8VerificationTargetEmail',
]),
});
const FLOW_FIELD_GROUPS = Object.freeze({
openai: OPENAI_FLOW_FIELD_GROUPS,
});
function isPlainObject(value) {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function cloneValue(value) {
if (Array.isArray(value)) {
return value.map((item) => cloneValue(item));
}
if (isPlainObject(value)) {
return Object.fromEntries(
Object.entries(value).map(([key, entryValue]) => [key, cloneValue(entryValue)])
);
}
return value;
}
function deepMerge(baseValue, patchValue) {
if (Array.isArray(patchValue)) {
return patchValue.map((item) => cloneValue(item));
}
if (!isPlainObject(patchValue)) {
return patchValue === undefined ? cloneValue(baseValue) : patchValue;
}
const baseObject = isPlainObject(baseValue) ? baseValue : {};
const next = {
...cloneValue(baseObject),
};
Object.entries(patchValue).forEach(([key, value]) => {
next[key] = deepMerge(baseObject[key], value);
});
return next;
}
function normalizePlainObject(value) {
return isPlainObject(value) ? value : {};
}
function normalizeFlowId(value = '') {
const normalized = String(value || '').trim().toLowerCase();
return normalized || DEFAULT_ACTIVE_FLOW_ID;
}
function normalizeRunId(value = '') {
return String(value || '').trim();
}
function normalizeNodeStatus(value = '') {
const normalized = String(value || '').trim().toLowerCase();
if (!normalized) {
return 'pending';
}
return normalized;
}
function buildDefaultNodeStatuses() {
return Object.fromEntries(
Object.entries(normalizePlainObject(defaultNodeStatuses)).map(([key, value]) => [
String(key),
normalizeNodeStatus(value),
])
);
}
function normalizeNodeStatuses(value) {
const base = buildDefaultNodeStatuses();
if (!isPlainObject(value)) {
return base;
}
const next = { ...base };
for (const [key, status] of Object.entries(value)) {
const nodeId = String(key || '').trim();
if (!nodeId) continue;
next[nodeId] = normalizeNodeStatus(status);
}
return next;
}
function pickDefinedFields(state = {}, fields = []) {
const next = {};
for (const field of fields) {
if (Object.prototype.hasOwnProperty.call(state, field)) {
next[field] = cloneValue(state[field]);
}
}
return next;
}
function buildSharedState(baseValue = {}, state = {}) {
return {
...cloneValue(normalizePlainObject(baseValue)),
...pickDefinedFields(state, RUNTIME_SHARED_FIELDS),
};
}
function buildServiceState(baseValue = {}, state = {}) {
const base = cloneValue(normalizePlainObject(baseValue));
return {
...base,
proxy: {
...cloneValue(normalizePlainObject(base.proxy)),
...pickDefinedFields(state, RUNTIME_PROXY_FIELDS),
},
};
}
function buildScopedFlowState(baseFlowState = {}, state = {}, flowId = 'openai') {
const fieldGroups = FLOW_FIELD_GROUPS[flowId] || {};
const baseScopedState = cloneValue(normalizePlainObject(baseFlowState[flowId]));
const scopedState = {
...baseScopedState,
};
for (const [groupKey, fields] of Object.entries(fieldGroups)) {
scopedState[groupKey] = {
...cloneValue(normalizePlainObject(baseScopedState[groupKey])),
...pickDefinedFields(state, fields),
};
}
return scopedState;
}
function buildFlowState(baseValue = {}, state = {}) {
const baseFlowState = cloneValue(normalizePlainObject(baseValue));
return {
...baseFlowState,
openai: buildScopedFlowState(baseFlowState, state, 'openai'),
};
}
function listFlowFieldNames() {
const fields = [];
for (const flowGroups of Object.values(FLOW_FIELD_GROUPS)) {
for (const groupFields of Object.values(normalizePlainObject(flowGroups))) {
for (const field of Array.isArray(groupFields) ? groupFields : []) {
const normalizedField = String(field || '').trim();
if (normalizedField) {
fields.push(normalizedField);
}
}
}
}
return Array.from(new Set(fields));
}
const FLOW_RUNTIME_FIELDS = Object.freeze(listFlowFieldNames());
const RUNTIME_TOP_LEVEL_FIELDS = Object.freeze([
...RUNTIME_SHARED_FIELDS,
...RUNTIME_PROXY_FIELDS,
...FLOW_RUNTIME_FIELDS,
]);
const RUNTIME_TOP_LEVEL_FIELD_SET = new Set(RUNTIME_TOP_LEVEL_FIELDS);
const RUNTIME_PATCH_IGNORED_KEYS = new Set([
'runtimeState',
'flowState',
'sharedState',
'serviceState',
'flows',
'shared',
'services',
'currentStep',
'stepStatuses',
'legacyStepCompat',
'flowId',
'runId',
'activeFlowId',
'activeRunId',
'currentNodeId',
'nodeStatuses',
'kiroRuntime',
...RUNTIME_TOP_LEVEL_FIELDS,
]);
function projectScopedFlowFields(flowState = {}) {
const next = {};
for (const [flowId, fieldGroups] of Object.entries(FLOW_FIELD_GROUPS)) {
const scopedState = normalizePlainObject(normalizePlainObject(flowState)[flowId]);
for (const [groupKey, fields] of Object.entries(fieldGroups)) {
const group = normalizePlainObject(scopedState[groupKey]);
Object.assign(next, pickDefinedFields(group, fields));
}
}
return next;
}
function projectRuntimeViewFields(runtimeState = {}) {
const normalizedRuntimeState = normalizePlainObject(runtimeState);
return {
...pickDefinedFields(
normalizePlainObject(normalizedRuntimeState.sharedState),
RUNTIME_SHARED_FIELDS
),
...pickDefinedFields(
normalizePlainObject(normalizePlainObject(normalizedRuntimeState.serviceState).proxy),
RUNTIME_PROXY_FIELDS
),
...projectScopedFlowFields(normalizedRuntimeState.flowState),
};
}
function buildRuntimeInputFromPatch(updates = {}) {
const normalizedUpdates = normalizePlainObject(updates);
const runtimeStatePatch = normalizePlainObject(normalizedUpdates.runtimeState);
const next = {
...pickDefinedFields(normalizedUpdates, [
'flowId',
'runId',
'activeFlowId',
'activeRunId',
'currentNodeId',
'nodeStatuses',
]),
...pickDefinedFields(runtimeStatePatch, [
'flowId',
'runId',
'activeFlowId',
'activeRunId',
'currentNodeId',
'nodeStatuses',
]),
...projectRuntimeViewFields(runtimeStatePatch),
...pickDefinedFields(normalizedUpdates, RUNTIME_TOP_LEVEL_FIELDS),
};
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'sharedState')) {
Object.assign(
next,
pickDefinedFields(normalizePlainObject(normalizedUpdates.sharedState), RUNTIME_SHARED_FIELDS)
);
}
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'serviceState')) {
Object.assign(
next,
pickDefinedFields(
normalizePlainObject(normalizePlainObject(normalizedUpdates.serviceState).proxy),
RUNTIME_PROXY_FIELDS
)
);
}
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'flowState')) {
Object.assign(next, projectScopedFlowFields(normalizedUpdates.flowState));
}
if (!Object.prototype.hasOwnProperty.call(next, 'flowId') && Object.prototype.hasOwnProperty.call(next, 'activeFlowId')) {
next.flowId = next.activeFlowId;
}
if (!Object.prototype.hasOwnProperty.call(next, 'runId') && Object.prototype.hasOwnProperty.call(next, 'activeRunId')) {
next.runId = next.activeRunId;
}
return next;
}
function buildRuntimeStateSeed(currentRuntimeState = {}, updates = {}) {
const normalizedUpdates = normalizePlainObject(updates);
let nextRuntimeState = deepMerge(currentRuntimeState, normalizePlainObject(normalizedUpdates.runtimeState));
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'sharedState')) {
nextRuntimeState = deepMerge(nextRuntimeState, {
sharedState: normalizePlainObject(normalizedUpdates.sharedState),
});
}
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'shared')) {
nextRuntimeState = deepMerge(nextRuntimeState, {
sharedState: normalizePlainObject(normalizedUpdates.shared),
});
}
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'serviceState')) {
nextRuntimeState = deepMerge(nextRuntimeState, {
serviceState: normalizePlainObject(normalizedUpdates.serviceState),
});
}
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'services')) {
nextRuntimeState = deepMerge(nextRuntimeState, {
serviceState: normalizePlainObject(normalizedUpdates.services),
});
}
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'flowState')) {
nextRuntimeState = deepMerge(nextRuntimeState, {
flowState: normalizePlainObject(normalizedUpdates.flowState),
});
}
if (Object.prototype.hasOwnProperty.call(normalizedUpdates, 'flows')) {
nextRuntimeState = deepMerge(nextRuntimeState, {
flowState: normalizePlainObject(normalizedUpdates.flows),
});
}
return nextRuntimeState;
}
function buildRuntimeStateDefault() {
return {
flowId: DEFAULT_ACTIVE_FLOW_ID,
runId: '',
activeFlowId: DEFAULT_ACTIVE_FLOW_ID,
activeRunId: '',
currentNodeId: '',
nodeStatuses: {},
sharedState: {},
serviceState: {
proxy: {},
},
flowState: {
openai: {
auth: {},
platformBinding: {},
plus: {},
phoneVerification: {},
luckmail: {},
identity: {},
},
},
};
}
function ensureRuntimeState(state = {}) {
const baseRuntimeState = {
...buildRuntimeStateDefault(),
...cloneValue(normalizePlainObject(state.runtimeState)),
};
const projectedKiroRuntime = isPlainObject(normalizePlainObject(state.flowState).kiro)
? normalizePlainObject(state.flowState.kiro)
: {};
const canonicalKiroRuntime = deepMerge(
normalizePlainObject(normalizePlainObject(baseRuntimeState.flowState).kiro),
projectedKiroRuntime
);
if (Object.keys(canonicalKiroRuntime).length > 0) {
baseRuntimeState.flowState = {
...cloneValue(normalizePlainObject(baseRuntimeState.flowState)),
kiro: canonicalKiroRuntime,
};
}
const activeFlowId = normalizeFlowId(
Object.prototype.hasOwnProperty.call(state, 'activeFlowId')
? state.activeFlowId
: Object.prototype.hasOwnProperty.call(state, 'flowId')
? state.flowId
: Object.prototype.hasOwnProperty.call(baseRuntimeState, 'activeFlowId')
? baseRuntimeState.activeFlowId
: baseRuntimeState.flowId
);
const currentNodeId = String(
Object.prototype.hasOwnProperty.call(state, 'currentNodeId')
? state.currentNodeId
: baseRuntimeState.currentNodeId
).trim();
const nodeStatuses = normalizeNodeStatuses(
Object.prototype.hasOwnProperty.call(state, 'nodeStatuses')
? state.nodeStatuses
: baseRuntimeState.nodeStatuses
);
return {
...baseRuntimeState,
flowId: activeFlowId,
activeFlowId,
runId: normalizeRunId(
Object.prototype.hasOwnProperty.call(state, 'runId')
? state.runId
: Object.prototype.hasOwnProperty.call(state, 'activeRunId')
? state.activeRunId
: Object.prototype.hasOwnProperty.call(baseRuntimeState, 'runId')
? baseRuntimeState.runId
: baseRuntimeState.activeRunId
),
activeRunId: normalizeRunId(
Object.prototype.hasOwnProperty.call(state, 'runId')
? state.runId
: Object.prototype.hasOwnProperty.call(state, 'activeRunId')
? state.activeRunId
: Object.prototype.hasOwnProperty.call(baseRuntimeState, 'runId')
? baseRuntimeState.runId
: baseRuntimeState.activeRunId
),
currentNodeId,
nodeStatuses,
sharedState: buildSharedState(baseRuntimeState.sharedState, state),
serviceState: buildServiceState(baseRuntimeState.serviceState, state),
flowState: buildFlowState(baseRuntimeState.flowState, state),
};
}
function buildPersistentPatchPayload(updates = {}) {
const next = {};
for (const [key, value] of Object.entries(normalizePlainObject(updates))) {
if (RUNTIME_PATCH_IGNORED_KEYS.has(key)) {
continue;
}
next[key] = cloneValue(value);
}
return next;
}
function buildStateView(state = {}) {
const runtimeState = ensureRuntimeState(state);
return {
...state,
...projectRuntimeViewFields(runtimeState),
flowId: runtimeState.flowId,
runId: runtimeState.runId,
activeFlowId: runtimeState.activeFlowId,
activeRunId: runtimeState.activeRunId,
currentNodeId: runtimeState.currentNodeId,
nodeStatuses: cloneValue(runtimeState.nodeStatuses),
flowState: cloneValue(runtimeState.flowState),
sharedState: cloneValue(runtimeState.sharedState),
serviceState: cloneValue(runtimeState.serviceState),
flows: cloneValue(runtimeState.flowState),
shared: cloneValue(runtimeState.sharedState),
services: cloneValue(runtimeState.serviceState),
runtimeState,
};
}
function buildSessionStatePatch(currentState = {}, updates = {}) {
const currentRuntimeState = ensureRuntimeState(currentState);
const runtimeStateSeed = buildRuntimeStateSeed(currentRuntimeState, updates);
const runtimeState = ensureRuntimeState({
runtimeState: runtimeStateSeed,
...projectRuntimeViewFields(runtimeStateSeed),
...buildRuntimeInputFromPatch(updates),
});
return {
...buildPersistentPatchPayload(updates),
flowId: runtimeState.flowId,
runId: runtimeState.runId,
activeFlowId: runtimeState.activeFlowId,
activeRunId: runtimeState.activeRunId,
currentNodeId: runtimeState.currentNodeId,
nodeStatuses: cloneValue(runtimeState.nodeStatuses),
runtimeState,
};
}
return {
DEFAULT_ACTIVE_FLOW_ID,
FLOW_FIELD_GROUPS,
OPENAI_FLOW_FIELD_GROUPS,
RUNTIME_PROXY_FIELDS,
RUNTIME_SHARED_FIELDS,
buildDefaultRuntimeState: buildRuntimeStateDefault,
buildSessionStatePatch,
buildStateView,
ensureRuntimeState,
};
}
return {
createRuntimeStateHelpers,
};
});