social components
inlay.at
atproto
components
sdui
1// data/xrpc.ts
2import "server-only";
3import type { ComponentResponse } from "./types";
4import { resolveDidToService } from "./resolve";
5import { MissingError } from "@inlay/render";
6
7/**
8 * Call a component's XRPC procedure endpoint (POST).
9 */
10export async function callComponent(
11 did: string,
12 procedure: string,
13 input: Record<string, unknown>,
14 serviceJwt?: string
15): Promise<ComponentResponse> {
16 let url: string;
17 try {
18 const serviceUrl = await resolveDidToService(did, "#inlay");
19 url = `${serviceUrl}/xrpc/${procedure}`;
20 } catch (e) {
21 throw new Error(
22 `XRPC resolve failed for ${procedure} (did=${did}): ${(e as Error).message}`
23 );
24 }
25
26 const headers: Record<string, string> = {
27 "Content-Type": "application/json",
28 };
29
30 // Pass service JWT for personalized components
31 if (serviceJwt) {
32 headers["Authorization"] = `Bearer ${serviceJwt}`;
33 }
34
35 let res: Response;
36 try {
37 res = await fetch(url, {
38 method: "POST",
39 headers,
40 body: JSON.stringify(input),
41 });
42 } catch (e) {
43 throw new Error(
44 `XRPC fetch failed for ${procedure} (${url}): ${(e as Error).message}`
45 );
46 }
47
48 return handleResponse(res, procedure);
49}
50
51/**
52 * Call an XRPC query endpoint (GET).
53 */
54export async function callQuery(
55 did: string,
56 nsid: string,
57 params?: Record<string, string>
58): Promise<unknown> {
59 const serviceUrl = await resolveDidToService(did, "#inlay");
60 const qs = new URLSearchParams();
61 if (params) {
62 for (const [k, v] of Object.entries(params)) {
63 if (v != null) qs.set(k, v);
64 }
65 }
66 const qsStr = qs.toString();
67 const url = `${serviceUrl}/xrpc/${nsid}${qsStr ? `?${qsStr}` : ""}`;
68 const res = await fetch(url);
69 return handleResponse(res, nsid);
70}
71
72async function handleResponse(res: Response, label: string): Promise<any> {
73 if (!res.ok) {
74 const text = await res.text().catch(() => "");
75 MissingError.rethrowFromResponse(text);
76 let detail = text;
77 try {
78 const json = JSON.parse(text);
79 const err = json.error ?? json;
80 detail = err.message ?? err.name ?? text;
81 } catch {}
82 throw new Error(`XRPC ${label} failed (${res.status}): ${detail}`);
83 }
84 return res.json();
85}