'use strict';
/** Read only the socket already initialized in this exact browser realm. */
function readOriginalSocketGeneration() {
try {
const req = globalThis.require;
if (typeof req !== 'function') return null;
const api = req('WAComms');
if (api.isCommsInitialized?.() !== true) return null;
const comms = api.getComms?.();
if (
!comms?.socket ||
typeof comms.socket.sendFrame !== 'function' ||
!Number.isSafeInteger(comms.socketId) ||
comms.socketId <= 0 ||
!Number.isFinite(globalThis.performance?.timeOrigin) ||
globalThis.performance.timeOrigin <= 0
)
return null;
return `${globalThis.performance.timeOrigin}:${comms.socketId}`;
} catch {
return null;
}
}
/**
* Borrow the original page owner first. Only worker-owned transports require
* worker discovery: unrelated media workers may intentionally block their JS
* event loop and cannot be readiness dependencies for a live page.
* Never opens a page, worker, login or socket; close removes observers only.
*/
async function selectOriginalChannelRealm(page, signal, assertOwned) {
const fail = () => new Error('wwebjs_original_realm_unavailable');
if (!(signal instanceof AbortSignal) || typeof assertOwned !== 'function')
throw fail();
const lifetime = new AbortController();
const combined = AbortSignal.any([signal, lifetime.signal]);
let browser, mainFrame, selected;
let closed = false;
const removedWorkers = new Set();
const close = () => {
if (closed) return;
closed = true;
lifetime.abort();
signal.removeEventListener('abort', close);
page.off('close', close);
page.off('error', close);
page.off('framenavigated', onNavigation);
page.off('framedetached', onNavigation);
page.off('workerdestroyed', onWorkerDestroyed);
browser?.off('disconnected', close);
removedWorkers.clear();
};
const onNavigation = (frame) => {
if (frame === mainFrame) close();
};
const onWorkerDestroyed = (worker) => {
if (selected) {
if (worker === selected) close();
return;
}
if (removedWorkers.size >= 64) close();
else removedWorkers.add(worker);
};
const check = () => {
try {
if (combined.aborted || page.isClosed()) throw fail();
const result = assertOwned();
if (result && typeof result.then === 'function') {
void Promise.resolve(result).catch(() => {});
throw fail();
}
const url = new URL(page.url());
if (
url.protocol !== 'https:' ||
url.host !== 'web.whatsapp.com' ||
page.mainFrame() !== mainFrame ||
page.browser() !== browser ||
!browser?.connected ||
(selected &&
selected !== page &&
(removedWorkers.has(selected) ||
!page.workers().includes(selected)))
)
throw fail();
} catch {
close();
throw fail();
}
};
const validGeneration = (value) =>
typeof value === 'string' && /^[0-9.]+:[1-9][0-9]*$/.test(value);
let abort, timer;
try {
browser = page.browser();
mainFrame = page.mainFrame();
page.on('close', close);
page.on('error', close);
page.on('framenavigated', onNavigation);
page.on('framedetached', onNavigation);
page.on('workerdestroyed', onWorkerDestroyed);
browser.on('disconnected', close);
signal.addEventListener('abort', close, { once: true });
check();
const cancelled = new Promise((_, reject) => {
abort = () => reject(fail());
combined.addEventListener('abort', abort, { once: true });
timer = setTimeout(abort, 5000);
timer.unref?.();
});
const pageGeneration = await Promise.race([
page.evaluate(readOriginalSocketGeneration),
cancelled,
]);
check();
let generation;
if (pageGeneration !== null) {
if (!validGeneration(pageGeneration)) throw fail();
selected = page;
generation = pageGeneration;
} else {
const workers = page.workers();
if (
!Array.isArray(workers) ||
workers.length > 64 ||
new Set(workers).size !== workers.length
)
throw fail();
const probes = await Promise.race([
Promise.all(
workers.map(async (realm) => ({
realm,
generation: await realm.evaluate(
readOriginalSocketGeneration,
),
})),
),
cancelled,
]);
check();
const current = page.workers();
if (
current.length !== workers.length ||
workers.some((worker) => !current.includes(worker))
)
throw fail();
const owners = probes.filter((probe) => probe.generation !== null);
if (owners.length !== 1 || !validGeneration(owners[0].generation))
throw fail();
selected = owners[0].realm;
generation = owners[0].generation;
}
check();
return Object.freeze({
realm: selected,
generation,
signal: combined,
check,
close,
});
} catch {
close();
throw fail();
} finally {
clearTimeout(timer);
if (abort) combined.removeEventListener('abort', abort);
}
}
module.exports = { readOriginalSocketGeneration, selectOriginalChannelRealm };