Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091import { Client, simpleFetchHandler } from "@atcute/client";import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { knotProcedure } from "$lib/api/cob";import { nsidFromUrl, withServiceAuth } from "$lib/api/client";import { knotCapabilities } from "$lib/api/knot";import { knotFor } from "$lib/api/repo";import { capabilityOf, didOf, nsidOf, type Did, type KnotOrigin, type Nsid } from "$lib/api/syntax";import { serviceDidForHost } from "$lib/auth/agent";
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 }) });};