Ctrl K
ComunidadGuías…

electron/included-x.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// 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<void> | 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}`); }
    },
  });
}