Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101import { Client, simpleFetchHandler } from "@atcute/client";import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { knotProcedure } from "#lib/api/cob.ts";import { nsidFromUrl, withServiceAuth } from "#lib/api/client.ts";import { knotCapabilities } from "#lib/api/knot.ts";import { knotFor } from "#lib/api/repo.ts";import { capabilityOf, didOf, nsidOf, type Did, type KnotOrigin, type Nsid} from "#lib/api/syntax.ts";import { serviceDidForHost } from "#lib/auth/agent.ts";import type { Fetch } from "#lib/fetch.ts";
export const REPO_TOKEN_MINT_CAPABILITY = capabilityOf("knot-repo-token-mint");
const MINT_TOKEN_NSID = nsidOf("org.tangled.repo.mintToken");const REPO_TOKEN_LIFETIME_SECS = 55;
export interface SpindleTarget { knot?: KnotOrigin; repoDid: Did;}
export const spindleTargetOf = (repo: { repoDid?: string; knot?: string }): SpindleTarget | null => repo.repoDid ? repo.knot ? { knot: knotFor(repo.knot), repoDid: didOf(repo.repoDid) } : { repoDid: didOf(repo.repoDid) } : null;
const mintRepoToken = async ( agent: OAuthUserAgent, knot: KnotOrigin, repoDid: Did, spindle: URL, lxm: Nsid): Promise<string> => { const { token } = await knotProcedure<{ token: string }>( agent, knot, repoDid, MINT_TOKEN_NSID, { aud: serviceDidForHost(spindle.host), lxm, exp: Math.floor(Date.now() / 1000) + REPO_TOKEN_LIFETIME_SECS }, { signal: AbortSignal.timeout(10_000), invalidate: false } ); return token;};
const withRepoToken = ( base: Fetch, agent: OAuthUserAgent, knot: KnotOrigin, repoDid: Did, spindle: URL, userToken: Fetch): Fetch => { return async (input, init) => { const lxm = nsidFromUrl(input); if (!lxm) return userToken(input, init); try { const token = await mintRepoToken(agent, knot, repoDid, spindle, lxm); const headers = new Headers(init?.headers); headers.set("authorization", `Bearer ${token}`); return base(input, { ...init, headers }); } catch { return userToken(input, init); } };};
export const spindleXrpc = async ( agent: OAuthUserAgent, spindle: URL, target: SpindleTarget): Promise<Client> => { const origin = spindle.toString(); const userToken = withServiceAuth(globalThis.fetch, agent, origin); const authenticated = target.knot && (await knotCapabilities(target.knot))?.includes(REPO_TOKEN_MINT_CAPABILITY) ? withRepoToken( globalThis.fetch, agent, target.knot, target.repoDid, spindle, userToken ) : userToken; return new Client({ handler: simpleFetchHandler({ service: origin, fetch: authenticated as typeof fetch }) });};