this repo has no description
1const API_BASE = '/xrpc'
2export class ApiError extends Error {
3 public did?: string
4 constructor(public status: number, public error: string, message: string, did?: string) {
5 super(message)
6 this.name = 'ApiError'
7 this.did = did
8 }
9}
10async function xrpc<T>(method: string, options?: {
11 method?: 'GET' | 'POST'
12 params?: Record<string, string>
13 body?: unknown
14 token?: string
15}): Promise<T> {
16 const { method: httpMethod = 'GET', params, body, token } = options ?? {}
17 let url = `${API_BASE}/${method}`
18 if (params) {
19 const searchParams = new URLSearchParams(params)
20 url += `?${searchParams}`
21 }
22 const headers: Record<string, string> = {}
23 if (token) {
24 headers['Authorization'] = `Bearer ${token}`
25 }
26 if (body) {
27 headers['Content-Type'] = 'application/json'
28 }
29 const res = await fetch(url, {
30 method: httpMethod,
31 headers,
32 body: body ? JSON.stringify(body) : undefined,
33 })
34 if (!res.ok) {
35 const err = await res.json().catch(() => ({ error: 'Unknown', message: res.statusText }))
36 throw new ApiError(res.status, err.error, err.message, err.did)
37 }
38 return res.json()
39}
40export interface Session {
41 did: string
42 handle: string
43 email?: string
44 emailConfirmed?: boolean
45 preferredChannel?: string
46 preferredChannelVerified?: boolean
47 accessJwt: string
48 refreshJwt: string
49}
50export interface AppPassword {
51 name: string
52 createdAt: string
53}
54export interface InviteCode {
55 code: string
56 available: number
57 disabled: boolean
58 forAccount: string
59 createdBy: string
60 createdAt: string
61 uses: { usedBy: string; usedAt: string }[]
62}
63export type VerificationChannel = 'email' | 'discord' | 'telegram' | 'signal'
64export interface CreateAccountParams {
65 handle: string
66 email: string
67 password: string
68 inviteCode?: string
69 verificationChannel?: VerificationChannel
70 discordId?: string
71 telegramUsername?: string
72 signalNumber?: string
73}
74export interface CreateAccountResult {
75 handle: string
76 did: string
77 verificationRequired: boolean
78 verificationChannel: string
79}
80export interface ConfirmSignupResult {
81 accessJwt: string
82 refreshJwt: string
83 handle: string
84 did: string
85 email?: string
86 emailConfirmed?: boolean
87 preferredChannel?: string
88 preferredChannelVerified?: boolean
89}
90export const api = {
91 async createAccount(params: CreateAccountParams): Promise<CreateAccountResult> {
92 return xrpc('com.atproto.server.createAccount', {
93 method: 'POST',
94 body: {
95 handle: params.handle,
96 email: params.email,
97 password: params.password,
98 inviteCode: params.inviteCode,
99 verificationChannel: params.verificationChannel,
100 discordId: params.discordId,
101 telegramUsername: params.telegramUsername,
102 signalNumber: params.signalNumber,
103 },
104 })
105 },
106 async confirmSignup(did: string, verificationCode: string): Promise<ConfirmSignupResult> {
107 return xrpc('com.atproto.server.confirmSignup', {
108 method: 'POST',
109 body: { did, verificationCode },
110 })
111 },
112 async resendVerification(did: string): Promise<{ success: boolean }> {
113 return xrpc('com.atproto.server.resendVerification', {
114 method: 'POST',
115 body: { did },
116 })
117 },
118 async createSession(identifier: string, password: string): Promise<Session> {
119 return xrpc('com.atproto.server.createSession', {
120 method: 'POST',
121 body: { identifier, password },
122 })
123 },
124 async getSession(token: string): Promise<Session> {
125 return xrpc('com.atproto.server.getSession', { token })
126 },
127 async refreshSession(refreshJwt: string): Promise<Session> {
128 return xrpc('com.atproto.server.refreshSession', {
129 method: 'POST',
130 token: refreshJwt,
131 })
132 },
133 async deleteSession(token: string): Promise<void> {
134 await xrpc('com.atproto.server.deleteSession', {
135 method: 'POST',
136 token,
137 })
138 },
139 async listAppPasswords(token: string): Promise<{ passwords: AppPassword[] }> {
140 return xrpc('com.atproto.server.listAppPasswords', { token })
141 },
142 async createAppPassword(token: string, name: string): Promise<{ name: string; password: string; createdAt: string }> {
143 return xrpc('com.atproto.server.createAppPassword', {
144 method: 'POST',
145 token,
146 body: { name },
147 })
148 },
149 async revokeAppPassword(token: string, name: string): Promise<void> {
150 await xrpc('com.atproto.server.revokeAppPassword', {
151 method: 'POST',
152 token,
153 body: { name },
154 })
155 },
156 async getAccountInviteCodes(token: string): Promise<{ codes: InviteCode[] }> {
157 return xrpc('com.atproto.server.getAccountInviteCodes', { token })
158 },
159 async createInviteCode(token: string, useCount: number = 1): Promise<{ code: string }> {
160 return xrpc('com.atproto.server.createInviteCode', {
161 method: 'POST',
162 token,
163 body: { useCount },
164 })
165 },
166 async requestPasswordReset(email: string): Promise<void> {
167 await xrpc('com.atproto.server.requestPasswordReset', {
168 method: 'POST',
169 body: { email },
170 })
171 },
172 async resetPassword(token: string, password: string): Promise<void> {
173 await xrpc('com.atproto.server.resetPassword', {
174 method: 'POST',
175 body: { token, password },
176 })
177 },
178 async requestEmailUpdate(token: string): Promise<{ tokenRequired: boolean }> {
179 return xrpc('com.atproto.server.requestEmailUpdate', {
180 method: 'POST',
181 token,
182 })
183 },
184 async updateEmail(token: string, email: string, emailToken?: string): Promise<void> {
185 await xrpc('com.atproto.server.updateEmail', {
186 method: 'POST',
187 token,
188 body: { email, token: emailToken },
189 })
190 },
191 async updateHandle(token: string, handle: string): Promise<void> {
192 await xrpc('com.atproto.identity.updateHandle', {
193 method: 'POST',
194 token,
195 body: { handle },
196 })
197 },
198 async requestAccountDelete(token: string): Promise<void> {
199 await xrpc('com.atproto.server.requestAccountDelete', {
200 method: 'POST',
201 token,
202 })
203 },
204 async deleteAccount(did: string, password: string, deleteToken: string): Promise<void> {
205 await xrpc('com.atproto.server.deleteAccount', {
206 method: 'POST',
207 body: { did, password, token: deleteToken },
208 })
209 },
210 async describeServer(): Promise<{
211 availableUserDomains: string[]
212 inviteCodeRequired: boolean
213 links?: { privacyPolicy?: string; termsOfService?: string }
214 }> {
215 return xrpc('com.atproto.server.describeServer')
216 },
217 async getNotificationPrefs(token: string): Promise<{
218 preferredChannel: string
219 email: string
220 discordId: string | null
221 discordVerified: boolean
222 telegramUsername: string | null
223 telegramVerified: boolean
224 signalNumber: string | null
225 signalVerified: boolean
226 }> {
227 return xrpc('com.bspds.account.getNotificationPrefs', { token })
228 },
229 async updateNotificationPrefs(token: string, prefs: {
230 preferredChannel?: string
231 discordId?: string
232 telegramUsername?: string
233 signalNumber?: string
234 }): Promise<{ success: boolean }> {
235 return xrpc('com.bspds.account.updateNotificationPrefs', {
236 method: 'POST',
237 token,
238 body: prefs,
239 })
240 },
241 async describeRepo(token: string, repo: string): Promise<{
242 handle: string
243 did: string
244 didDoc: unknown
245 collections: string[]
246 handleIsCorrect: boolean
247 }> {
248 return xrpc('com.atproto.repo.describeRepo', {
249 token,
250 params: { repo },
251 })
252 },
253 async listRecords(token: string, repo: string, collection: string, options?: {
254 limit?: number
255 cursor?: string
256 reverse?: boolean
257 }): Promise<{
258 records: Array<{ uri: string; cid: string; value: unknown }>
259 cursor?: string
260 }> {
261 const params: Record<string, string> = { repo, collection }
262 if (options?.limit) params.limit = String(options.limit)
263 if (options?.cursor) params.cursor = options.cursor
264 if (options?.reverse) params.reverse = 'true'
265 return xrpc('com.atproto.repo.listRecords', { token, params })
266 },
267 async getRecord(token: string, repo: string, collection: string, rkey: string): Promise<{
268 uri: string
269 cid: string
270 value: unknown
271 }> {
272 return xrpc('com.atproto.repo.getRecord', {
273 token,
274 params: { repo, collection, rkey },
275 })
276 },
277 async createRecord(token: string, repo: string, collection: string, record: unknown, rkey?: string): Promise<{
278 uri: string
279 cid: string
280 }> {
281 return xrpc('com.atproto.repo.createRecord', {
282 method: 'POST',
283 token,
284 body: { repo, collection, record, rkey },
285 })
286 },
287 async putRecord(token: string, repo: string, collection: string, rkey: string, record: unknown): Promise<{
288 uri: string
289 cid: string
290 }> {
291 return xrpc('com.atproto.repo.putRecord', {
292 method: 'POST',
293 token,
294 body: { repo, collection, rkey, record },
295 })
296 },
297 async deleteRecord(token: string, repo: string, collection: string, rkey: string): Promise<void> {
298 await xrpc('com.atproto.repo.deleteRecord', {
299 method: 'POST',
300 token,
301 body: { repo, collection, rkey },
302 })
303 },
304}