154 lines
4.8 KiB
JavaScript
154 lines
4.8 KiB
JavaScript
(function attachPlusHostedCheckoutSuccess(root, factory) {
|
|
root.MultiPagePlusHostedCheckoutSuccess = factory();
|
|
})(typeof self !== 'undefined' ? self : globalThis, function createPlusHostedCheckoutSuccessModule() {
|
|
const PAYMENT_SUCCESS_URL_PATTERN = /^https:\/\/(?:chatgpt\.com|www\.chatgpt\.com|chat\.openai\.com)\/(?:backend-api\/)?payments\/success(?:[/?#]|$)/i;
|
|
const PLUS_CHECKOUT_NODE_ID = 'plus-checkout-create';
|
|
const PLUS_PAYMENT_METHOD_PAYPAL = 'paypal';
|
|
|
|
function normalizeString(value = '') {
|
|
return String(value || '').trim();
|
|
}
|
|
|
|
function normalizePaymentMethod(value = '') {
|
|
return normalizeString(value).toLowerCase();
|
|
}
|
|
|
|
function isPaymentSuccessUrl(url = '') {
|
|
return PAYMENT_SUCCESS_URL_PATTERN.test(normalizeString(url));
|
|
}
|
|
|
|
function isRunnableNodeStatus(value = '') {
|
|
const normalized = normalizeString(value).toLowerCase();
|
|
return !normalized || normalized === 'pending' || normalized === 'running';
|
|
}
|
|
|
|
function isHostedCheckoutSuccessWaitActive(state = {}, tabId = null) {
|
|
if (!state || typeof state !== 'object') {
|
|
return false;
|
|
}
|
|
if (!state.plusModeEnabled) {
|
|
return false;
|
|
}
|
|
if (normalizePaymentMethod(state.plusPaymentMethod) !== PLUS_PAYMENT_METHOD_PAYPAL) {
|
|
return false;
|
|
}
|
|
if (state.plusHostedCheckoutCompletionPending !== true) {
|
|
return false;
|
|
}
|
|
|
|
const checkoutTabId = Number(state.plusCheckoutTabId);
|
|
if (!Number.isInteger(checkoutTabId) || checkoutTabId <= 0) {
|
|
return false;
|
|
}
|
|
if (tabId !== null && checkoutTabId !== Number(tabId)) {
|
|
return false;
|
|
}
|
|
|
|
return isRunnableNodeStatus(state.nodeStatuses?.[PLUS_CHECKOUT_NODE_ID]);
|
|
}
|
|
|
|
function createPlusHostedCheckoutSuccessManager(deps = {}) {
|
|
const {
|
|
addLog: rawAddLog = async () => {},
|
|
completeNodeFromBackground = null,
|
|
failNodeFromBackground = null,
|
|
getState = async () => ({}),
|
|
setState = async () => {},
|
|
} = deps;
|
|
|
|
const activeTabIds = new Set();
|
|
|
|
function addLog(message, level = 'info', options = {}) {
|
|
return rawAddLog(message, level, {
|
|
stepKey: PLUS_CHECKOUT_NODE_ID,
|
|
nodeId: PLUS_CHECKOUT_NODE_ID,
|
|
...(options && typeof options === 'object' ? options : {}),
|
|
});
|
|
}
|
|
|
|
async function completeFromSuccessTab(tabId, successUrl = '') {
|
|
const numericTabId = Number(tabId);
|
|
if (!Number.isInteger(numericTabId) || numericTabId <= 0) {
|
|
return null;
|
|
}
|
|
if (activeTabIds.has(numericTabId)) {
|
|
return null;
|
|
}
|
|
activeTabIds.add(numericTabId);
|
|
|
|
try {
|
|
const initialState = await getState();
|
|
if (!isHostedCheckoutSuccessWaitActive(initialState, numericTabId)) {
|
|
return null;
|
|
}
|
|
|
|
const latestState = await getState();
|
|
if (!isHostedCheckoutSuccessWaitActive(latestState, numericTabId)) {
|
|
return null;
|
|
}
|
|
|
|
const normalizedSuccessUrl = normalizeString(successUrl);
|
|
await setState({
|
|
plusReturnUrl: normalizedSuccessUrl,
|
|
});
|
|
await addLog('Detected ChatGPT payment success page; continuing Plus session import flow.', 'ok');
|
|
|
|
if (typeof completeNodeFromBackground === 'function') {
|
|
await completeNodeFromBackground(PLUS_CHECKOUT_NODE_ID, {
|
|
plusReturnUrl: normalizedSuccessUrl,
|
|
plusHostedCheckoutCompleted: true,
|
|
});
|
|
}
|
|
|
|
await setState({
|
|
plusHostedCheckoutCompletionPending: false,
|
|
plusHostedCheckoutCompleted: true,
|
|
});
|
|
|
|
return {
|
|
completed: true,
|
|
plusReturnUrl: normalizedSuccessUrl,
|
|
};
|
|
} catch (error) {
|
|
const message = normalizeString(error?.message) || 'unknown error';
|
|
await addLog(`Failed to continue after ChatGPT payment success page: ${message}`, 'error');
|
|
if (typeof failNodeFromBackground === 'function') {
|
|
await failNodeFromBackground(PLUS_CHECKOUT_NODE_ID, message);
|
|
return {
|
|
completed: false,
|
|
failed: true,
|
|
message,
|
|
};
|
|
}
|
|
throw error;
|
|
} finally {
|
|
activeTabIds.delete(numericTabId);
|
|
}
|
|
}
|
|
|
|
async function handleTabUpdated(tabId, changeInfo = {}, tab = {}) {
|
|
if (changeInfo?.status !== 'complete' && tab?.status !== 'complete') {
|
|
return null;
|
|
}
|
|
const nextUrl = normalizeString(changeInfo?.url || tab?.url);
|
|
if (!isPaymentSuccessUrl(nextUrl)) {
|
|
return null;
|
|
}
|
|
return completeFromSuccessTab(tabId, nextUrl);
|
|
}
|
|
|
|
return {
|
|
completeFromSuccessTab,
|
|
handleTabUpdated,
|
|
isHostedCheckoutSuccessWaitActive,
|
|
isPaymentSuccessUrl,
|
|
};
|
|
}
|
|
|
|
return {
|
|
createPlusHostedCheckoutSuccessManager,
|
|
isHostedCheckoutSuccessWaitActive,
|
|
isPaymentSuccessUrl,
|
|
};
|
|
});
|