This repository has no description
0

Configure Feed

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

wip: web: auth'd bobbin call

Signed-off-by: Seongmin Lee <git@boltless.me>

author
Seongmin Lee
date (Aug 1, 2026, 8:40 PM +0900) commit 868546a7 parent 1ba71392 change-id rzmotsxs
+36 -2
+36 -2
web/src/lib/api/client.ts
··· 1 1 import { Client, simpleFetchHandler } from "@atcute/client"; 2 + import type { OAuthUserAgent } from "@atcute/oauth-browser-client"; 3 + import { mintServiceAuth, serviceDidForHost } from "$lib/auth/agent"; 2 4 3 5 export { ClientResponseError, isXRPCErrorPayload, ok } from "@atcute/client"; 4 6 export type { XRPCErrorPayload } from "@atcute/client"; ··· 14 16 export interface CreateBobbinOptions { 15 17 serviceUrl: string; 16 18 fetch?: typeof globalThis.fetch; 19 + /** when set, every xrpc request carries a freshly minted service-auth jwt */ 20 + agent?: OAuthUserAgent; 17 21 } 18 22 19 - export const createBobbinClient = ({ serviceUrl, fetch }: CreateBobbinOptions): BobbinContext => { 23 + const 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 + 35 + const 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 + 52 + export const createBobbinClient = ({ serviceUrl, fetch, agent }: CreateBobbinOptions): BobbinContext => { 20 53 const origin = serviceUrl.replace(/\/+$/, ""); 21 - const boundFetch = fetch ?? globalThis.fetch; 54 + const baseFetch = fetch ?? globalThis.fetch; 55 + const boundFetch = agent ? withServiceAuth(baseFetch, agent, origin) : baseFetch; 22 56 const xrpc = new Client({ handler: simpleFetchHandler({ service: origin, fetch: boundFetch }) }); 23 57 return { xrpc, serviceUrl: origin, fetch: boundFetch }; 24 58 };