atprotoSession

tcmts.cli.atproto.atprotoSession · #ilc56jom · function · runs on the server

uses process

A sign-in for scope, as who (a handle or DID) or, without one, the one used last: kept from before (its tokens refreshed if they've expired), or a new one, kept for next time (in tcmSessions): with the app password in TCM_ATPROTO_APP_PASSWORD if it's set (no browser, and never again, as it signs in again by itself), else in the browser, for the scopes the kept one had as well. A kept app password's sign-in covers every scope.

import { Refused, resumeSession, signInLoopback, signInWithAppPassword } from "#codebase/tcmts/atproto";
import type { Session } from "#codebase/tcmts/atproto";
import { APP_PASSWORD_ENV, tcmSessions } from "#codebase/tcmts/cli/atproto";

export async function atprotoSession(o: {
  who?: string;
  scope: string;
  why: string;
  tell?: (line: string) => void;
}): Promise<Session> {
  const store = tcmSessions();
  const kept = store.read();
  const who = o.who?.trim().replace(/^@/, "").toLowerCase();
  const s = who
    ? Object.values(kept.sessions).find((x) => x.did === who || x.handle?.toLowerCase() === who)
    : kept.last
      ? kept.sessions[kept.last]
      : undefined;
  const password = process.env[APP_PASSWORD_ENV]?.trim();
  // (a kept app password's sign-in is used only with that password given, or none; else a new password signs in)
  const usable =
    s && (s.appPassword !== undefined ? !password || s.appPassword === password : !password);
  if (usable) {
    const resumed = await resumeSession(store, { who: s.did, scope: o.scope });
    if (resumed) return resumed;
  }
  const as = who ?? s?.handle ?? s?.did;
  if (!as)
    throw new Refused(`${o.why}: sign in with --as <handle> (once: it's kept for next time)`);
  if (password) return signInWithAppPassword(as, password, { store });
  // (asking for what it had too: else announcing, then signing in to a server, each would sign in again by turns)
  const scope =
    s && !s.appPassword
      ? [...new Set([...s.scope.split(" "), ...o.scope.split(" ")])].join(" ")
      : o.scope;
  return signInLoopback(as, { scope, store, ...(o.tell ? { tell: o.tell } : {}) });
}

uses

used by