Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980import type { OAuthUserAgent } from "@atcute/oauth-browser-client";import { mintServiceAuth, serviceDidForHost } from "$lib/auth/agent";import { buildUrl, toResponseError } from "./_request";import type { QueryValue, XrpcRequestInit } from "./client";
// Authenticated client for deliberi's org.tangled.temp.* xrpc methods.// Calls are authed with an atproto service-auth jwt: the browser mints a// per-call token via the user's pds (getServiceAuth), scoped to the method// (lxm) and deliberi's did:web (aud).export interface DeliberiContext { readonly serviceUrl: string; readonly aud: string; readonly agent: OAuthUserAgent; readonly fetch: typeof globalThis.fetch;}
export interface CreateDeliberiOptions { deliberiUrl: string; agent: OAuthUserAgent; fetch?: typeof globalThis.fetch;}
export const createDeliberiClient = ({ deliberiUrl, agent, fetch}: CreateDeliberiOptions): DeliberiContext => { const serviceUrl = deliberiUrl.replace(/\/+$/, ""); // aud is derived from the url hostname so it can't drift from // deliberi's DELIBERI_HOSTNAME — both must match for service auth. const aud = serviceDidForHost(new URL(serviceUrl).host); return { serviceUrl, aud, agent, fetch: fetch ?? globalThis.fetch };};
const authHeader = async (ctx: DeliberiContext, nsid: string): Promise<string> => { const token = await mintServiceAuth(ctx.agent, { aud: ctx.aud, lxm: nsid }); return `Bearer ${token}`;};
export const authedGet = async <T>( ctx: DeliberiContext, nsid: string, params?: Record<string, QueryValue>, init?: XrpcRequestInit): Promise<T> => { const response = await ctx.fetch(buildUrl(ctx.serviceUrl, nsid, params), { headers: { accept: "application/json", authorization: await authHeader(ctx, nsid), ...init?.headers }, signal: init?.signal }); if (!response.ok) throw await toResponseError(response); return (await response.json()) as T;};
export const authedPost = async <T>( ctx: DeliberiContext, nsid: string, body: unknown, init?: XrpcRequestInit): Promise<T | null> => { const response = await ctx.fetch(buildUrl(ctx.serviceUrl, nsid), { method: "POST", headers: { "content-type": "application/json", accept: "application/json", authorization: await authHeader(ctx, nsid), ...init?.headers }, body: JSON.stringify(body ?? {}), signal: init?.signal }); if (!response.ok) throw await toResponseError(response); // most temp procedures return no body (200 with empty payload) const text = await response.text(); return text ? (JSON.parse(text) as T) : null;};