Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798import { 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";
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: typeof globalThis.fetch, agent: OAuthUserAgent, knot: KnotOrigin, repoDid: Did, spindle: URL, userToken: typeof globalThis.fetch): typeof globalThis.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 }) });};