This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / api / client.ts
2.2 kB 65 lines
1import { Client, simpleFetchHandler } from "@atcute/client"; 2import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; 3import { mintServiceAuth, serviceDidForHost } from "$lib/auth/agent"; 4 5export { ClientResponseError, isXRPCErrorPayload, ok } from "@atcute/client"; 6export type { XRPCErrorPayload } from "@atcute/client"; 7 8// generated lexicons register ambient types; don't import the barrel at runtime. 9 10export interface BobbinContext { 11 readonly xrpc: Client; 12 readonly serviceUrl: string; 13 readonly fetch: typeof globalThis.fetch; 14} 15 16export interface CreateBobbinOptions { 17 serviceUrl: string; 18 fetch?: typeof globalThis.fetch; 19 /** when set, every xrpc request carries a freshly minted service-auth jwt */ 20 agent?: OAuthUserAgent; 21} 22 23const nsidOf = (input: RequestInfo | URL): string | null => { 24 const href = input instanceof Request ? input.url : String(input); 25 let pathname: string; 26 try { 27 pathname = new URL(href).pathname; 28 } catch { 29 return null; 30 } 31 const [, prefix, nsid, ...rest] = pathname.split("/"); 32 return prefix === "xrpc" && nsid && rest.length === 0 ? nsid : null; 33}; 34 35const withServiceAuth = ( 36 base: typeof globalThis.fetch, 37 agent: OAuthUserAgent, 38 origin: string 39): typeof globalThis.fetch => { 40 const aud = serviceDidForHost(new URL(origin).host); 41 return async (input, init) => { 42 const lxm = nsidOf(input); 43 if (!lxm) return base(input, init); 44 45 const token = await mintServiceAuth(agent, { aud, lxm }); 46 const headers = new Headers(init?.headers); 47 headers.set("authorization", `Bearer ${token}`); 48 return base(input, { ...init, headers }); 49 }; 50}; 51 52export const createBobbinClient = ({ serviceUrl, fetch, agent }: CreateBobbinOptions): BobbinContext => { 53 const origin = serviceUrl.replace(/\/+$/, ""); 54 const baseFetch = fetch ?? globalThis.fetch; 55 const boundFetch = agent ? withServiceAuth(baseFetch, agent, origin) : baseFetch; 56 const xrpc = new Client({ handler: simpleFetchHandler({ service: origin, fetch: boundFetch }) }); 57 return { xrpc, serviceUrl: origin, fetch: boundFetch }; 58}; 59 60export type QueryValue = string | number | boolean | readonly (string | number)[] | undefined; 61 62export interface XrpcRequestInit { 63 signal?: AbortSignal; 64 headers?: HeadersInit; 65}