// X research's relay access on the desktop: while this computer's // MausBot Cloud sign-in is on an active paid plan, fetch that sign-in's // own relay token from the Admin once and hand it to the local server over // the private parent port (server/included-services.ts). Kept in memory only. // // A fetch replaces the sign-in's previous token at the Admin, so it happens // once per sign-in, never on each 15-minute refresh: a new token mid-request // would refuse the one a bot is using. When the Admin says no (the plan is not // active there, or X research is off), that answer stands for the sign-in and // its plan version, and the server is told it is not offered, so the app says // so instead of connecting forever. A server restart gets the held token // again; a plan that stopped, a sign-out or a sign-in to redo clears it. const paidDevice = (state) => state?.status === "connected" && state.entitlement?.plan === "pro" && state.entitlement.status === "active" && typeof state.deviceId === "string" ? state.deviceId : null; /** * @param {{ fetchAccess: () => Promise<{ url: string; token: string } | null>, * send: (access: { url: string; token: string } | null, note?: { offered: false }) => void, * device?: (state: any) => string | null }} options * `fetchAccess` asks the Admin (null: the plan is not active there, or X research is not offered); `send` posts to the server. * `device`: the sign-in that gets access, or null for none (default: one on an active paid plan). */ export function createIncludedXSync({ fetchAccess, send, device = paidDevice }) { /** The sign-in and the plan's version: a changed plan asks again after a no. */ const planKey = (state) => `${device(state)}@${state?.entitlement?.version ?? ""}`; /** @type {{ deviceId: string; access: { url: string; token: string } } | null} */ let held = null; /** The plan key the Admin last said no to. */ let refused = null; /** The newest state, so an answer that arrives after it changed is never sent. */ let latest = null; /** @type {Promise | null} */ let inflight = null; const onState = async (state) => { latest = state; const deviceId = device(state); if (!deviceId) { // Clears a held token, or the server's note that the Admin said no. if (held || refused) { held = null; refused = null; send(null); } return; } if (held?.deviceId === deviceId || refused === planKey(state)) return; if (inflight) return inflight; const key = planKey(state); inflight = (async () => { try { const access = await fetchAccess(); // The sign-in or plan changed while asking: this answer is for a state that is gone. if (planKey(latest) !== key) return; if (access) { held = { deviceId, access }; refused = null; send(access); } else { held = null; refused = key; send(null, { offered: false }); } } catch { // Offline or the Admin is down: the next state change tries again. Another sign-in's token never stays with the server // meanwhile: the account in use just changed, and its bots would run on the one before. if (held && held.deviceId !== deviceId && planKey(latest) === key) { held = null; send(null); } } finally { inflight = null; } })(); await inflight; // A newer paid sign-in arrived while this one was asked about: ask for it now. if (device(latest) && latest !== state && planKey(latest) !== key) await onState(latest); }; return { /** Every Cloud account state the desktop publishes. */ onState, /** The local server (re)started and holds nothing yet. */ serverStarted() { if (held) send(held.access); }, }; } /** * The sync posting this sign-in's access to whichever local server is running, over the private parent port. * @param {{ account: () => { xResearchAccess(): Promise<{ url: string; token: string } | null> } | null, * server: () => { postMessage(message: unknown): void } | null, log: (line: string) => void }} options */ export function createDesktopIncludedX({ account, server, log }) { return createIncludedXSync({ fetchAccess: () => account()?.xResearchAccess() ?? Promise.resolve(null), send: (access, note) => { const proc = server(); if (!proc) return; try { proc.postMessage({ type: "openmausbot:included-x", access, ...(note?.offered === false ? { offered: false } : {}) }); } catch (error) { log(`X research access sync failed: ${error?.message ?? error}`); } }, }); }